        TITLE   DOS_CLOSE/COMMIT - Internal SFT close and commit call for MSDOS
        NAME    DOS_CLOSE


IF 1
__TONYI__ = 1	; Space hacks....
__TONYI__1= 1	; Space/speed hacks.... 10/28/92
ENDIF


;
;       IBM Corporation
;       Copyright (C) IBM Corporation 1993
;       All Rights Reserved.
;
;**     Internal Close and Commit calls to close a local or NET SFT.
;
;       DOS_CLOSE
;       DOS_COMMIT
;       FREE_SFT
;       SetSFTTimes
;
;       Revision history:
;
;          AN000  version 4.00  Jan. 1988
;          A005   PTM 3718 --- lost clusters when fastopen installed
;          A011   PTM 4766 --- C2 fastopen problem

        .xlist
        .xcref
        include version.inc
        include dosseg.inc
        INCLUDE DOSSYM.INC
        INCLUDE DEVSYM.INC
        include sf.inc
        include mult.inc
        include bugtyp.inc
        .cref
        .list

Installed = TRUE

        I_need  Attrib,BYTE
        i_need  THISSFT,DWORD
        i_need  CURBUF,DWORD
        i_need  THISDRV,BYTE
        i_need  ALLOWED,BYTE
        i_need  EXTERR_LOCUS,BYTE
        I_need  FailErr,BYTE
        I_Need  PROC_ID,WORD
        I_Need  USER_ID,WORD
        i_need  JShare,DWORD
        i_need  HIGH_SECTOR,WORD         ;F.C. >32mb
        i_need  OLD_FIRSTCLUS,WORD        ;F.O. >32mb

DOSCODE SEGMENT
        ASSUME  SS:DOSDATA,CS:DOSCODE


Break <DOS_CLOSE -- CLOSE FILE from SFT>
;---------------------------------------------------------------------------
;
; Procedure Name : DOS_CLOSE
;
; Inputs:
;       [THISSFT] set to the SFT for the file being used
; Function:
;       Close the indicated file via the SFT
; Returns:
;       sf_ref_count decremented otherwise
;       ES:DI point to SFT
;       Carry set if error
;           AX has error code
; DS preserved, others destroyed
;---------------------------------------------------------------------------

;hkn; DOS_CLOSE called from fcbio.asm and handle.asm. DS alreday set up.

procedure   DOS_CLOSE,NEAR
        DOSAssume   <DS>,"DOS_Close"

        LES     DI,[THISSFT]
        Assert  ISSFT,<ES,DI>,<"DOS_CLOSE">
        fmt     TypAccess,LevBUSY,<"$p: CLOSE SFT: $x:$x\n">,<ES,DI>
        MOV     BX,ES:[DI.sf_flags]

;       Network closes are handled entirely by the net code.

        TEST    BX,sf_isnet
        JZ      LocalClose
        CallInstall Net_Close,multnet,6
        return

;
; All closes release the sharing information.
; No commit releases sharing information
;
; All closes decrement the ref count.
; No commit decrements the ref count.
;
LocalClose:
        EnterCrit   critDisk
        CALL    SetSFTTimes
        CALL    Free_SFT                ; dec ref count or mark as busy

;hkn; SS is DOSDATA
        Context DS

        SAVE    <AX,BX>
        invoke  ShareEnd
        RESTORE <BX,AX>
;
; Commit enters here.  AX from commit MUST be <> 1, BX is flags word
;
CloseEntry:
        PUSH    AX
;
; File clean or device does not get stamped nor disk looked at.
;
        TEST    BX,devid_file_clean + devid_device
        JZ      rdir
        JMP     Free_SFT_OK             ; either clean or device
;
; Retrieve the directory entry for the file
;
rdir:
        CALL    DirFromSFT
ASSUME  DS:NOTHING
        MOV     AL,error_access_denied
        JNC     clook
IFDEF __TONYI__
;-------------------------------------------
; Save a byte...
;-------------------------------------------
	jmp	short ShortToCloseFinish
ELSE
        JMP     CloseFinish             ; pretend the close worked.
ENDIF
clook:
;
; ES:DI points to entry
; DS:SI points to SFT
; ES:BX points to buffer header
;
        SAVE    <DI,SI>
        LEA     SI,[SI].sf_name
;
; ES:DI point to directory entry
; DS:SI point to unpacked name
;
        invoke  XCHGP
;
; ES:DI point to unpacked name
; DS:SI point to directory entry
;
        invoke  MetaCompare
        invoke  XCHGP
        RESTORE <SI,DI>
        JZ      CLOSE_GO                ; Name OK
Bye:    MOV     DI,SI
        PUSH    DS
        POP     ES                      ; ES:DI points to SFT
        PUSH    SS
        POP     DS
        STC
        MOV     AL,error_file_not_found
IFDEF __TONYI__
;-------------------------------------------------------
; Label to allow tightening up JMP to CloseFinish above.
;-------------------------------------------------------
ShortToCloseFinish:
ENDIF
        JMP     CloseFinish

CLOSE_GO:
        TEST    [SI].sf_mode,sf_isfcb   ; FCB ?
        JZ      nofcb                   ; no, set dir attr, sf_attr
        MOV     CH,ES:[DI].dir_attr
        MOV     AL,[SI].sf_attr

;hkn; SS override
        MOV     Attrib,AL
        JMP     SHORT setattr           ;FT.
nofcb:
        MOV     AL,[SI].sf_attr         ;FT.                                    ;AN000;
        MOV     ES:[DI].dir_attr,AL     ;FT.                                    ;AN000;
setattr:
        OR      BYTE PTR ES:[DI.dir_attr],attr_archive  ;Set archive
        MOV     AX,ES:[DI.dir_first]    ;AN011;F.O. save old first clusetr

;hkn; SS override
        MOV     [OLD_FIRSTCLUS],AX      ;AN011;F.O. save old first clusetr

        MOV     AX,[SI.sf_firclus]
        MOV     ES:[DI.dir_first],AX    ;Set firclus pointer
IFDEF __TONYI__1
;---------------------------------------------------------
; Save 4 bytes...
;---------------------------------------------------------
	push	ds
        lds	AX,DWORD PTR [SI.sf_size]
        MOV     ES:[DI.dir_size_l],AX   ;Set size
        MOV     ES:[DI.dir_size_h],ds
	pop	ds
	push	ds
        lds	AX, dword ptr [SI.sf_time]
	.errnz	(sf_date - sf_time - 2)
        MOV     ES:[DI.dir_time],AX     ;Set time
        MOV     ES:[DI.dir_date],ds     ;Set date
	pop	ds
ELSE
        MOV     AX,WORD PTR [SI.sf_size]
        MOV     ES:[DI.dir_size_l],AX   ;Set size
        MOV     AX,WORD PTR [SI.sf_size+2]
        MOV     ES:[DI.dir_size_h],AX
        MOV     AX,[SI.sf_date]
        MOV     ES:[DI.dir_date],AX     ;Set date
        MOV     AX,[SI.sf_time]
        MOV     ES:[DI.dir_time],AX     ;Set time
ENDIF
        TEST    ES:[BX.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:[BX.buf_flags],buf_dirty ;Buffer dirty
yesdirty:
        SAVE    <DS,SI>
        MOV     CX,[SI.sf_firclus]      ; do this for Fastopen

;hkn; SS override
        MOV     AL,[THISDRV]
;;; 10/1/86  update fastopen cache
        PUSH    DX
; *** TONYI *** Can we be *SURE* [THISDRV] is < 127?  If so CBW saves a byte!
        MOV     AH,0                    ; dir entry update
        MOV     DL,AL                   ; drive number A=0, B=1,,,
        OR      CX,CX                     ;AN005; first cluster 0; may be truncated
        JNZ     do_update2                ;AN005; no, do update
        MOV     AH,3                      ;AN005; do a delete cache entry
IFDEF __TONYI__1
;------------------------------------------------------------------
; Reshuffle to save 2 bytes and be faster....
; Note: "do_update" immediately reloads DS, so we can trash it here.
;------------------------------------------------------------------
        MOV     DH,[SI.sf_dirpos]            ;AN005; dh= dir pos
        lds     DI,DWORD PTR [SI.sf_dirsec]  ;AN005; cx:di = dir sector
	mov	cx, ds
ELSE
        MOV     DI,WORD PTR [SI.sf_dirsec]   ;AN005; cx:di = dir sector
        MOV     CX,WORD PTR [SI.sf_dirsec+2] ;AN005;
        MOV     DH,[SI.sf_dirpos]            ;AN005; dh= dir pos
ENDIF
        JMP     SHORT do_update         ;AN011;F.O.
do_update2:                             ;AN011;F.O.

;hkn; SS override fort OLD_FIRSTCLUS
        CMP     CX,[OLD_FIRSTCLUS]      ;AN011;F.O. same as old first clusetr?
        JZ      do_update               ;AN011;F.O. yes
        MOV     AH,2                    ;AN011;F.O. delete the old entry
        MOV     CX,[OLD_FIRSTCLUS]      ;AN011;F.O.
do_update:                                ;AN005;

;hkn; SS is DOSDATA
        Context DS
        invoke  FastOpen_Update         ; invoke fastopen
        POP     DX

;;; 10/1/86  update fastopen cache
        invoke  FLUSHBUF                ; flush all relevant buffers
        RESTORE <DI,ES>
        MOV     AL,error_access_denied
        JC      CloseFinish
FREE_SFT_OK:
        CLC                             ; signal no error.
CloseFinish:
;
; Indicate to the device that the SFT is being closed.
;
;;;; 7/21/86
        PUSHF                           ; save flag from DirFromSFT
        invoke  Dev_Close_SFT
        POPF
;;;; 7/21/86
;
; See if the ref count indicates that we have busied the SFT.  If so, mark the
; SFT as being free.  Note that we do NOT need to be in critSFT as we are ONLY
; going to be moving from busy to free.
;
        POP     CX                      ; get old ref count
        PUSHF
        fmt     TypAccess,LevBUSY,<"$p: DOSFreeSFT: $x:$x from $x\n">,<ES,DI,AX>
IFDEF __TONYI__1
;----------------------------------------------------------------
; LOOP is the same as DEC CX/JNZ, but 1 byte shorter!
;----------------------------------------------------------------
	loop	NoFree	; Note! This is *not* really a "loop".
ELSE
        DEC     CX                      ; if cx != 1
        JNZ     NoFree                  ; then do NOT free SFT
ENDIF
        Assert  ISSFT,<ES,DI>,"DOS_FREE_SFT"
        MOV     ES:[DI].sf_ref_Count,CX
NoFree:
        LeaveCrit   critDisk
        POPF
        return
EndProc DOS_Close

;---------------------------------------------------------------------------
;
; Procedure Name : FREE_SFT
;
; ES:DI -> SFT. Decs sft_ref_count.  If the count goes to 0, mark it as busy.
; Flags preserved.  Return old ref count in AX
;
; Note that busy is indicated by the SFT ref count being -1.
;
;---------------------------------------------------------------------------

Procedure   FREE_SFT,NEAR
        DOSAssume   <DS>,"Free_SFT"

        PUSHF           ; Save carry state
        MOV     AX,ES:[DI.sf_ref_count]
        DEC     AX
        JNZ     SetCount
        DEC     AX
SetCount:
        XCHG    AX,ES:[DI.sf_ref_count]
        POPF
        return

EndProc Free_SFT

;----------------------------------------------------------------------------
;
; Procedure Name : DirFromSFT
;
;   DirFromSFT - locate a directory entry given an SFT.
;
;   Inputs:     ES:DI point to SFT
;               DS = DOSDATA
;   Outputs:
;               EXTERR_LOCUS = errLOC_Disk
;               CurBuf points to buffer
;               Carry Clear -> operation OK
;                   ES:DI point to entry
;                   ES:BX point to buffer
;                   DS:SI point to SFT
;               Carry SET   -> operation failed
;                   registers trashified
;   Registers modified: ALL
;----------------------------------------------------------------------------

Procedure   DirFromSFT,NEAR
        DOSAssume   <DS>,"DOS_Close"

        ; BUGBUG - assert SFT
IFDEF __TONYI__1
;-------------------------------------------------
; Save 3 bytes......
;-------------------------------------------------
	invoke	SetErrLocDisk
ELSE
        MOV     [EXTERR_LOCUS],errLOC_Disk
ENDIF
        SAVE    <ES,DI>
        MOV     DX,WORD PTR ES:[DI.sf_dirsec+2]  ;F.C. >32mb
        MOV     [HIGH_SECTOR],DX                 ;F.C. >32mb
IFDEF __TONYI__1
;--------------------------------------------
; Enable saving 3 bytes below...faster too.
;--------------------------------------------
	push	dx	; (i.e. [HIGH_SECTOR])
ENDIF
        MOV     DX,WORD PTR ES:[DI.sf_dirsec]

IFNDEF __TONYI__1
;--------------------------------------------
; Save 3 bytes by pushing DX up above.....
;--------------------------------------------
        PUSH    [HIGH_SECTOR]                    ;F.C. >32mb
ENDIF
        PUSH    DX
        invoke  FATREAD_SFT             ; ES:BP points to DPB, [THISDRV] set
                                        ; [THISDPB] set
        POP     DX
        POP     [HIGH_SECTOR]                    ;F.C. >32mb
        JC      PopDone
        XOR     AL,AL                   ; Pre read
        MOV     [ALLOWED],allowed_FAIL + allowed_RETRY
        invoke  GETBUFFR
        JC      PopDone
        RESTORE <SI,DS>         ; Get back SFT pointer
        ASSUME  DS:NOTHING

;hkn; SS override
        LES     DI,Curbuf
        OR      ES:[DI.buf_flags],buf_isDIR
        MOV     BX,DI                   ; ES:BX point to buffer header
        LEA     DI,[DI].BUFINSIZ        ; Point to buffer
        MOV     AL,SIZE dir_entry
        MUL     [SI].sf_DirPos
        ADD     DI,AX                   ; Point at the entry

        return                          ; carry is clear
PopDone:
        RESTORE <DI,ES>
        return
EndProc DirFromSFT,NoCheck

        Break   <DOS_Commit - update directory entries>
;
;----------------------------------------------------------------------------
;
;**     DOS_Commit - UPdate Directory Entries
;
;       ENTRY   same as DOS_CLOSE (??? BUGBUG - update this jgl)
;               (DS) = DOSGROUP
;       EXIT    Same as DOS_CLOSE except ref_count field is not altered
;       USES    all but DS
;
;----------------------------------------------------------------------------
;

procedure   DOS_COMMIT,NEAR
        DOSAssume   <DS>,"DOS_Commit"    ;hkn; called from srvcall. DS already set up.

        LES     DI,[THISSFT]
        MOV     BX,ES:[DI.sf_flags]
        TEST    BX,devid_file_clean + devid_device      ;Clears carry
        retnz
        TEST    BX,sf_isnet
        JZ      LOCAL_COMMIT
IF NOT Installed
        transfer NET_COMMIT
ELSE
        MOV     AX,(multNET SHL 8) OR 7
        INT     2FH
        return
ENDIF

;
; Perform local commit operation by doing a close but not releaseing the SFT.
; There are three ways we can do this.  One is to enter a critical section to
; protect a potential free.  The second is to increment the ref count to mask
; the close decrementing.
;
; The proper way is to let the caller's of close decide if a decrement should
; be done.  We do this by providing another entry into close after the
; decrement and after the share information release.
;
LOCAL_COMMIT:
        EnterCrit   critDisk
        EnterCrit   critDisk            ;PTM.                                   ;AN000;
        call    SetSFTTimes
        MOV     AX,-1
        call    CloseEntry
        PUSHF                           ;PTM.                                   ;AN000;
        invoke  DEV_OPEN_SFT            ;PTM.  increment device count           ;AN000;
IFDEF __TONYI__1
;------------------------------------------------
; Save 2 bytes....
; NOTE: CritSec stuff does NOT touch flags, so
; the popf order isn't important here.
;------------------------------------------------
	jmp	NoFree	; Tail merge up in DOS_Close
ELSE
        POPF                            ;PTM.                                   ;AN000;
        LeaveCrit CritDisk              ;PTM.                                   ;AN000;
        return
ENDIF
EndProc DOS_COMMIT

Break   <SetSFTTimes - signal a change in the times for an SFT>
;----------------------------------------------------------------------------
;
; Procedure Name : SetSFTTimes
;
;   SetSFTTimes - Examine the flags for a SFT and set the time appropriately.
;   Reflect these times in other SFT's for the same file.
;
;   Inputs:     ES:DI point to SFT
;               BX = sf_flags set apprpriately
;   Outputs:    Set sft times to current time iff File & dirty & !nodate
;   Registers modified: All except ES:DI, BX, AX
;
;----------------------------------------------------------------------------

Procedure   SetSFTTimes,NEAR
        Assert  ISSFT,<ES,DI>,"SetSFTTimes"

;       File clean or device does not get stamped nor disk looked at.

        TEST    BX,devid_file_clean + devid_device
        retnz                           ; clean or device => no timestamp

;       file and dirty.  See if date is good

        TEST    BX,sf_close_nodate
        retnz                           ; nodate => no timestamp
        SAVE    <AX,BX>
        invoke  DATE16                  ; Date/Time to AX/DX
    ASSUME DS:DOSDATA
        MOV     ES:[DI.sf_date],AX
        MOV     ES:[DI.sf_time],DX
        XOR     AX,AX
if installed
        call    JShare + 14 * 4
else
        call    ShSU
endif
        RESTORE <BX,AX>
        return
EndProc SetSFTTimes

DOSCODE ENDS
        END
