        TITLE   'ifs - DOS Installable File System Interface'
        PAGE 59, 132
        .LALL

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  DOS Installable File System Interface                        ;
        ;...............................................................;

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Real Time Dos                                                ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  This material  was created as a published version  of a DOS  ;
        ;  equivalent product.   This program  logically  functions in  ;
        ;  the same way as  MSDOS functions and it  is  internal  data  ;
        ;  structure compliant with MSDOS 6.0                           ;
        ;                                                               ;
        ;  This product is distributed  AS IS and contains no warranty  ;
        ;  whatsoever,   including  warranty  of   merchantability  or  ;
        ;  fitness for a particular purpose.                            ;
        ;                                                               ;
        ;                                                               ;
        ;  (c) Copyright 1990, 1997. Api Software and Mike Podanoffsky  ;
        ;      All Rights Reserved Worldwide.                           ;
        ;                                                               ;
        ;  This product is protected under copyright laws and  may not  ;
        ;  be reproduced  in whole  or in part, in any form  or media,  ;
        ;  included but not limited to source listing, facsimile, data  ;
        ;  transmission, cd-rom, or  floppy disk without the expressed  ;
        ;  written consent of the author.                               ;
        ;                                                               ;
        ;  License  for  distribution  for commercial  use  or  resale  ;
        ;  required from:                                               ;
        ;                                                               ;
        ;  Api Software                                                 ;
        ;  12 South Walker Street                                       ;
        ;  Lowell,  MA   01851                                          ;
        ;                                                               ;
        ;  internet: mikep@world.std.com                                ;
        ;                                                               ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;  Compile with MASM 5.1                                        ;
        ;...............................................................;

        include rxdosmac.asm
        include rxdosdef.asm

RxDOS   SEGMENT PARA PUBLIC 'CODE'
        assume cs:RxDOS, ds:RxDOS, es:RxDOS, ss:RxDOS

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  DOS Installable File System Interface                        ;
        ;...............................................................;

        public Interrupt2F

    ; defined in rxdos

        extrn _RetCallersStackFrame             : near
        extrn _RxDOS_pCDS                       : dword
        extrn _RxDOS_bLastDrive                 : byte
        extrn _RxDOS_CurrentDrive               : byte
        extrn SDAFirstName                      : byte
        extrn SDASecondName                     : byte
        extrn SDApCurrentCDS                    : dword
    
        extrn pexterrInvalidFunction            : near
        extrn pexterrFileNotFound               : near
        extrn pexterrPathNotFound               : near
        extrn pexterrIllegalName                : near
        extrn pexterrNoHandlesAvailable         : near
        extrn pexterrAccessDenied               : near
        extrn pexterrInvalidHandle              : near
        extrn pexterrArenaTrashed               : near
        extrn pexterrNotEnoughMemory            : near
        extrn pexterrInvalidBlock               : near
        extrn pexterrInvalidAccess              : near
        extrn pexterrInvalidDrive               : near
        extrn pexterrCurrentDirectory           : near
        extrn pexterrNoMoreFiles                : near
        extrn pexterrFileExists                 : near

    ; defined in rxdosccb

        extrn CCBChanged                        : near
        extrn linkBegCCB                        : near
        extrn locateCCBPHeader                  : near
        extrn readBuffer                        : near
        extrn unlinkCCB                         : near
        extrn updateAllChangedCCBBuffers        : near

    ; defined in rxdosdev

        extrn checkforDeviceName                : near
        extrn checkforDeviceType                : near
        extrn DefineDPB                         : near
        extrn getDPB                            : near
        extrn getSysDate                        : near
        extrn setSysDate                        : near
        extrn getExpandedDateTime               : near
        extrn DevRead                           : near
        extrn DevWrite                          : near

    ; defined in rxdosfcb

        extrn initFCBfromSFT                    : near
        extrn buildFindFromFCB                  : near
        extrn buildDTAfcbFind                   : near

    ; defined in rxdosfil

        extrn blankinitDirName                  : near
        extrn initdiskAccess                    : near
        extrn compareDirEntries                 : near
        extrn computeLogSectorNumber            : near
        extrn ExpandFileName                    : near
        extrn LocateFile                        : near
        extrn LocateFreeDirSlot                 : near
        extrn LocateFileByAttribute             : near

        extrn GetActualDrive                    : near
        extrn getCurrDirCluster                 : near
        extrn getDevice                         : near
        extrn getDrive                          : near
        extrn getWhereInDir                     : near

    ; defined in rxdosmem

        extrn _initializeMemoryBlock            : near
        extrn _collectMemoryBlocks              : near
        extrn _releaseOwnerMemoryBlocks         : near
        extrn _allocateUpperMB                  : near
        extrn _allocateConvMB                   : near
        extrn _modifyMemBlock                   : near

    ; defined in rxdossft

        extrn createSFTEntry                    : near
        extrn FindAvailableSFTHandle            : near
        extrn findmatchingFCBSFT                : near
        extrn FindSFTbyHandle                   : near
        extrn MapApptoSFTHandle                 : near
        extrn MapSFTtoAppHandle                 : near
        extrn releaseSFT                        : near
        extrn VerifyAvailableHandle             : near

        extrn _SFTReadFile                      : near
        extrn _SFTWriteFile                     : near
        extrn _SFTOpenFile                      : near
        extrn _SFTCreateFile                    : near
        extrn _SFTCloseFile                     : near
        extrn _SFTCloseAllFiles                 : near
        extrn _SFTCommitFile                    : near

    ; defined in rxdosstr

        extrn CopyString                        : near
        extrn CopyBlock                         : near
        extrn convFCBNametoASCIZ                : near
        extrn convFilenametoFCBString           : near
        extrn getSysDateinDirFormat             : near
        extrn upperCase                         : near
        extrn lowerCase                         : near
        extrn __ascii_stosb                     : near
        extrn getMonthDayYear                   : near
        extrn getDaysSince1980                  : near
        extrn StringLength                      : near
        extrn condStringLength                  : near

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Installable File System (2f/11) Dispatch Table               ;
        ;...............................................................;

IFS_Dispatch:

        dw _IFSInstallCheck                     ; 00h Install Check
        dw _IFSRemoveDirectory                  ; 01h Remove Directory
        dw _IFSUndefined                        ; 02h (Unused)
        dw _IFSMakeDirectory                    ; 03h Make Directory
        dw _IFSUndefined                        ; 04h (Unused)
        dw _IFSChangeDirectory                  ; 05h Change Directory
        dw _IFSCloseFile                        ; 06h Close File
        dw _IFSCommitFile                       ; 07h Commit File
        dw _IFSReadFile                         ; 08h Read File
        dw _IFSWriteFile                        ; 09h Write File
        dw _IFSLockRegion                       ; 0Ah Lock Region
        dw _IFSUnlockRegion                     ; 0Bh Unlock Region
        dw _IFSGetDiskSpace                     ; 0Ch Get Disk Space
        dw _IFSUndefined                        ; 0Dh (Unused)
        dw _IFSSetFileAttributes                ; 0Eh Set File Attributes
        dw _IFSGetFileAttributes                ; 0Fh Get File Attributes
        dw _IFSUndefined                        ; 10h (Unused)
        dw _IFSRenameFile                       ; 11h Rename File
        dw _IFSUndefined                        ; 12h (Unused)
        dw _IFSDeleteFile                       ; 13h Delete File
        dw _IFSUndefined                        ; 14h (Unused)
        dw _IFSUndefined                        ; 15h (Unused)
        dw _IFSOpenFile                         ; 16h Open File
        dw _IFSCreateFile                       ; 17h Create File
        dw _IFSUnsupported                      ; 18h Create File without CDS
        dw _IFSUndefined                        ; 19h (Unused)
        dw _IFSUndefined                        ; 1Ah (Unused)
        dw _IFSFindFirst                        ; 1Bh Find First
        dw _IFSFindNext                         ; 1Ch Find Next
        dw _IFSCloseAllFiles                    ; 1Dh Close All Files
        dw _IFSSetRedirection                   ; 1Eh Set Redirection
        dw _IFSPrinterSetup                     ; 1Fh Printer Setup
        dw _IFSFlushBuffers                     ; 20h Flush Buffers
        dw _IFSSeekFromEnd                      ; 21h Seek From End
        dw _IFSTerminateProcess                 ; 22h Terminate Process
        dw _IFSQualifyFilename                  ; 23h Qualify Filename
        dw _IFSUndefined                        ; 24h (Unused)
        dw _IFSPrinterMode                      ; 25h Printer Mode
        dw _IFSPrinterOnOff                     ; 26h Printer On/Off
        dw _IFSCopy                             ; 27h Copy
        dw _IFSUndefined                        ; 28h (Unused)
        dw _IFSUndefined                        ; 29h (Unused)
        dw _IFSUndefined                        ; 2Ah (Unused)
        dw _IFSIOCTL                            ; 2Bh IOCTL
        dw _IFSUndefined                        ; 2Ch (Unused)
        dw _IFSUndefined                        ; 2Dh (Unused)
        dw _IFSExpandedOpen                     ; 2Eh Expanded Open/Create
        dw _IFSUndefined                        ; 2Fh (Unused)
        dw _IFSGetSegment                       ; 30h Get NFS Segment

_IFS_maxFunctionCode   equ ( $ - IFS_Dispatch ) / 2
IFS_INTERFACECODE       equ 11h

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Int 2F Original Chain                                        ;
        ;...............................................................;

Int2F_OriginalPtr:
        dd Int2F_DummyReturn
         
Int2F_DummyReturn:
        iret

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Install 2F Interface                                         ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  We know that the call is for us because no other redirector  ;
        ;  interface has claimed this call.                             ;
        ;                                                               ;
        ;...............................................................;

InstallRedirector:

        pushf                                           ; save interrupts

        cli
        xor ax, ax
        mov ds, ax
        mov bx, 002Fh * 4
        push word ptr [ bx. _pointer ]                  ; address
        push word ptr [ bx. _segment ]                  ; segment

        mov word ptr [ bx. _pointer ], offset Interrupt2F
        mov word ptr [ bx. _segment ], ss               ; segment

        pop word ptr ss:[ Int2F_OriginalPtr. _segment ]
        pop word ptr ss:[ Int2F_OriginalPtr. _pointer ] ; original

        pop ds
        popf                                            ; restore interrupts
        ret

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Interrupt 2F                                                 ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  We know that the call is for us because no other redirector  ;
        ;  interface has claimed this call.                             ;
        ;                                                               ;
        ;  al   contains function request                               ;
        ;...............................................................;

Interrupt2F   proc far

        cmp ah, IFS_INTERFACECODE                       ; is it the IFS function code ?
        jz Interrupt2F_08                               ; yes, allow -->
        iret

Interrupt2F_08:
        FarEntry 1
        arg  _returnFlag
        def  _FctAddress

        call IFS_SaveRegisters
        and word ptr [ _returnFlag ][ bp ], NOT 1       ; clear carry bit.

        sti
        cld

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  dispatch
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        cmp al, _IFS_maxFunctionCode                    ; max function code ?
        jnc Interrupt2F_26                              ; if out of range -->

        xor ah, ah
        mov bx, ax
        add bx, bx                                      ; word offset
        mov bx, word ptr [ IFS_Dispatch ][ bx ]
        mov word ptr [ _FctAddress ][ bp ], bx

        lea bx, offset [ _ReturnFlag + 2 ][ bp ]        ; ptr to arguments passed on stack
        mov cx, word ptr [ bx ]                         ; if arg passed on stack
        call word ptr [ _FctAddress ][ bp ]             ; call Function
        jnc Interrupt2F_26                              ; if carry not set -->
        or word ptr [ _returnFlag ][ bp ], 1            ; set carry bit.

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  return
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Interrupt2F_26:
        call IFS_RestoreRegisters

        mov sp, bp                                      ; part of return
        pop bp
        iret

Interrupt2F   endp

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Save Registers                                               ;
        ;...............................................................;

IFS_SaveRegisters:

        push cx
        push dx
        push si
        push di
        push ds
        push es

        push bp
        mov bp, sp
        xchg bx, word ptr ss:[ bp + 14 ]                ; return address to bx
        push bx
        mov bx, word ptr ss:[ bp + 14 ]                 ; restore bx
        mov bp, word ptr ss:[ bp ]                      ; restore bp
        ret                                             ; return

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Restore Registers                                            ;
        ;...............................................................;

IFS_RestoreRegisters:

        pop bx                                          ; really, its the return address
        pop cx                                          ; really discarded bp
        pop es
        pop ds
        pop di
        pop si
        pop dx
        pop cx

        push bp
        mov bp, sp
        xchg bx, word ptr ss:[ bp + 2 ]                 ; original bx
        pop bp                                          ; restore bp
        ret                                             ; return

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  IFS                                                          ;
        ;...............................................................;

_IFSChangeDirectory:
_IFSCloseAllFiles:
_IFSCloseFile:
_IFSCommitFile:
_IFSCopy:
_IFSDeleteFile:
_IFSExpandedOpen:
_IFSFindFirst:
_IFSFindNext:
_IFSFlushBuffers:
_IFSGetDiskSpace:
_IFSGetFileAttributes:
_IFSGetSegment:
_IFSInstallCheck:
_IFSIOCTL:
_IFSLockRegion:
_IFSMakeDirectory:
_IFSOpenFile:
_IFSPrinterMode:
_IFSPrinterOnOff:
_IFSPrinterSetup:
_IFSQualifyFilename:
_IFSReadFile:
_IFSRemoveDirectory:
_IFSSeekFromEnd:
_IFSSetFileAttributes:
_IFSSetRedirection:
_IFSTerminateProcess:
_IFSUnlockRegion:
_IFSWriteFile:

_IFSUndefined:
_IFSUnsupported:
        ret

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  IFS 17h Create File                                          ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  CX             attributes                                    ;
        ;  ES:DI          pointer to unitialized SFT                    ;
        ;  SDAFirstName   pointer to expanded file/path                 ;
        ;  SDApCurrentCDS pointer to CDS                                ;
        ;...............................................................;

_IFSCreateFile:

        Entry
        def   _Attributes, cx

        Return

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  IFS 11h Rename File                                          ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  SDAFirstName  first name                                     ;
        ;  SDASecondName second name                                    ;
        ;...............................................................;

_IFSRenameFile:

        Entry
        ddef _wherePointer
        defbytes _existfileAccess, sizeDIRACCESS
        defbytes _renfileAccess, sizeDIRACCESS

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  does existing file exist ?
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        mov ax, (FILE_NODEVICENAME + FILECANNOT_BEDIRECTORY)
        mov si, offset SDAFirstName
        lea di, offset _existfileAccess [ bp ]          ; work dir access block
        call LocateFile                                 ; check file path
        ifc _renameFile_40                              ; if file does not exist -->

        mov ax, (FILE_NODEVICENAME + FILECANNOT_BEDEFINED + FILECANNOT_BEDIRECTORY)
        mov si, offset SDASecondName
        lea di, offset _renfileAccess [ bp ]            ; renamed file dir access block
        call LocateFile                                 ; check file path
        ifc _renameFile_40                              ; if file does not exist -->

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  both files seem ok, so we'll move them 
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        mov al, byte ptr [ _existfileAccess. fileAcDrive ][ bp ]
        cmp al, byte ptr [ _renfileAccess. fileAcDrive ][ bp ]
        mov ax, offset pexterrPathNotFound
        stc
        ifnz _renameFile_40                             ; cannot move across drives -->

        mov ax, word ptr [ _existfileAccess. fileAcDirCluster ][ bp ]
        cmp ax, word ptr [ _renfileAccess. fileAcDirCluster ][ bp ]
        jnz _renameFile_22                              ; if must move files across dirs -->

        setDS ss
        mov si,  word ptr [ _renfileAccess. fileAcNameOffset  ][ bp ]
        les di, dword ptr [ _existfileAccess. fileAcBufferPtr ][ bp ]
        add di,  word ptr [ _existfileAccess. fileAcDirOffset ][ bp ]
        call convFilenametoFCBString                    ; convert name

        les si, dword ptr [ _existfileAccess. fileAcBufferPtr ][ bp ]
        call locateCCBPHeader
        call CCBChanged                                 ; update buffer
        jmp short _renameFile_38                        ; exit -->

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  move entry between directories
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_renameFile_22:
        and word ptr [ _renfileAccess. fileAcDrive   ][ bp ], 7FFFh
        mov ax, word ptr [ _renfileAccess. fileAcDrive   ][ bp ]
        mov dx, word ptr [ _renfileAccess. fileAcDirCluster ][ bp ]
        call LocateFreeDirSlot                          ; can we find a valid empty entry ?
        ifc _renameFile_40                              ; if can't find free slot -->

        stordarg _wherePointer, es, si        
        mov di, si                                      ; where entry must be copied to

        lds si, dword ptr [ _existfileAccess. fileAcBufferPtr ][ bp ]
        add si,  word ptr [ _existfileAccess. fileAcDirOffset ][ bp ]
        mov cx, ( sizeDIRENTRY / 2 )
        rep movsw                                       ; copy entry from source dir

        setDS ss
        getdarg es, di, _wherePointer
        mov si, word ptr [ _renfileAccess. fileAcNameOffset ][ bp ]
        call convFilenametoFCBString                    ; rename file

        getdarg es, si, _wherePointer
        call locateCCBPHeader
        call CCBChanged                                 ; update buffer

        les di, dword ptr [ _existfileAccess. fileAcBufferPtr ][ bp ]
        mov bx,  word ptr [ _existfileAccess. fileAcDirOffset ][ bp ]
        mov byte ptr es:[ di + bx ], DIRENTRY_DELETED
        call CCBChanged

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  return
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_renameFile_38:
        or ax, ax                                       ; no carry

_renameFile_40:
        Return

RxDOS   ENDS
        END

