        TITLE   DOS_RENAME - Internal RENAME call for MS-DOS
        NAME    DOS_RENAME


IF 1
__TONYI__ = 1   ; Space hacks...
__TONYI__1= 1   ; Call SetErrLocDisk
VCB_DATA_OPT = 1        ; Data area optimizations
ENDIF


;
;       Microsoft Confidential
;       Copyright (C) Microsoft Corporation 1991
;       All Rights Reserved.
;
;**     Low level routine for renaming files
;
;       DOS_RENAME
;
;       Modification history:
;
;           Created: ARR 30 March 1983

ifdef   DOSV

;       I50-50AT        91-08-26        A. Togami       J5.00         ;dbcs50at;
;       Adaptation (merged with J4.00 version)                        ;dbcs50at;
;               change DBCS to DBCS_MSKK to maintain renaming rules.  ;dbcs50at;

;       I61-50AT        93-07-28        A. Togami       J6.10         ;dbcs50at;
;       I63-50AT        94-02-02        A. Togami       J6.30         ;dbcs50at;
;       Maintenance (merged with J5.00 version)                       ;dbcs50at;

endif
        .xlist
        .xcref
        include version.inc
        include dosseg.inc
        INCLUDE DOSSYM.INC
        INCLUDE DEVSYM.INC
        include sf.inc
        include find.inc
        include filemode.inc
        include mult.inc
        .cref
        .list

Installed = TRUE

        i_need  RENAMEDMA,BYTE
        i_need  AUXSTACK,BYTE
        i_need  DESTSTART,WORD
        i_need  DIRSTART,WORD
        i_need  CURBUF,DWORD
        I_need  NAME1,BYTE
        i_need  NAME2,BYTE
        i_need  WFP_START,WORD
        i_need  REN_WFP,WORD
        i_need  CURR_DIR_END,WORD
        i_need  DMAADD,DWORD
        i_need  THISCDS,DWORD
        i_need  THISDPB,DWORD
        i_need  THISSFT,DWORD
        i_need  CREATING,BYTE
        i_need  THISDRV,BYTE
        i_need  ATTRIB,BYTE
        i_need  FOUND_DEV,BYTE
        i_need  FAILERR,BYTE
        i_need  EXTERR_LOCUS,BYTE
        i_need  SAVE_BX,WORD

IFNDEF VCB_DATA_OPT
; Move AuxSft to unused FAKE_COUNT area
DOSDATA SEGMENT
        PUBLIC AuxSft
        AuxSft        db    SIZE sf_entry  DUP (0)      ; D1153

DOSDATA ENDS
ENDIF
        i_need  AUXSFT,BYTE


DOSCODE SEGMENT
        ASSUME  SS:DOSDATA,CS:DOSCODE
;----------------------------------------------------------------------------
;
; Procedure Name : DOS_RENAME
;
; Inputs:
;       [WFP_START] Points to SOURCE WFP string ("d:/" must be first 3
;               chars, NUL terminated)
;       [CURR_DIR_END] Points to end of Current dir part of string [SOURCE]
;               ( = -1 if current dir not involved, else
;                Points to first char after last "/" of current dir part)
;       [REN_WFP] Points to DEST WFP string ("d:/" must be first 3
;               chars, NUL terminated)
;       [THISCDS] Points to CDS being used
;               (Low word = -1 if NUL CDS (Net direct request))
;       [SATTRIB] Is attribute of search, determines what files can be found
; Function:
;       Rename the specified file(s)
;       NOTE: This routine uses most of AUXSTACK as a temp buffer.
; Outputs:
;       CARRY CLEAR
;           OK
;       CARRY SET
;           AX is error code
;               error_file_not_found
;                       No match for source, or dest path invalid
;               error_not_same_device
;                       Source and dest are on different devices
;               error_access_denied
;                       Directory specified (not simple rename),
;                       Device name given, Destination exists.
;                       NOTE: In third case some renames may have
;                        been done if metas.
;               error_path_not_found
;                       Bad path (not in curr dir part if present)
;                       SOURCE ONLY
;               error_bad_curr_dir
;                       Bad path in current directory part of path
;                       SOURCE ONLY
;               error_sharing_violation
;                       Deny both access required, generates an INT 24.
; DS preserved, others destroyed
;
;----------------------------------------------------------------------------

        procedure   DOS_RENAME,NEAR

;hkn; DOS_RENAME is called from file.asm and fcbio.asm. DS has been set up
;hkn; at this point to DOSDATA.

        DOSAssume   <DS>,"DOS_Rename"
        ASSUME  ES:NOTHING

        Invoke  TestNet
        JNC     LOCAL_RENAME

IF NOT Installed
        transfer NET_RENAME
ELSE
        MOV     AX,(multNET SHL 8) OR 17
        INT     2FH
        return
ENDIF

LOCAL_RENAME:
IFDEF __TONYI__1
;-------------------------------------------------
; Save 3 bytes......
;-------------------------------------------------
        invoke  SetErrLocDisk
ELSE
        MOV     [EXTERR_LOCUS],errLOC_Disk
ENDIF
        MOV     SI,[WFP_START]
        MOV     DI,[REN_WFP]
        MOV     AL,BYTE PTR [SI]
        MOV     AH,BYTE PTR [DI]
        OR      AX,2020H                ; Lower case
        CMP     AL,AH
        JZ      SAMEDRV
        MOV     AX,error_not_same_device
        STC
        return

SAMEDRV:
        PUSH    WORD PTR [DMAADD+2]
        PUSH    WORD PTR [DMAADD]
        MOV     WORD PTR [DMAADD+2],DS

;hkn; RENAMEDMA is in DOSDATA
        MOV     WORD PTR [DMAADD],OFFSET DOSDATA:RENAMEDMA
        MOV     [Found_dev],0           ; Rename fails on DEVS, assume not a dev
        EnterCrit   critDisk
        invoke  DOS_SEARCH_FIRST        ; Sets [NoSetDir] to 1, [CURBUF+2]:BX
                                        ;    points to entry
        JNC     Check_Dev
        CMP     AX,error_no_more_files
        JNZ     GOTERR
        MOV     AX,error_file_not_found
GOTERR:
        STC
RENAME_POP:
        POP     WORD PTR [DMAADD]
        POP     WORD PTR [DMAADD+2]
        LeaveCrit   critDisk
        return

Check_dev:
        MOV     AX,error_access_denied  ; Assume error

        PUSH    DS                            ;PTM.                             ;AN000;
        LDS     SI,[DMAADD]                   ;PTM.  chek if source a dir       ;AN000;
        ADD     SI,find_buf_attr              ;PTM.                             ;AN000;
        TEST    [SI.dir_attr],attr_directory  ;PTM.                             ;AN000;
        JZ      notdir                        ;PTM.                             ;AN000;
        MOV     SI,[REN_WFP]                  ;PTM.  if yes, make sure path     ;AN000;
        invoke  Check_Pathlen2                ;PTM.   length < 67               ;AN000;
notdir:
        POP     DS                            ;PTM.                             ;AN000;
        JA      GOTERR                        ;PTM.                             ;AN000;

        CMP     [Found_dev],0
        JNZ     GOTERR
; At this point a source has been found.  There is search continuation info (a
; la DOS_SEARCH_NEXT) for the source at RENAMEDMA, together with the first
; directory entry found.
; [THISCDS], [THISDPB], and [THISDRV] are set and will remain correct
; throughout the RENAME since it is known at this point that the source and
; destination are both on the same device.
; [SATTRIB] is also set.
        MOV     SI,BX
        ADD     SI,dir_first
        invoke  REN_DEL_Check
        JNC     REN_OK1
        MOV     AX,error_sharing_violation
IFDEF __TONYI__
;--------------------------------------------------
; A short label to allow tightening up some JMP's
;--------------------------------------------------
ShortToRENAME_POP1:
ENDIF
        JMP     SHORT RENAME_POP

;------------------------------------------------------------------------------
; Check if the source is a file or directory.  If file, delete the entry
; from the Fastopen cache. If directory, rename it later
;------------------------------------------------------------------------------
REN_OK1:                                ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        PUSH    SI
        LDS     SI,[DMAADD]                   ;BN00X; PTM. chek if source a dir       ;AN000;
        ADD     SI,find_buf_attr              ;;BN00XPTM.P5520                             ;AN000;
        TEST    [SI.dir_attr],attr_directory  ;;BN00XPTM.                             ;AN000;
        JZ      Not_dir1                      ;;BN00XPTM.                             ;AN000;
        POP     SI                            ;BN00X
        JMP     SHORT  SWAP_SOURCE            ;BN00X

NOT_DIR1:                               ;;BN00X it is a file, delete the entry
        POP     SI
        invoke  FastOpen_Delete         ; delete dir info in fastopen DOS 3.3

SWAP_SOURCE:
        MOV     AX,[WFP_START]          ; Swap source and destination
        MOV     SI,[REN_WFP]            ; Swap source and destination
        MOV     [WFP_START],SI          ; WFP_START = Destination path
        MOV     [REN_WFP],AX            ; REN_WFP   = Source path
        MOV     [CURR_DIR_END],-1       ; No current dir on dest
        MOV     WORD PTR [CREATING],DIRFREE*256+0ffh  ; Creating, not DEL *.*
                                        ; A rename is like a CREATE_NEW as far
                                        ; as the destination is concerned.
        invoke  GetPathNoSet
;   If this Getpath fails due to file not found, we know all renames will work
;   since no files match the destination name.  If it fails for any other
;   reason, the rename fails on a path not found, or whatever (also fails if
;   we find a device or directory).  If the Getpath succeeds, we aren't sure
;   if the rename should fail because we haven't built an explicit name by
;   substituting for the meta chars in it.  In this case the destination file
;   spec with metas is in [NAME1] and the explicit source name is at RENAMEDMA
;   in the directory entry part.
        JC      NODEST
        OR      AH,AH                   ; Device?
        JNS     SAVEDEST                ; No, continue
BAD_ACC:
        MOV     AX,error_access_denied
        STC
RENAME_CLEAN:
        PUSHF                           ; Save carry state
        PUSH    AX                      ; and error code (if carry set)
        MOV     AL,[THISDRV]
        invoke  FLUSHBUF
        POP     AX
        CMP     [FAILERR],0
        JNZ     BAD_ERR                 ; User FAILed to I 24
        POPF
IFDEF __TONYI__
;----------------------------------
; Save a byte...
;----------------------------------
        jmp     short ShortToRENAME_POP1
ELSE
        JMP     RENAME_POP
ENDIF

BAD_ERR:
        POP     AX                      ; Saved flags
        MOV     AX,error_path_not_found
        JMP     GOTERR

NODEST:
        JNZ     BAD_PATH
        CMP     [FAILERR],0
        JNZ     BAD_PATH        ; Search for dest failed because user FAILed on
                                ;       I 24
        OR      CL,CL
        JNZ     SAVEDEST
BAD_PATH:
        MOV     AX,error_path_not_found
        STC
IFDEF __TONYI__
;----------------------------------
; Save a byte...
;----------------------------------
        jmp     short ShortToRENAME_POP1
ELSE
        JMP     RENAME_POP
ENDIF

SAVEDEST:
        Context ES

;hkn; NAME1 & NAME2 is in DOSDATA
        MOV     DI,OFFSET DOSDATA:NAME2
        MOV     SI,OFFSET DOSDATA:NAME1

        MOV     CX,11
        REP     MOVSB                   ; Save dest with metas at NAME2
        MOV     AX,[DIRSTART]
        MOV     [DESTSTART],AX
BUILDDEST:
        Context ES                      ; needed due to JMP BUILDDEST below

;hkn; RENAMEDMA, NAME1, NAME2 in DOSDATA
        MOV     BX,OFFSET DOSDATA:RENAMEDMA + 21   ; Source of replace chars
        MOV     DI,OFFSET DOSDATA:NAME1    ; Real dest name goes here
        MOV     SI,OFFSET DOSDATA:NAME2    ; Raw dest

;               change DBCS to DBCS_MSKK to maintain renaming rules.  ;dbcs50at;
ifdef DBCS_MSKK                                                       ;dbcs50at;
        mov     cx,8
        call    new_rename
        mov     cx,3
        call    new_rename
else
        MOV     CX,11
        CALL    NEW_RENAME                  ;IFS. replace ? chars               ;AN000;
endif

        MOV     [ATTRIB],attr_all       ; Stop duplicates with any attributes
        MOV     [CREATING],0FFH
        invoke  DEVNAME                 ; Check if we built a device name
        ASSUME  ES:NOTHING
        JNC     BAD_ACC
        MOV     BX,[DESTSTART]
        LES     BP,[THISDPB]
        invoke  SetDirSrch              ; Reset search to start of dir
        JC      BAD_ACC                 ; Screw up
        invoke  FINDENTRY               ; See if new name already exists
        JNC     BAD_ACC                 ; Error if found
        CMP     [FAILERR],0
        JNZ     BAD_ACCJ                ; Find failed because user FAILed to I 24
        MOV     AX,[DESTSTART]          ; DIRSTART of dest
        CMP     AX,WORD PTR [RENAMEDMA + 15]    ; DIRSTART of source
        JZ      SIMPLE_RENAME           ; If =, just give new name

        MOV     AL,[RENAMEDMA + 21 + dir_attr]
        TEST    AL,attr_directory
        JNZ     BAD_ACCJ                ; Can only do a simple rename on dirs,
                                        ; otherwise the .  and ..  entries get
                                        ; wiped.
        MOV     [ATTRIB],AL
        MOV     WORD PTR [THISSFT+2],DS

;hkn; AUXSTACK is in DOSDATA
;;        MOV     SI,OFFSET DOSDATA:AUXSTACK                     ;;D1153
        MOV     SI,OFFSET DOSDATA:AuxSft                         ;;D1153
        MOV     WORD PTR [THISSFT],SI
        MOV     [SI].sf_mode,sharing_compat+open_for_both
        XOR     CX,CX                   ; Set "device ID" for call into makenode
        invoke  RENAME_MAKE             ; This is in mknode
        JNC     GOT_DEST
PUBLIC BAD_ACCJ
BAD_ACCJ:
        JMP     BAD_ACC

GOT_DEST:
        SAVE    <BX>
        LES     DI,ThisSFT              ; Rename_make entered this into sharing
        Invoke  ShareEnd                ; we need to remove it.
        RESTORE <BX>
; A zero length entry with the correct new name has now been made at
;   [CURBUF+2]:BX.
        LES     DI,[CURBUF]
        Assert  ISBUF,<ES,DI>,"Got_Dest"

        TEST    ES:[DI.buf_flags],buf_dirty  ;LB. if already dirty              ;AN000;
        JNZ     yesdirty                  ;LB.    don't increment dirty count   ;AN000;
        invoke  INC_DIRTY_COUNT           ;LB.                                  ;AN000;
        OR      ES:[DI.buf_flags],buf_dirty
yesdirty:
        MOV     DI,BX
        ADD     DI,dir_attr             ; Skip name

;hkn; RENAMEDMA is in DOSDATA
        MOV     SI,OFFSET DOSDATA:RENAMEDMA + 21 + dir_attr
        MOV     CX,(SIZE dir_entry) - dir_attr
        REP     MOVSB
        CALL    GET_SOURCE
        DLJC    RENAME_OVER
        MOV     DI,BX
        MOV     ES,WORD PTR [CURBUF+2]
        MOV     AL,DIRFREE
        STOSB                           ; "free" the source
        JMP     SHORT DIRTY_IT

SIMPLE_RENAME:
        CALL    GET_SOURCE              ; Get the source back
        JC      RENAME_OVER
        MOV     DI,BX
        MOV     ES,WORD PTR [CURBUF+2]

;hkn; NAME1 is in DOSDATA
        MOV     SI,OFFSET DOSDATA:NAME1    ; New Name
        MOV     CX,11
        REP     MOVSB
DIRTY_IT:
        MOV     DI,WORD PTR [CURBUF]

        TEST    ES:[DI.buf_flags],buf_dirty  ;LB. if already dirty              ;AN000;
        JNZ     yesdirty2                 ;LB.    don't increment dirty count   ;AN000;
        invoke  INC_DIRTY_COUNT           ;LB.                                  ;AN000;
        OR      ES:[DI.buf_flags],buf_dirty

;------------------------------------------------------------------------------
; Check if the source is a directory of file.  If directory rename it to the
; the new name in the Fastopen cache buffer.   If file name it has been
; previously deleted.
;------------------------------------------------------------------------------
Yesdirty2:
        PUSH    SI
        LDS     SI,[DMAADD]                   ;;BN00XPTM. chek if source a dir       ;AN000;
        ADD     SI,find_buf_attr              ;;BN00XPTM.P5520                             ;AN000;
        TEST    [SI.dir_attr],attr_directory  ;;BN00XPTM.                             ;AN000;
        JZ      Not_dir2                      ;;BN00XPTM.                             ;AN000;
        INVOKE  FASTOPEN_RENAME               ;;BN00X rename dir entry in fastopen
        POP     SI
        JMP     SHORT NOT_DIRTY1

NOT_DIR2:                                     ;;BN00X it is a file, delete the entry
        POP     SI

NOT_DIRTY1:                                   ;;BN00X

        Assert  ISBUF,<ES,DI>,"Dirty_it"
NEXT_SOURCE:

;hkn; RENAMEDMA is in DOSDATA
        MOV     SI,OFFSET DOSDATA:RENAMEDMA + 1    ;Name
;
; WARNING!  Rename_Next leaves the disk critical section *ALWAYS*.  We need
; to enter it before going to RENAME_Next.
;
        EnterCrit   critDisk
        MOV     [CREATING],0    ; Correct setting for search (we changed it
                                ;   to FF when we made the prev new file).
        invoke  RENAME_NEXT
;
; Note, now, that we have exited the previous ENTER and so are back to where
; we were before.
;
        JC      RENAME_OVER
        LEA     SI,[BX].dir_First
        invoke  REN_DEL_Check
        JNC     REN_OK2
        MOV     AX,error_sharing_violation
IFDEF __TONYI__
;--------------------------------------------
; Allows for smaller JMP below...
;--------------------------------------------
ShortToRENAME_CLEAN:
ENDIF
        JMP     RENAME_CLEAN

;------------------------------------------------------------------------------
; Check if file or directory. If file, delete file from the Fastopen cache,
; if directory, rename directory name in the Fastopen cache.
;-----------------------------------------------------------------------------
REN_OK2:
        MOV     AL,[RENAMEDMA + 21 + dir_attr]     ; PTR P5622
        TEST    AL,attr_directory       ;;BN00X directory
        JZ      Ren_Directory           ;;BN00X no - file, delete it
        INVOKE  FASTOPEN_DELETE         ;;BN00X delete dir info in fastopen DOS 3.3
IFDEF __TONYI__
;--------------------------------------------
; Allows for smaller JMP below...
;--------------------------------------------
ShortToBUILDDEST:
ENDIF
        JMP     BUILDDEST               ;;BN00X

Ren_Directory:
        INVOKE  FASTOPEN_RENAME         ;;BN00X delete dir info in fastopen DOS 3.3
IFDEF __TONYI__
;-------------------------------
; Save a byte...
;-------------------------------
        jmp     short ShortToBUILDDEST
ELSE
        JMP     BUILDDEST
ENDIF

RENAME_OVER:
        CLC
IFDEF __TONYI__
;----------------------
; Save a byte......
;----------------------
        jmp     short ShortToRENAME_CLEAN
ELSE
        JMP     RENAME_CLEAN
ENDIF
;----------------------------------------------------------------------------
;
; Procedure: GET_SOURCE
;
; Inputs:
;       RENAMEDMA has source info
; Function:
;       Re-find the source
; Output:
;       [CURBUF] set
;       [CURBUF+2]:BX points to entry
;       Carry set if error (currently user FAILed to I 24)
; DS preserved, others destroyed
;----------------------------------------------------------------------------

GET_SOURCE:
        DOSAssume   <DS>,"Get_Source"
        ASSUME  ES:NOTHING

        MOV     BX,WORD PTR [RENAMEDMA + 15]    ; DirStart
        LES     BP,ThisDPB
        invoke  SetDirSrch
        JC      ret_label                       ; retc
        invoke  StartSrch
        MOV     AX,WORD PTR [RENAMEDMA + 13]    ; Lastent
        invoke  GetEnt

ret_label:
        return

EndProc DOS_RENAME

;----------------------------------------------------------------------------
;
;Procedure: NEW_RENAME
;
;Input: DS:SI -> raw string with ?
;       ES:DI -> destination string
;       DS:BX -> source string
;Function: replace ? chars of raw string with chars in source string and
;          put in destination string
;Output: ES:DI-> new string
;---------------------------------------------------------------------------

        ASSUME  ES:NOTHING
procedure   NEW_RENAME,NEAR
        DOSAssume   <DS>,"NEW_Rename"

;               change DBCS to DBCS_MSKK to maintain renaming rules.  ;dbcs50at;
ifdef DBCS_MSKK                         ; ### if DBCS ###             ;dbcs50at;

        mov     ah,0                    ; reset DBCS flag
        mov     dl,cl                   ; reset counter
        mov     dh,cl                   ; save length to do
newren_loop:
        cmp     ah,1                    ; if it was lead byte
        jz      newren_dbcs
        mov     ah,0                    ; reset if it was single or tail byte
        mov     al,[bx]                 ; get source char
        invoke  testkanj
        jz      newren_load             ; if not lead byte
newren_dbcs:
        inc     ah                      ; set dbcs flag
newren_load:
        lodsb                           ; get raw char
        cmp     al,'?'
        jnz     newren_store            ; if not '?'
        cmp     ah,0
        jz      newren_conv             ; if source is single
        cmp     ah,1
        jnz     newren_pass             ; if source is not lead
        cmp     cl,dh
        jnz     newren_lead             ; if this is not 1st char
        cmp     byte ptr [si],' '
        jz      newren_double           ; if this is the end
newren_lead:
        cmp     byte ptr [si],'?'
        jnz     newren_pass             ; if no '?' for tail byte
        cmp     cx,1
        jbe     newren_pass             ; if no room for tail byte
newren_double:
        mov     al,[bx]
        stosb
        dec     dl
        inc     bx
        inc     si
        dec     cx
newren_conv:
        mov     al,[bx]
newren_store:
        stosb                           ; store in destination
        dec     dl                      ; decrese counter
newren_pass:
        inc     bx
        loop    newren_loop
        mov     cl,dl                   ; get stored length
        xor     ch,ch
        jcxz    newren_ret              ; if all done
        mov     al,' '
        rep     stosb                   ; put sapce
newren_ret:
        return

else                                    ; ### if Not DBCS ###

NEWNAM:
        LODSB
        CMP     AL,"?"
        JNZ     NOCHG
        MOV     AL,[BX]                 ; Get replace char
NOCHG:
        STOSB
        INC     BX                      ; Next replace char
        LOOP    NEWNAM
        return
endif                                   ; ### end if Not DBCS ###

EndProc NEW_RENAME


DOSCODE ENDS
    END
