;       SCCSID = @(#)demfcbio.asm       6.2 91/11/27
;       SCCSID = @(#)demfcbio.asm       6.2 91/11/27
;       SCCSID = @(#)demfcbio.asm       6.2 91/11/27
;
;   Revisions:
;
;Local  DCR/
;Tag    PTM(R)  Who     When/What
;               danno   09-Mar-1989
;                       Created for MVDM
;
; B001  11/17/91  CP20 AA04457  Mark Rogalski
;       FCB_delete interface has changed. Make call with ES set to 0.
;
; BN005 - 5/13/92  CP20 DEFECT 24729  Mark Rogalski                     ;BN005;
;         Remove unneeded code for handling RM devices.                 ;BN005;
;***********************************************************************;BN005;

.xlist
include v86seg.inc

.xcref
include basemaca.inc
include osmaca.inc
include demmac.inc
include dossymc.inc
include mvdmexp.inc
include demsvc.inc
include cpmfcb.inc
include error.inc
include opncreat.inc
include devhdr.inc
include dos3dev.inc
include demver.inc
.cref
.list

Random  =   2                           ; random operation
FCBRead =   4                           ; doing a read
Block   =   8                           ; doing a block I/O


        CpuMode 386


V86CODE SEGMENT
        ASSUME  CS:V86GROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING

        ReferV86   DMAADD

        EXTRN   FCB_Ret_Err:NEAR
        EXTRN   FCB_Ret_OK:NEAR
        EXTRN   FCB_Return:NEAR
        EXTRN   RMDevCheckNameFCB:NEAR
;BD005        EXTRN   RMDevCheckFCB:NEAR
;BD005        EXTRN   RMDevCloseDI:NEAR
;BD005        EXTRN   RMDevXFLAGS:NEAR
;BD005        EXTRN   RMDevAllocDI:NEAR
;m        EXTRN   RMDevOpen:NEAR
;m        EXTRN   RMDevClose:NEAR
;m        EXTRN   RMDevRead:NEAR
;m        EXTRN   RMDevWrite:NEAR
;BD005        EXTRN   SFFromSFN:NEAR
        EXTRN   get_user_stack:NEAR
        EXTRN   VMcheck_fcb:NEAR                 ; mdr
        EXTRN   os2_handled:BYTE                 ; mdr

        ASSUME  CS:V86GROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING


;***    $FCB_Delete - remove several files that match the input FCB
;
;       Given an FCB, remove all directory entries in the current
;       directory that have names that match the FCB's ?  marks.
;
;       ENTRY   DS:DX - point to an FCB
;               ES - segment of environment                             ;BN001
;       EXIT    directory entries matching the FCB are deleted
;               AL = FF if no entries were deleted.
;       USES    all
;
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure $FCB_Delete,NEAR
        call    VMcheck_fcb            ; mdr return if dos drive
        push    es                     ; save original es                ;BN001
        push    0                      ; place 0 in es to tell           ;BN001
        pop     es                     ; delete we have no environment   ;BN001
        SVC     SVC_DEMDELETEFCB
        pop     es                     ; restore es                      ;BN001
        jmp     FCB_Return
EndProc   $FCB_Delete

;***    $FCB_Rename - change names in place
;
;       Rename a file in place within a directory.  Renames multiple
;       files copying from the meta characters.
;
;       ENTRY   DS:DX point to an FCB.  The normal name field is the source
;                   name of the files to be renamed.  Starting at offset 11h
;                   in the FCB is the destination name.
;       EXIT    AL = 0 -> no error occurred and all files were renamed
;               AL = FF -> some files may have been renamed but:
;                   rename to existing file or source file not found
;       USES    all
;
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure $FCB_Rename,NEAR
        call    VMcheck_fcb            ; mdr return if dos drive
        SVC     SVC_DEMRENAMEFCB
        jmp     FCB_Return
EndProc   $FCB_Rename

;***    $Get_FCB_Position - set random record fields to current pos
;
;   $Get_FCB_Position - look at an FCB, retrieve the current position from the
;       extent and next record field and set the random record field to point
;       to that record
;
;   Inputs:     DS:DX point to a possible extended FCB
;   Outputs:    The random record field of the FCB is set to the current record
;   Registers modified: AX,DX,SI
;
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure $Get_FCB_Position,NEAR
        call    VMcheck_fcb             ; mdr return if DOS request
        invoke  GetExtended             ; point to FCB
        invoke  GetExtent               ; DX:AX is current record
        MOV     WORD PTR [SI.fcb_RR],AX ; drop in low order piece
        MOV     [SI+fcb_RR+2],DL        ; drop in high order piece
        CMP     [SI.fcb_RECSIZ],64
        JAE     GetFCBBye
        MOV     [SI+fcb_RR+2+1],DH      ; set 4th byte only if record size < 64
GetFCBBye:
        jmp     FCB_Ret_OK
EndProc $Get_FCB_Position

;***    $Get_FCB_File_Length - return the length of a file
;
;       Set the random record field to the length of the file in
;       records (rounded up if partial).
;
;       ENTRY   DS:DX - point to a possible extended FCB
;       EXIT    Random record field updated to reflect the number of records
;       USES    all
;
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure $Get_FCB_File_Length,NEAR
        call    VMcheck_fcb            ; mdr return if dos drive
        SVC     SVC_DEMFCBLENGTH
        jmp     FCB_Return
EndProc   $Get_FCB_File_Length

;***    $FCB_Close - close a file
;
;       Given an FCB, look up the SFN and close it.  Do not free it
;       as the FCB may be used for further I/O
;
;       ENTRY   DS:DX point to FCB
;       EXIT    AL = FF if file was not found on disk
;       USES    all
;
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure $FCB_Close,NEAR
        invoke  GetExtended
;BD005        call    RMDevCheckFCB           ; Local device FCB?
;BD005        jnc     short fcl1              ; yes? let DOS handle it
        call    VMcheck_fcb             ; mdr return if dos drive

        SVC     SVC_DEMFCBCLOSE
        jmp     FCB_Return

;BD005 fcl1:   mov     cs:os2_handled,0        ; mdr
;BD005         ret                             ; mdr

;mdrfcl1:   xor     bh,bh
;mdr        mov     bl,ds:[si].fcb_sfn
;mdr        call    RMDevCloseDI
;mdr        jmp     FCB_Return

EndProc   $FCB_Close

;***    $FCB_Create - create a new directory entry
;
;       CPM compatability file create.  The user has formatted an
;       FCB for us and asked to have the rest filled in.
;
;       ENTRY   DS:DX point to an unopenned FCB
;       EXIT    AL indicates status 0 is ok FF is error
;               FCB has the following fields filled in:
;                   Time/Date Extent/NR Size
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure $FCB_Create,NEAR
        call    RMDevCheckNameFCB       ; local device?
        jnc     fop0                    ; Yes? let dos handle it
        call    VMcheck_fcb             ; mdr return if dos drive
        mov     ax,exist_replace+nexist_create
        xor     bx,bx                   ; (BX) = create attributes
        call    GetExtended             ; (DS:SI) = fcb pointer
        jz      short fcr10
        mov     bl,[si-1]
fcr10:  SVC     SVC_DEMFCBOPEN
        jmp     FCB_Return

EndProc   $FCB_Create

;***    $FCB_Open - open an old-style FCB
;
;       CPM compatability file open.  The user has formatted an FCB
;       for us and asked to have the rest filled in.
;
;       ENTRY   DS:DX point to an unopenned FCB
;       EXIT    AL indicates status 0 is ok FF is error
;               FCB has the following fields filled in:
;                   Time/Date Extent/NR Size
;
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure $FCB_Open,NEAR
        call    RMDevCheckNameFCB       ; Local device?
        jnc     short fop0              ; mdr yes? let DOS handle it
        call    VMcheck_fcb             ; mdr return if dos drive

        mov     ax,exist_open+nexist_fail
        SVC     SVC_DEMFCBOPEN
        jmp     FCB_Return

fop0:   mov     cs:os2_handled,0        ; mdr let DOS handle local devices
        ret                             ; mdr

IF NOT_FILTER

fop1:   SaveReg <ds,dx>
        mov     ax,es:[bx].SDevAtt      ; Get device attributes
        call    RMDevXFlags             ; Translate to RMDI flags
        call    RMDevAllocDI            ; Assign a DevInfo entry (V86 SFT)
        jc      short fop5              ; Exit if none available

        mov     bx,ax
        SaveReg <ax>                    ; save VSFN
        call    SFFromSFN               ; ES:DI points to VSFN
        dec     es:[di].rmdi_refcnt     ; Remove extra reference
        call    RMDevOpen               ; Open it; Will increment refcnt
        RestoreReg <ax>
        RestoreReg <si,ds>
        jc      short fop10             ; jump if open failed
        mov     ds:[si].fcb_sfn, al     ; put sfn in fcb
        call    GetRecSize
        jmp     FCB_Ret_OK

fop5:   jmp     FCB_Ret_Err

fop10:  push    ax                      ; push error code
        call    RMDevClose              ; Deallocate DI entry
        pop     ax
        jmp     short fop5
ENDIF

EndProc   $FCB_Open

;***    $FCB_Random_write_Block - write a block of records to a file
;
;       Retrieve a location from the FCB, seek to it and write a number
;       of blocks from it.
;
;       ENTRY   DS:DX point to an FCB
;               CX number of records to write
;       EXIT    AL = 0 write was successful and the FCB position is updated
;               AL <> 0 Not enough room on disk for the output
;
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure $FCB_Random_Write_Block,NEAR
        MOV     AL,Random+Block
        JMP     short FCBIO
EndProc $FCB_Random_Write_Block

;***    $FCB_Random_Read_Block - read a block of records to a file
;
;       Retrieve a location from the FCB, seek to it and read a
;       number of blocks from it.
;
;       ENTRY   DS:DX point to an FCB
;               CX number of records to read
;       EXIT    AL = error codes defined above
;
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure $FCB_Random_Read_Block,NEAR
        MOV     AL,Random+FCBRead+Block
        jmp     short FCBIO
EndProc $FCB_Random_Read_Block

;***    $FCB_Seq_Read - read the next record from a file
;
;       Retrieve the next record from an FCB and read it into memory.
;
;       ENTRY   DS:DX point to an FCB
;       EXIT    AL = error codes defined above

        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure $FCB_Seq_Read,NEAR
        MOV     AL,FCBRead
        jmp     short FCBIO
EndProc $FCB_Seq_Read

;***    $FCB_Seq_Write - write the next record to a file
;
;       Retrieve the next record from an FCB and write it to the file.
;
;       ENTRY   DS:DX point to an FCB
;       EXIT    AL = error codes defined above
;
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure $FCB_Seq_Write,NEAR
        MOV     AL,0
        jmp     short FCBIO
EndProc $FCB_SEQ_WRITE

;***    $FCB_Random_Read - Read a single record from a file
;
;       Retrieve a location from the FCB, seek to it and read a
;       record from it.
;
;       ENTRY   DS:DX point to an FCB
;       EXIT    AL = error codes defined above
;
;
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure $FCB_Random_Read,NEAR
        MOV     AL,Random+FCBRead
        jmp     short FCBIO                   ; single block
EndProc $FCB_RANDOM_READ

;***    $FCB_Random_Write - write a single record to a file
;
;       Retrieve a location from the FCB, seek to it and write
;       a record to it.
;
;       ENTRY   DS:DX point to an FCB
;       EXIT    AL = error codes defined above
;
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure $FCB_Random_Write,NEAR
        MOV     AL,Random
        jmp     short FCBIO
EndProc $FCB_RANDOM_WRITE

;***    FCBIO - do internal FCB I/O
;
;       Look at FCBOP and merge all FCB operations into a single routine.
;
;       ENTRY   FCBOP flags which operations need to be performed
;               DS:DX point to FCB
;               CX may have count of number of records to xfer
;       EXIT    AL has error code
;       USES    all
;
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure FCBIO,NEAR
        push    ax
        xor     al,al                   ; re-open FCB if closed
        invoke  GetExtended
;BD005        call    RMDevCheckFCB           ; local device?
        pop     ax
;BD005        jnc     short fio3              ; yes? let DOS handle it
        call    VMcheck_fcb             ; mdr return if dos drive

        SVC     SVC_DEMFCBIO            ; (AX) = error code, (DL) = FCBErr
        push    dx                      ; mdr save fcb error code
        push    ax                      ; mdr save regular error code
        jc      short fio1              ; skip if error
        call    get_user_stack          ; (DS:SI) = user stack
        mov     ds:[si.User_CX],cx      ; return CX
        mov     dx,ds:[si.User_DX]      ; mdr get original ds:dx
        mov     ax,ds:[si.User_DS]      ; mdr
        mov     ds,ax                   ; mdr

fio1:   pop     ax                      ; mdr get regular error code
        call    FCB_Return
        pop     ax                      ; (AL) = FCBErr
fio2:   ret


;BD005 fio3:   mov     cs:os2_handled,0        ; mdr let DOS handle this
;BD005         ret                             ; mdr

IF NOT_FILTER

fio3:   test    al,Block                ; Is it block I/O
        jnz     fio4
        mov     CX,1                    ;       cRec = 1;

fio4:   call    GetRecSize
        push    ds
        push    si
        push    ax                      ; At this point CX = nRecords
        mov     ax,cx                   ; and BX = Rec Size
        mul     bx
        mov     cx,ax                   ; CX = cBytes to transfer
        pop     ax
        push    ax
        mov     dx, word ptr [DMAADD]
        test    al,FCBRead
        jz      short fio7              ; do write

        call    RMDevRead
        jnc     short fio45
        call    FCB_Ret_Err
        jmp     short fio50

fio45:  call    get_user_stack          ; (DS:SI) = user stack
        mov     ds:[si.User_CX],ax      ; return CX
        jz      short fio5              ; end of file indication
        jmp     fio15                   ; successful read but not at eof

fio5:   or      ax,ax
        jz      short fio6
        mov     ax,3                    ; At end of file and Partial read
fio50:  pop     bx
        pop     si
        pop     ds
        ret                             ; cant call FCB_Ret_OK

fio6:   mov     ax,1                    ; At end of file and no data read
        jmp     short fio50             ; cant call FCB_Ret_OK

fio7:   call    RMDevWrite
        jnc     short fio10             ; operation successful
        call    FCB_Ret_Err
        jmp     short fio50

fio10:  call    get_user_stack          ; (DS:SI) = user stack
        mov     ds:[si.User_CX],ax      ; return CX
fio15:  pop     ax                      ; Can not pop ax
        pop     si
        pop     ds
        test    ax,Block+Random         ; Set extent/NR field for seq ops.
        jnz     short fio20
        call    GetExtent
        add     ax,1
        adc     dx,0
        call    SetExtent
fio20:  jmp     FCB_Ret_OK

ENDIF
EndProc                                                         FCBIO

;***    GetExtended - Make DS:SI point to FCB from DS:DX
;
;       ENTRY   DS:DX point to a possible extended FCB
;       EXIT    DS:SI point to the FCB part
;               zeroflag set if not extended fcb
;       USES    SI

        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING
Procedure GetExtended
        MOV     SI,DX                   ; point to Something
        CMP     BYTE PTR DS:[SI],-1     ; look for extention
        JNZ     GetBye                  ; not there
        ADD     SI,7                    ; point to FCB
GetBye:
        CMP     SI,DX                   ; set condition codes
        RET
EndProc   GetExtended

;***    GetExtent - retrieve next location for sequential IO
;
;       Construct the next record to perform I/O from the EXTENT and
;       NR fields in the FCB.
;
;       ENTRY   DS:SI - point to FCB
;       EXIT    DX:AX contain the contents of the random record field
;       USES    AX,DX
;
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure GetExtent,NEAR
        MOV     AL,[SI.fcb_NR]          ; get low order piece
        MOV     DX,[SI.fcb_EXTENT]      ; get high order piece
        SHL     AL,1
        SHR     DX,1
        RCR     AL,1            ; move low order bit of DL to high order of AH
        MOV     AH,DL
        MOV     DL,DH
        XOR     DH,DH
        RET
EndProc   GetExtent

;***    SetExtent - update next location for sequential IO
;
;       Chnage the position of an FCB by filling in the extent/NR fields.
;
;       ENTRY   DS:SI - point to FCB
;               DX:AX contain the contents of the random record field
;       EXIT    Extent/NR field set
;
;       USES    CX,AX,DX
;
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure SetExtent,NEAR
        MOV     CX,AX
        AND     AL,7FH
        MOV     [SI.fcb_NR],AL
        AND     CL,80H
        SHL     CX,1
        RCL     DX,1
        MOV     AL,CH
        MOV     AH,DL
        MOV     [SI.fcb_EXTENT],AX
        RET

EndProc   SetExtent

;   GetRecSize - return in BX the record size from the FCB at DS:SI
;
;   Inputs:     DS:SI point to a non-extended FCB
;   Outputs:    BX contains the record size
;   Registers modified: None
;
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure   GetRecSize,NEAR
        MOV     BX,[SI.fcb_RECSIZ]      ; get his record size
        OR      BX,BX                   ; is it nul?
        jnz     grsx
        MOV     BX,128                  ; use default size
        MOV     [SI.fcb_RECSIZ],BX      ; stuff it back
grsx:   ret
EndProc GetRecSize

V86CODE ENDS

        END
