;       SCCSID = @(#)inisifs.asm        6.7 92/03/08
        page    ,132
        .sall
        .286p
        name    sifs
        title   CP/DOS SysInit File System  ***  IBM CONFIDENTIAL  **

SCCSID  equ     "@(#)inisifs.asm        6.7 92/03/08"

;
;                 IBM/Microsoft Confidential
;
;           Copyright (c) IBM Corporation  1987, 1990
;           Copyright (c) Microsoft Corp.  1987, 1990
;                     All Rights Reserved
;

;
; Source File Name:     INISIFS.ASM
;
; Descriptive Name:     CP-DOS System Initialization File System (SIFS)
;
; Function:     This module contains routines which comprise a basic file
;               system for using in loading files during system initialization.
;
; Notes:        - All code in this file is new                          ;@@
;               - All external entrypoints in this module may be called in
;               protect mode only. However, buffer addresses will be physical.
;               - Files must be opened before they are read.
;               - SIFS does not allocate memory to read the file into; that is
;               left up to the caller.
;
; Dependencies: - Memory management must be initialized before SIFS.
;               - The system must be running in protected mode.
;               - SIFS must be initialized before a file may be opened.
;               - SIFS must be terminated when it's usefulness is exhausted.
;               - DosCode and DOSGROUP MUST BE TILED.
;
; Restrictions: - The buffer for reads MUST be in LOW MEMORY.
;               - Interrupts must remain disabled from before switching to
;               real mode till the return switch to protect mode.
;
; Entry Points: syiInitSIFS:DOSCODE (hybrid, protect mode only)
;               SYIOpenFile:DOSCODE (hybrid, protect mode only)
;               syiPreInitSIFS:DOSCODE (near, real mode only)
;               SYIReadFile:DOSCODE (hybrid, protect mode only)
;               syiReInitSIFS:DOSCODE (hybrid, protect mode only)
;               syiTermSIFS:DOSCODE (hybrid, protect mode only)
;
; External References:
;               SegAlloc
;               SegRealloc
;               SegFree
;               SegLock
;               SelToSeg
;               RealModeIC
;               ProtModeIC
;               VirtToPhys
;
; Hierarchy:
;
; PreInit       Init            Open             Read           Term
;                /|\                           /   |  \
;              /  | \                       /      |     \
;            /    |   \                  /         |        \
;       GetBPB GetFAT GetDir GetNextCluster Cluster2Sector ValidateCluster
;                  \     |    /
;                    \   |  /                           ProtMode
; - - - - - - - -   ReadSectors  - - - - - - - - - - - - - - - - - - - - -
;                       |                               RealMode
;                   DHReadSC                            DOSHelp
;

        .xlist
        include dosseg.inc
        include basemaca.inc
        include fnoinit.inc
        include osmaca.inc
        include mi.inc
        include struc.inc
        include doshlp.inc
        .xlist
        include bpb.inc
        include dirent.inc
        include mhandle.inc
        include pmode.inc
        include fsc.inc
        .xlist
        include initmac.inc
        include inisms.inc            ; SysInit Message Segment
        .xlist
        include basemid.inc           ; Message IDs
        .list
include dossymc.inc
include except.inc
include sigdef.inc
include osconst.inc
include pgexport.inc
include vmexport.inc
include tkexport.inc
include infoseg.inc
include curdir.inc
include find.inc
include screen.inc
include sem.inc
include tkptda.inc
include error.inc
include ldrvars.inc

        ModName  , FNO_INISIFS_ASM
        CpuMode 386


        EXTRNFAR        SegAlloc                ;see virtseg.asm
        EXTRNFAR        SegRealloc              ;see virtseg.asm
        EXTRNFAR        SegFree                 ;see virtseg.asm
        EXTRNFAR        SegLock                 ;see virtseg.asm
        EXTRNFAR        SegUnlock               ;see virtseg.asm
        EXTRNFAR        SelToSeg                ;see modesw.asm
        EXTRNFAR        VirtToPhys              ;see virtphys.asm
        EXTRNFAR        WrtToScrn               ;see subr.asm

        extrn           RealModeIC:near ; see initmac.inc
        extrn           ProtModeIC:near ; see initmac.inc
        extrn           _SELLdrDesc:near
        extrn           _SELFreeGDT:near
        extrn           SYIAbort:near
ifdef PMDEBUG
        EXTRN           SIDebugLoadSymDosFS:near
        EXTRN           SIDebugLoadSymModule:near
endif

        EXTRNF32        _TKSetSSBase            ; see initmac.inc

        ReferGDT        GDT_RM_IDT,word         ;see sdata.asm

        ReferInitGlobal mfscNameList,BYTE
        ReferInitGlobal mfscInitTemplate,BYTE
        ReferInitGlobal tbl_syi_boot_err,BYTE
        ReferInitGlobal tbl_mFSD_failure_2,BYTE

        ReferInitGlobal ConfigSysFilename,BYTE

        ReferGlobal     mFSD_FLAG,BYTE          ;Mini-FSD is present
        ReferGlobal     SISData,BYTE            ;Global infoseg
        ReferGlobal     pMiniFSD,DWORD
        ReferGlobal     VectorRIPL,DWORD
        ReferGlobal     MFSD_Stage,BYTE
        ReferGlobal     NumIORipl,BYTE  ;Number of RIPL drives reserved (CDB)
        ReferGlobal     DumpProc,DWORD          ;Dump exit routine

        ReferFlat       _pPTDACur,dword
        ReferFlat       _ldrpFileNameBuf,dword

        public          _FileBufferAddress, FileBufferAddress
        public          _FileBufferLength, FileBufferLength
        public          BytesPerSector
        public          _FatDirtyBit, FatDirtyBit
        public          _FileReadBuffer, FileReadBuffer
ifdef testhooks
        public          Cluster2Sector
        public          GetBPB
        public          GetDir
        public          GetFAT
        public          GetNextCluster
        public          ParseFilespec
        public          ReadClusters
        public          ReadHTS
        public          ReadSectorBuffered
        public          ReadSectors
        public          ReadSectorsDirect
        public          Sector2HTS
        public          ValidateCluster
endif


.panic  macro   %cond,%text
        ifb     <%text>
          InternalError   <%cond>
        else
          .if     <%cond>
            InternalError   <%text>
          .endif
        endif
        endm


; FastRepMov - Macro to minimize the amount of time to copy from one
;              buffer to another.  Works for 16-bit or 32-bit code
;
;    Input: nosaveeax : blank - Saves and restores EAX
;                       nonblank - blasts EAX
;
;
;   The following register must be setup before using this macro:
;        ds:(e)si = Source buffer
;        es:(e)di = Target buffer
;        cx       = Number of bytes to copy
;
;
FastRepMov  macro nosaveeax
     ifb <nosaveeax>
        push    eax                   ; Save EAX unless told not to
     endif
        mov     eax,ecx               ; save byte count
        shr     ecx,02                ; convert to DWORD size
        rep     movsd

        mov     ecx,eax               ; restore byte count
        and     ecx,3                 ; get leftover bytes
        rep     movsb                    ; copy them
     ifb <nosaveeax>
        pop     eax
     endif                            ; Restore EAX unless told not to
endm

cylsec          struc           ;cylinder/sector
sector          dw      ?       ;sector
cylinder        dw      ?       ;cylinder
cylsec          ends

qbyte   struc           ;double word
lsw     dw      ?       ;least significant word
msw     dw      ?       ;more significant word
qbyte   ends

dbyte   struc           ;double byte
lsb     dw      ?       ;least significant byte
msb     dw      ?       ;more significant byte
dbyte   ends

PARASHIFT       equ     4

SIFS_SEG_FLAGS    equ HF_LOWMEM+HF_MOVABLE+HF_ZEROINIT ;flags for SegAlloc
SIFS_HISEG_FLAGS  equ HF_MOVABLE+HF_ZEROINIT ;flags for SegAlloc

CONSTANTS SEGMENT
        extrn   DHF:dword
CONSTANTS ENDS

INITDATA segment

        public          SIFSRoutines
SIFSRoutines label   word
        dd      offset FLAT:SIOpen
        dd      offset FLAT:SIClose
        dd      offset FLAT:SIReadAt
        dd      offset FLAT:SIIOSftTransPath
        dd      offset FLAT:SIldrGetMedia
ifdef PMDEBUG
        dd      offset FLAT:SIDebugLoadSymDosFS
        dd      offset FLAT:SIDebugLoadSymModule
endif

INITDATA ends

INITBSS segment
SIFilePointer   dd      ?       ;currentposition in file for SI calls
INITBSS ends

DATA segment            ;##### would rather have this in DosInitRMData

; media parameters
BytesPerSector          dw      512     ;BPB_BytesPerSector (usually 512)
_FatDirtyBit            label   BYTE
FatDirtyBit             db      0       ;FAT Dirty Bit from BPB (Curhd) ;### AC DCR 1520
BytesPerCluster         dw      ?
ClusterSectorBase       dw      ?       ;starting sector of file area
DirEntryCount           dw      ?       ;number of entries in root directory
OS2DirEntryCount        dw      ?       ;### DCR 403 number of entries in OS2 directory
OS2BOOTDirEntryCount    dw      ?       ;number of entries in OS2\BOOT directory
DirSectorBase           dw      ?       ;starting sector of root directory
DirSectorCount          dw      ?       ;number of sectors in root directory
FATSectorBase           dw      ?       ;starting sector of FAT
FATSectorCount          dw      ?       ;number of sectors in first FAT
FATSectorCount2         dw      0       ;number of sectors in second FAT
FileClusterBase         dw      ?       ;starting cluster number of file
StartFileClusterBase         dw      ?       ;starting cluster number of file
HeadCount               db      ?       ;BPB_Heads
PartitionBase           cylsec  <0,0>   ;start of disk partition
SectorsPerCluster       dw      ?       ;BPB_SectorsPerCluster (usually 1 to 8)
SectorsPerTrack         db      1       ;BPB_SectorsPerTrack
SectorsPerCylinder      dw      1       ;SectorsPerTrack*HeadCount

;
; Cache Parameters (defines the contents of FileReadBuffer)
;
; CacheStartByte and CacheByteSize are initialized in syiOpenFile, and
;  are updated in syiReadAtFile.  The parameter values are valid until the
;  file is closed.
;
CacheStartByte         dd      ?        ;the cache starting byte (file relative)
CacheByteSize          dd      ?        ;# of bytes cached starting from
                                        ;  CacheStartByte    (<=64K)



; directory data:
public _DirBufferSelector, DirBufferSelector
_DirBufferSelector      label   WORD
DirBufferSelector       dw      ?       ;selector for directory buffer
DirBufferLength         dw      ?       ;number of bytes in directory buffer
DirEntrySize            dw      32      ;number of words in directory entry

;### DCR 403 OS2 directory data:
   public _OS2DirBufferSelector, OS2DirBufferSelector
   public _OS2BOOTDirBufferSelector, OS2BOOTDirBufferSelector
_OS2DirBufferSelector   label   WORD
OS2DirBufferSelector    dw      0       ;selector for OS2 directory buffer
_OS2BOOTDirBufferSelector       label   WORD
OS2BOOTDirBufferSelector dw      0       ;selector for OS2\BOOT directory buffer

OS2AVAIL                db      0
OS2BOOTAVAIL            db      0

; FAT data:
FATBufferLength1        dd      ?       ;number of bytes in first FAT buffer
FATBufferSelector1      dw      ?       ;selector for first FAT buffer
FATBufferLength2        dd      0       ;number of bytes in second FAT buffer
FATBufferSelector2      dw      0       ;selector for second FAT buffer
FATEntrySize            db      ?       ;number of bits in FAT entry

; file data:
_FileBufferAddress      label   DWORD
FileBufferAddress       dd      ?       ;physical address of read buffer
_FileBufferLength       label   DWORD
FileBufferLength        dd      ?       ;length of read buffer
FileDataOffset          dw      ?       ;byte offset from beginning of tmp file
FileNameBuffer          db 11 dup (?)   ;buffer for file name
MfsdOS2NameBuffer       db      '\OS2\          '  ;### DCR 403 buffer for file name
OS2NameBuffer           db      'OS2        '      ;### DCR 403 OS2 dir name

MfsdOS2BOOTNameBuffer   db      '\OS2\BOOT\             ' ;buffer for file name
OS2BOOTNameBuffer       db      'BOOT           '         ;BOOT dir name

EndNameBuffer           db 11 dup (00h) ;### DCR 403 null entry in directory chain
FileOpenFlag            db      FALSE   ;file open flag
FileSize                dd      ?       ;number of bytes in file
_FileReadBuffer         label   WORD
FileReadBuffer          dw      ?       ;selector for file read buffer

TempDirSize             dw      ?

; misc
ResetSubsystemFlag      db      ?       ;disk/diskette reset flag
SIFSAvailableFlag       db      0       ;SIFS available flag
SIFSNumInits            db      0       ;keep track of number of inits.
   public  BootBPB
BootBPB                 a_BPB   <>      ;boot BPB


DATA ends               ;##### would rather have this in DosInitRMData

        FARCODE INIT
INITCODE segment


;
; SUBROUTINE NAME:      Cluster2Sector
;
; DESCRIPTIVE NAME:     Get logical sector number
;
; FUNCTION:     Convert a cluster number to a logical sector number.
;
; NOTES:        none
;
; ENTRY POINT:  Cluster2Sector
;    LINKAGE:   call (near)
;
; INPUT:        ax = cluster number
;               ds -> DOSGROUP
;
; EXIT-NORMAL:  dx:ax = logical sector number
;
; EXIT-ERROR:   none
;
; EFFECTS:      none
;
; INTERNAL REFERENCES:
;    ROUTINES:  none
;
; EXTERNAL REFERENCES:
;    ROUTINES:  none
;
; Pseudo Code:
;       sector = ((cluster-2)*SectorsPerCluster)+ClusterSectorBase
;       Return
;

Procedure Cluster2Sector,near,local
    assume ds:DOSGROUP,es:nothing,fs:nothing,gs:nothing,ss:nothing
sub             ax,2                    ;ax = cluster number
mul             SectorsPerCluster       ;dx:ax = sector number
add             ax,ClusterSectorBase
adc             dx,0
.panic          <c>,<SIFS: Cluster2Sector: logical sector number too large>
ret
EndProc Cluster2Sector


;
; SUBROUTINE NAME:      GetBPB
;
; DESCRIPTIVE NAME:     Get BPB
;
; FUNCTION:     Read in the BPB. This data structure describes the media's
;               parameters.
;
; NOTES:        The BPB for the boot media was read into memory by the boot
;               code.
;
; ENTRY POINT:  GetBPB
;    LINKAGE:   call (near)
;
; INPUT:        nothing
;
; EXIT-NORMAL:  es:bx -> bpb
;
; EXIT-ERROR:   none
;
; EFFECTS:      none
;
; INTERNAL REFERENCES:
;    ROUTINES:  none
;
; EXTERNAL REFERENCES:
;    ROUTINES:  none
;
; Pseudo Code:
;     Get the pointer to the BPB buffer
;     Return
;

Procedure GetBPB,near,local
    assume ds:nothing,es:nothing,fs:nothing,gs:nothing,ss:nothing
mov             bx,DOSGROUP                     ;es:bx -> BPB
mov             es,bx
mov             bx,offset DOSGROUP:BootBPB
ret
EndProc GetBPB


;
; SUBROUTINE NAME:      GetDir
;
; DESCRIPTIVE NAME:     Get Directory
;
; FUNCTION:     Read the disk directory.
;
; NOTES:        The root directory is assumed to be contiguous.
;
; ENTRY POINT:  GetDir
;    LINKAGE:   call (near)
;
; INPUT:        nothing
;
; EXIT-NORMAL:  nothing
;
; EXIT-ERROR:   none
;
; EFFECTS:      no registers preserved
;
; INTERNAL REFERENCES:
;    ROUTINES:  ReadSectors
;
; EXTERNAL REFERENCES:
;    ROUTINES:  none
;
; Pseudo Code:
;       Read the directory (call ReadSectors)
;       Return
;

Procedure GetDir,near,local
    assume ds:DOSGROUP,es:nothing,fs:nothing,gs:nothing,ss:nothing
SaveReg         <ds>
mov             ds,FileReadBuffer               ;DS:SI -> below 1MB buffer
assume ds:nothing
xor             si,si
CALLFAR         VirtToPhys                      ;ax:bx = physical address
.panic          <c>,<SIFS: GetDir: can not get address of directory buffer>
RestoreReg      <ds>
assume ds:DOSGROUP
test            ax,0FFF0h                       ;check for low memory
.panic          <nz>,<SIFS: GetDir: directory buffer is above the 1M boundary>
mov             FileBufferAddress.msw,ax
mov             FileBufferAddress.lsw,bx
xor             ax,ax
mov             FileBufferLength.msw,ax
mov             ax,DirBufferLength
mov             FileBufferLength.lsw,ax
mov             ax,DirSectorBase
mov             cx,DirSectorCount
xor             dx,dx                           ; Dir sector is at start of disk
call            SYIReadSectors

SaveReg         <es,ds,edi,esi,ecx>
xor             esi,esi
xor             edi,edi
movzx           ecx,DirBufferLength
mov             es,DirBufferSelector            ;es:di -> directory buffer
mov             ds,FileReadBuffer               ;DS:SI -> below 1MB buffer
assume ds:nothing
FastRepMov

DosContext      ds                              ;
mov             es,FileReadBuffer               ;now clear out FileReadBuffer
xor             edi,edi                         ;
mov             ecx,4000h                       ;
xor             eax,eax                         ;
rep             stosd                           ;

RestoreReg      <ecx,esi,edi,ds,es>

assume ds:DOSGROUP
ret
EndProc GetDir


;
; SUBROUTINE NAME:      GetFAT
;
; DESCRIPTIVE NAME:     Get the FAT
;
; FUNCTION:     To get the File Allocation Table
;
; NOTES:        The FAT is assumed to be contiguous.
;
; ENTRY POINT:  GetFAT
;    LINKAGE:   call (near)
;
; INPUT:        nothing
;
; EXIT-NORMAL:  nothing
;
; EXIT-ERROR:   none
;
; EFFECTS:      no registers preserved
;
; INTERNAL REFERENCES:
;    ROUTINES:  ReadSectors
;
; EXTERNAL REFERENCES:
;    ROUTINES:  none
;
; Pseudo Code:
;       Read the FAT (call ReadSectors)
;       Set the FAT terminator
;       Return
;

Procedure GetFAT,near,local
    assume ds:DOSGROUP,es:nothing,fs:nothing,gs:nothing,ss:nothing
        SaveReg <ds>
        mov     ds,FileReadBuffer
        assume ds:nothing
        xor     si,si
        CALLFAR VirtToPhys                      ;ax:bx = physical address
        .panic  <c>,<SIFS: GetFAT: can not get address of first FAT buffer>
        RestoreReg <ds>
        assume ds:DOSGROUP
        test    ax,0FFF0h                       ;check for low memory
        .panic  <nz>,<SIFS: GetFAT: First FAT buffer is above the 1M boundary>
        mov     FileBufferAddress.msw,ax
        mov     FileBufferAddress.lsw,bx
        mov     ax,FATBufferLength1.msw
        mov     FileBufferLength.msw,ax
        mov     ax,FATBufferLength1.lsw
        mov     FileBufferLength.lsw,ax
        mov     ax,FATSectorBase
        mov     cx,FATSectorCount
        xor     dx,dx                       ; dx:ax = sector number
        call    SYIReadSectors              ; Read the first part of the FAT

        SaveReg   <es,ds,esi,edi>
        mov       ecx,FATBufferLength1      ; Number of bytes to copy
        mov       es,FATBufferSelector1     ; es:di -> target buffer
        xor       edi,edi                   ; ds:si -> source buffer
        xor       esi,esi
        mov       ds,FileReadBuffer
        FastRepMov  nosaveeax               ;copy

        DosContext      ds                  ;
        mov             es,FileReadBuffer   ;now clear out FileReadBuffer
        xor             edi,edi             ;
        mov             ecx,4000h           ;
        xor             eax,eax             ;
        rep             stosd               ;

        RestoreReg <edi,esi,ds,es>

        mov     cx,FATSectorCount2
        or      cx,cx
        jz      GetFAT_done                 ; No more sectors in FAT
        mov     ax,FATBufferSelector2
        or      ax,ax
        jz      GetFAT_done                 ; No selector allocated
        SaveReg <ds>
        mov     ds,FileReadBuffer
        assume ds:nothing
        xor     si,si
        CALLFAR VirtToPhys                  ; ax:bx = physical address
        .panic  <c>,<SIFS: GetFAT: can not get address of second FAT buffer>
        RestoreReg <ds>
        assume ds:DOSGROUP
        test    ax,0FFF0h                       ;check for low memory
        .panic  <nz>,<SIFS: GetFAT: Second FAT buffer is above the 1M boundary>
        mov     FileBufferAddress.msw,ax
        mov     FileBufferAddress.lsw,bx
        mov     ax,FATBufferLength2.msw
        mov     FileBufferLength.msw,ax
        mov     ax,FATBufferLength2.lsw
        mov     FileBufferLength.lsw,ax
        mov     ax,FATSectorBase
        xor     dx,dx
        add     ax,FATSectorCount
        adc     dx,0
        call    SYIReadSectors  ; Read second part of the FAT

        SaveReg   <es,ds,edi,esi,ecx>
        mov       ecx,FATBufferLength2      ; Number of bytes to copy
        mov       es,FATBufferSelector2     ; es:di -> target buffer
        xor       edi,edi                   ; ds:si -> source buffer
        xor       esi,esi
        mov       ds,FileReadBuffer
        FastRepMov  nosaveeax               ;copy

        DosContext      ds                  ;
        mov             es,FileReadBuffer   ;now clear out FileReadBuffer
        xor             edi,edi             ;
        mov             ecx,4000h           ;
        xor             eax,eax             ;
        rep             stosd               ;

        RestoreReg <ecx,esi,edi,ds,es>

GetFAT_done:
    ret
EndProc GetFAT


;
; SUBROUTINE NAME:      GetNextCluster
;
; DESCRIPTIVE NAME:     Get the next cluster number
;
; FUNCTION:     Gets the next cluster in the cluster chain.
;
; NOTES:        none
;
; ENTRY POINT:  GetNextCluster
;    LINKAGE:   call (near, protect mode)
;
; INPUT:        ax = current cluster number
;
; EXIT-NORMAL:  ax = next cluster number
;
; EXIT-ERROR:   none
;
; EFFECTS:      none
;
; INTERNAL REFERENCES:
;    ROUTINES:  none
;
; EXTERNAL REFERENCES:
;    ROUTINES:  none
;
; Pseudo Code:
;       IF the FAT has 12-bit entries
;         Get the next 12-bit entry
;       ELSE
;         Get the next 16-bit entry
;       ENDIF
;       Return
;

Procedure GetNextCluster,near,local
    assume ds:DOSGROUP,es:nothing,fs:nothing,gs:nothing,ss:nothing
SaveReg         <dx,si,es>              ;save registers
mov             es,FATBufferSelector1   ;es:si -> FAT
.if             <FATEntrySize eq 12>
  imul            ax,3                  ;ax = cluster number * 3
  rcr             ax,1                  ;ax.c = cluster number * 1.5
  mov             si,ax                 ;es:si -> FAT entry
  mov             ax,es:[si]            ;ax = FAT entry
  .if             <c>
    shr             ax,4                ;get bits 15-4
  .endif
  and             ax,0FFFh              ;mask off unused bits
.else
  xor             dx,dx
  sal             ax,1
  adc             dx,0                  ;dx:ax = cluster number * 2
  or              dx,dx
  jz              gnc2                  ; We have the correct FAT buffer
  mov             es,FATBufferSelector2 ; Entry is in second FAT buffer
gnc2:
  mov             si,ax                 ;es:si -> FAT entry
  mov             ax,es:[si]            ;ax = FAT entry
.endif
RestoreReg      <es,si,dx>              ;restore registers
ret
EndProc GetNextCluster


;
; SUBROUTINE NAME:      syiInitSIFS
;
; DESCRIPTIVE NAME:     Initialize SysInit File System
;
; FUNCTION:     Initialize the mini file system so SysInit can read files
;               from the root directory of the boot media.
;
; NOTES:        none
;
; ENTRY POINT:  syiInitSIFS in DOSCODE
;    LINKAGE:   call (hybrid, protect mode)
;
; INPUT:        al = boot drive number
;
; EXIT-NORMAL:  FileOpenFlag = false
;
; EXIT-ERROR:   Panic - can not allocate needed memory
;               Abort - MFS_INIT returned an error
;
; EFFECTS:      no registers preserved
;
; INTERNAL REFERENCES:
;    ROUTINES:  GetBPB
;               GetDir
;               GetFAT
;
; EXTERNAL REFERENCES:
;    ROUTINES:  SegAlloc
;               VirtToPhys
;               SYIAbort
;
; Pseudo Code:
;       IF available flag true
;         Panic - invalid initialization
;       ENDIF
;       Allocate readbuffer
;       If Fat System or Mini FSD uses DOVOLIO Function then
;         Force resetting disk/diskette subsystem on next call to ReadHTS
;         Allocate sector buffer
;         Get the BPB (call GetBPB)
;         Calculate disk conversion factors
;       If Fat System
;         Calculate base sector number and size of FAT
;         Calculate base sector number and size of root directory
;         Calculate base sector number of files
;         Calculate size of FAT, directory and sector buffers
;         Get memory for them (call SegAlloc)
;         IF error Panic - can not allocate needed memory
;         Get the physical address of that memory (call VirtToPhys)
;         Store
;         Read FAT (call GetFAT)
;         Read directory (call GetDir)
;         Set available flag true
;       Else
;         Call MFS_INIT
;       Return
;

Procedure syiInitSIFS,hybrid
    assume ds:nothing,es:nothing,fs:nothing,gs:nothing,ss:nothing
SaveReg         <ax,bx,cx,dx,si,di,bp,ds,es>    ;save registers
DosContext      ds
.panic          <SIFSAvailableFlag ne 0>,<SIFS: Init: invalid initialization>

mov             al,SIFSNumInits
inc             al
mov             SIFSNumInits,al

mov             ax,1                            ;ax:bx = size of buffer
xor             bx,bx
mov             ch,D_DATA0                      ;cx = attributes
mov             cl,SA_GDT                       ;cl = table to use
mov             si,SIFS_SEG_FLAGS               ;si = physical attributes
mov             di,INITOWNER                    ;di = owner
SaveReg         <ds>
CALLFAR         SegAlloc                        ;destroys everything!
RestoreReg      <ds>
.panic          <c>,<SIFS: Init: can not allocate memory for tmp file>
mov             FileReadBuffer,bx                   ;returns bx = selector
.if             <bit mFSD_FLAG nand 01h> near
  mov             ResetSubsystemFlag,-1           ;force reseting subsystem
  ; get the media parameters
  call            GetBPB                          ;read in the BPB
  ; calculate conversion factors
  mov             ax,es:[bx].BPB_BytesPerSector   ;check BytesPerSector
  .panic          <ax ne BytesPerSector>,<SIFS: Init: media not 512 bytes per sector>
  mov             al,es:[bx].BPB_SectorsPerCluster ;set SectorsPerCluster
  xor             ah,ah
  mov             SectorsPerCluster,ax
  mul             BytesPerSector
  mov             BytesPerCluster,ax
  mov             ax,es:[bx].BPB_Heads            ;set HeadCount
  .panic          <ah ne 0>,<SIFS: Init: too many heads>
  mov             HeadCount,al
  mov             ax,es:[bx].BPB_SectorsPerTrack  ;set SectorsPerTrack
  .panic          <ah ne 0>,<SIFS: Init: too many sectors per track>
  mov             SectorsPerTrack,al
  mul             HeadCount                       ;set SectorsPerCylinder
  mov             SectorsPerCylinder,ax
  mov             dx,es:[bx].BPB_HiddenSectors.msw ;set PartitionBase
  mov             ax,es:[bx].BPB_HiddenSectors.lsw
  div             SectorsPerCylinder              ;ax = cylinder, dx = sector
  ;; .panic          <o>,<SIFS: Init: number of hidden sectors too large>
  mov             PartitionBase.cylinder,ax
  mov             PartitionBase.sector,dx
.endif

.if             <mFSD_FLAG eq FALSE>    near    .then   ;If FAT System
  SaveReg <bx>
  xor             bx,bx
  mov             cx,BootBPB.BPB_TotalSectors
  ; Make sure that we have the correct total sectors for the disk
  .if             <cx e 0>
      mov         cx,word ptr BootBPB.BPB_BigTotalSectors
      mov         bx,word ptr BootBPB.BPB_BigTotalSectors+2
  .endif
  ; BX:CX = TS
  sub             cx,BootBPB.BPB_ReservedSectors
  sbb             bx,0                            ;bx:cx = TS-RS
  mov             al,BootBPB.BPB_NumberOfFATs     ;ax = CF
  xor             ah,ah
  mul             BootBPB.BPB_SectorsPerFAT       ;dx:ax = CF*SPF
  .panic          <c>,<SIFS: Init: too many FAT sectors>
  sub             cx,ax
  sbb             bx,dx                           ;bx:cx = TS-RS-(CF*SPF)
  mov             ax,BootBPB.BPB_RootEntries      ;ax = D
  mov             dx,size dir_entry               ;dx = BPD
  mul             dx                              ;dx:ax = D*BPD
  div             BootBPB.BPB_BytesPerSector      ;ax = D*BPD/BPS
  .panic          <dx ne 0>,<SIFS: Init: uneven number of root directory sectors>
  sub             cx,ax
  sbb             bx,0                            ;bx:cx = TS-RS-(CF*SPF)-(D*BPD/BPS)
  mov             ax,cx
  mov             dx,bx                           ;dx:ax = TS-RS-(CF*SPF)-(D*BPD/BPS)
  RestoreReg <bx>
  mov             cl,BootBPB.BPB_SectorsPerCluster ;cx = SPC
  xor             ch,ch
  .panic          <dx ae cx>,<SIFS: Init: Too many clusters>
  div             cx                              ;ax = (TS-RS-(CF*SPF)-(D*BPD/BPS))/SPC
  mov             FATEntrySize,12                 ;assume 12-bit FAT
  .if             <ax ae 4096-10-1>               ;was assumption correct?
    mov             FATEntrySize,16                 ;no - make it a 16-bit FAT
  .endif
  mov             ax,es:[bx].BPB_RootEntries      ;set DirEntryCount
  mov             DirEntryCount,ax
  ; calculate bases and counts
  mov             ax,es:[bx].BPB_ReservedSectors  ;set FATSectorBase
  mov             FATSectorBase,ax
  mov             ax,es:[bx].BPB_SectorsPerFAT    ;set FATSectorCount
  mov             FATSectorCount,ax
  mov             dl,es:[bx].BPB_NumberOfFATs        ;set DirSectorBase
  xor             dh,dh
  mul             dx
  .panic          <c>,<SIFS: Init: too many sectors in FAT or too many FATs>
  add             ax,FATSectorBase
  .panic          <c>,<SIFS: Init: base sector for root directory too large>
  mov             DirSectorBase,ax
  mov             ax,BytesPerSector               ;set DirSectorCount
  div             DirEntrySize                    ;al = entries/sector
  ;; .panic          <o>,<SIFS: Init: too many directory entries per sector>
  mov             dl,al                           ;dl = entries/sector
  mov             ax,DirEntryCount                ;ax = entries/dir
  div             dl                              ;al = sectors/dir, ah = remainder
  ;; .panic          <o>,<SIFS: Init: too many sectors in root directory>
  .if             <ah ne 0>                       ;if partial sector
    xor           ah,ah                             ;bump sectors/dir
    inc           ax
  .endif
  mov             DirSectorCount,ax
  add             ax,DirSectorBase                ;set ClusterSectorBase
  .panic          <c>,<SIFS: Init: base sector for data area too large>
  mov             ClusterSectorBase,ax
  ; allocate memory for the FAT buffer
  mov             dx,PartitionBase.sector
  mov             ax,FATSectorCount               ;? for the FAT buffer
  mul             BytesPerSector                  ;dx:ax = size of buffer
  ; Number of bytes in FAT can be up to 128K (i.e. 64K FAT entries)
  .if             <dx a 2> or                     ;If the FAT >128 kbytes
  .if             eq and
  .if             <nonzero ax>
    .panic          <SIFS: Init: too many sectors in the FAT>
  .endif

  .if             <dx a 1> or                     ;If the FAT >64 kbytes
  .if             eq and
  .if             <nonzero ax>
    dec             dx                            ;Calculate size of second buffer
    mov             FATBufferLength2.lsw,ax       ; in bytes
    mov             FATBufferLength2.msw,dx
    div             BytesPerSector                ;Calculate size of second buffer
                                                  ; in sectors
                                                  ;if overflow, then a Trap 0 occurs.
    .panic          <nonzero dx>,<SIFS: Init: Buffer size not a multiple of sector size>
    mov             FATSectorCount2,ax
    mov             FATBufferLength1.lsw,0        ;First buffer is 64 kbytes
    mov             FATBufferLength1.msw,1
    sub             FATSectorCount,ax             ;Adjust Total sector count to
                                                  ; the size of the first buffer
    .panic          <c>,<SIFS: Init: FatSectorCount(s) corrupted>
  .else                                         ;Else the Fat <64 kbytes
    mov             FATBufferLength1.lsw,ax       ;Save the first buffer size
    mov             FATBufferLength1.msw,dx
    mov             FATBufferLength2.lsw,0        ;The second buffer is empty
    mov             FATBufferLength2.msw,0
    mov             FATSectorCount2,0             ;The second buffer is empty
  .endif

  ;Allocate memory for the buffers

  mov             bx,FATBufferLength1.lsw
  mov             ax,FATBufferLength1.msw
  mov             ch,D_DATA0                      ;cx = attributes
  mov             cl,SA_GDT                       ;cl = table to use
  mov             si,SIFS_HISEG_FLAGS             ;si = physical attributes
  mov             di,INITOWNER                    ;di = owner
  SaveReg         <ds>
  CALLFAR         SegAlloc                        ;destroys everything!
  RestoreReg      <ds>
  .panic          <c>,<SIFS: Init: can not allocate memory for FAT buffer>
  mov             FATBufferSelector1,bx           ;returns bx = selector
  ; Allocate memory for second FAT buffer if necessary
  mov             ax,FATSectorCount2              ;? for the FAT buffer
  or              ax,ax
  jz              no_sec_FAT                      ; No second buffer to alloc

  mov             bx,FATBufferLength2.lsw
  mov             ax,FATBufferLength2.msw
  mov             ch,D_DATA0                      ;cx = attributes
  mov             cl,SA_GDT                       ;cl = table to use
  mov             si,SIFS_HISEG_FLAGS             ;si = physical attributes
  mov             di,INITOWNER                    ;di = owner
  SaveReg         <ds>
  CALLFAR         SegAlloc                        ;destroys everything!
  RestoreReg      <ds>
  .panic          <c>,<SIFS: Init: can not allocate memory for FAT buffer>
  mov             FATBufferSelector2,bx           ;returns bx = selector
  no_sec_FAT:
  ; read in fat
  call            GetFAT                          ;read in the FAT
  ; allocate memory for the directory buffer
  mov             ax,DirSectorCount               ;? for the directory buffer
  mul             BytesPerSector                  ;dx:ax = size of buffer
  .panic          <c>,<SIFS: Init: too many sectors in the root directory>
  mov             DirBufferLength,ax
  mov             bx,ax                           ;ax:bx = size of buffer
  mov             ax,dx
  mov             ch,D_DATA0                      ;cx = attributes
  mov             cl,SA_GDT                       ;cl = table to use
  mov             si,SIFS_HISEG_FLAGS             ;si = physical attributes
  mov             di,INITOWNER                    ;di = owner
  SaveReg         <ds>
  CALLFAR         SegAlloc                        ;destroys everything!
  RestoreReg      <ds>
  .panic          <c>,<SIFS: Init: can not allocate memory for directory buffer>
  mov             DirBufferSelector,bx            ;returns bx = selector
  ; read in directory
  call            GetDir                          ;read in the directory
  mov             SIFSAvailableFlag,-1            ;make SIFS available

  ;====Start of check for OS2 subdirectory====================================
  ;### DCR 403 ###
  ;### Processing for reading in the \OS2 directory
  ;### Find OS2 dir in the root

   mov      FileOpenFlag,FALSE      ;clear open flag
   mov      es,DirBufferSelector    ;es:di -> first directory entry
   xor      di, di                  ;start at first entry in directory
   mov      cx,DirEntryCount        ;load counter
;; We decrement before checking if zero, so no need to decrement here.
;; dec      cx                      ;Account for starting at actual 1st
;;                                  ;dir entry
   lea      si,OS2NameBuffer        ;ds:si -> OS2 dir name

   .repeat
      .if <BIT es:[di].dir_attr and attr_directory> near ;if entry is a directory
        SaveReg   <cx>                    ;save count
        mov       cx,11                   ;check for matching entry
        SaveReg   <si,di>
        repe      cmpsb
        RestoreReg<di,si>
        .if       <eq> near

             mov        FileOpenFlag,TRUE               ;set open flag

; allocate memory for the OS2 directory buffer
             mov        ax,es:[di].dir_firstfile        ;get first cluster
             mov        FileClusterBase,ax
; The dir structure returns a 0 filesize for a directory
; Since the largest file that can be read is 64K with SYIReadFile
; the size of the OS/2 dir will be set to ffffh
             mov        TempDirSize,0FFFFh             ; 64K max for SYIReadfile
sis_1alloc:
             sub        ax, ax
             mov        FileSize.msw,ax
             mov        bx, TempDirSize
             mov        FileSize.lsw,bx
             mov        cx,D_DATA0*256+SA_GDT           ;cx = attributes
             mov        si,SIFS_SEG_FLAGS               ;si = physical attributes
             mov        di,INITOWNER                    ;di = owner
             SaveReg    <ds>
             CALLFAR    SegAlloc                        ;destroys everything!
             RestoreReg <ds>
             .if        <c>                             ;failed?
                mov     ax, TempDirSize                 ;try 1K less
                sub     ax, 1000H
                mov     TempDirSize,ax
                cmp     ax, 7FFFH                       ;can't get 32K?
                jae     sis_1alloc                      ; if not, panic
                .panic <SIFS: Init: can not allocate memory for OS2 directory buffer>
             .endif
             mov        OS2AVAIL,1                      ;OS2 available for Openfile
             mov        OS2DirBufferSelector,bx         ;returns bx = selector
             mov        dx,FileSize.msw
             mov        ax,FileSize.lsw
             mov        ax,bx
             xor        bx,bx
             SaveReg    <cx,dx>
             xor        cx,cx
             xor        dx,dx
; read in OS2 directory
             call       SYIReadFile
             RestoreReg <dx,cx>
;Find # of OS2 entries and size
             mov        es,OS2DirBufferSelector    ;es:di -> first OS2 directory entry
             xor        di,di                      ;get 1st dir entry
             lea        si,EndNameBuffer           ;ds:si -> OS2 dir name
             mov        ax,0
             mov        bx,0
             SaveReg    <bp>
             mov        bp,TempDirSize
             sub        bp,11
             .while     <zero bx>                  ;Loop to find null entry
               inc        ax
               mov        cx,11                    ;check for matching entry
               SaveReg    <si,di>
               repe       cmpsb
               RestoreReg <di,si>                 ;If null entry end of chain
               .if        <eq>
                  dec       ax
                  mov       OS2DirEntryCount,ax
                  mov       bx,1
               .endif
               .if <di a bp>               ;not last entry, end of segment?
                  .panic <SIFS: Init: OS2 Dir too big for segment>
               .endif
               add         di,word ptr DirEntrySize  ;es:di -> next entry
             .endwhile
             RestoreReg <bp>
; Allocate segment with proper OS2 size
; (Don't just Realloc because of fragmentation.  In some cases we don't have
;  another 64K block of contiguous low memory for the OS2BOOT subdirectory)
             mov     ax,OS2DirEntryCount
             mul     DirEntrySize
             mov     bx,ax
             SaveReg <ds,ax,bx,cx,dx,di,si>

             push       bx                       ;save size on stack
             sub        ax, ax                   ;ax:bx = size
             mov        FileSize.lsw,bx
             mov        cx,D_DATA0*256+SA_GDT    ;cx = attributes
             mov        si,SIFS_HISEG_FLAGS      ;si = physical attributes
             mov        di,INITOWNER             ;di = owner
             SaveReg    <ds>
             CALLFAR    SegAlloc                 ;destroys everything!
             RestoreReg <ds>
             mov       ecx,0
             pop       cx                        ;get size off stack
             .if    nc
                SaveReg   <es,ds,esi,edi>
                mov       es,bx                    ;es:di ->new memory area
                xor       edi,edi                  ;ds:si ->old memory area
                xor       esi,esi
                mov       ds,OS2DirBufferSelector
                FastRepMov  nosaveeax               ;copy

                DosContext ds                  ;
                mov        es,FileReadBuffer   ;now clear out FileReadBuffer
                xor        edi,edi             ;
                mov        ecx,4000h           ;
                xor        eax,eax             ;
                rep        stosd               ;

                RestoreReg <edi,esi,ds,es>

                mov        ax,OS2DirBufferSelector    ;free the directory buffer
                mov        OS2DirBufferSelector,bx   ;new OS2DIR selector
                CALLFAR    SegFree
                .panic     <c>,<SIFS: Term: can not free memory for directory buffer>
                DosContext ds
             .endif

            RestoreReg <si,di,dx,cx,bx,ax,ds>
            mov       es,OS2DirBufferSelector

        .endif
        RestoreReg      <cx>                                 ;restore count
      .endif
   .until          <FileOpenFlag ne FALSE> or
      add             di,word ptr DirEntrySize             ;es:di -> next entry
      dec             cx
   .until          <cxz>   near
    mov             FileOpenFlag,FALSE                     ;set open flag

   ;======End of check for OS2 subdirectory====================================

   ;====Start of check for BOOT subdirectory================================
   ;### Processing for reading in the \OS2\BOOT directory
   ;### Find BOOT dir in the OS2 dir

   .if <OS2AVAIL eq 1> NEAR
      mov     FileOpenFlag,FALSE      ;clear open flag
      mov     es,OS2DirBufferSelector ;es:di -> first OS2 dir entry
      xor     di, di                  ;start at first entry in dir
      mov     cx,OS2DirEntryCount     ;load counter
;;    We decrement before checking if zero, so no need to decrement here.
;;    dec      cx                     ;Account for starting at actual 1st
;;                                    ;dir entry
      lea     si,OS2BOOTNameBuffer    ;ds:si -> BOOT dir name

      .repeat
         .if <BIT es:[di].dir_attr and attr_directory> near ;if entry is a directory
           SaveReg    <cx>                    ;save count
           mov        cx,11                   ;check for matching entry
           SaveReg    <si,di>
           repe       cmpsb
           RestoreReg <di,si>
           .if        <eq> near

                mov    FileOpenFlag,TRUE               ;set open flag

   ; allocate memory for the BOOT directory buffer
                mov    ax,es:[di].dir_firstfile        ;get first cluster
                mov    FileClusterBase,ax
   ; The dir structure returns a 0 filesize for a directory
   ; Since the largest file that can be read is 64K with SYIReadFile
   ; the size of the OS/2 dir will be set to ffffh
                mov        TempDirSize,0FFFFh         ; 64K max for SYIReadfile
sis_3alloc:
                sub    ax, ax
                mov    FileSize.msw,ax
                mov    bx, TempDirSize
                mov    FileSize.lsw,bx
                mov    cx,D_DATA0*256+SA_GDT           ;cx = attributes
                mov    si,SIFS_HISEG_FLAGS             ;si = physical attributes
                mov    di,INITOWNER                    ;di = owner
                SaveReg    <ds>
                CALLFAR    SegAlloc                    ;destroys everything!
                RestoreReg <ds>
                .if        <c>                         ;failed?
                   mov     ax, TempDirSize             ;try 1K less
                   sub     ax, 1000H
                   mov     TempDirSize,ax
                   cmp     ax, 7FFFH                   ;can't get 32K?
                   jae     sis_3alloc                  ; if not, panic
                   .panic <SIFS: Init: can not allocate memory for OS2\BOOT directory buffer>
                .endif
                mov        OS2BOOTAVAIL,1                ;BOOT available for Openfile
                mov        OS2BOOTDirBufferSelector,bx   ;returns bx = selector
                mov        dx,FileSize.msw
                mov        ax,FileSize.lsw
                mov        ax,FileReadBuffer
                xor        bx,bx
                SaveReg    <cx,dx>
                xor        cx,cx
                xor        dx,dx
   ; read in OS2\BOOT directory
                push       ds
                call       SYIReadFile
                pop        ds
                SaveReg    <ds,es,edi,esi>
                movzx      ecx,TempDirSize
                mov        es,OS2BOOTDirBufferSelector
                mov        ds,FileReadBuffer
                xor        esi,esi
                xor        edi,edi
                FastRepMov

                DosContext ds                  ;
                mov        es,FileReadBuffer   ;now clear out FileReadBuffer
                xor        edi,edi             ;
                mov        ecx,4000h           ;
                xor        eax,eax             ;
                rep        stosd               ;

                RestoreReg <esi,edi,es,ds>
                RestoreReg <dx,cx>
   ;Find # of OS2\BOOT entries and size
                mov        es,OS2BOOTDirBufferSelector;es:di -> first BOOT directory entry
                xor        di,di                      ;get 1st dir entry
                lea        si,EndNameBuffer           ;ds:si -> BOOT dir name
                mov        ax,0
                mov        bx,0
                SaveReg    <bp>
                mov        bp,TempDirSize
                sub        bp,11
                .while     <zero bx>                  ;Loop to find null entry
                  inc        ax
                  mov        cx,11                    ;check for matching entry
                  SaveReg    <si,di>
                  repe       cmpsb
                  RestoreReg <di,si>                  ;If null entry end of chain
                  .if        <eq>
                     dec   ax
                     mov   OS2BOOTDirEntryCount,ax
                     mov   bx,1
                  .endif
                  .if <di a bp>               ;not last entry, end of segment?
                     .panic <SIFS: Init: OS2 Dir too big for segment>
                  .endif
                  add     di,word ptr DirEntrySize    ;es:di -> next entry
                .endwhile
                RestoreReg <bp>
   ; Reallocate segment with proper OS2\BOOT size
                mov     ax,OS2BOOTDirEntryCount
                mul     DirEntrySize
                mov     bx,ax
                SaveReg <ds,es,ax,bx,cx,dx,di,si>
                mov     di,OS2BOOTDirBufferSelector
                mov     ds,di
                xor     dx,dx
                xor     ax,ax
                CALLFAR SegRealloc
               .if     c
                  InternalError <syiInitSIFS SegRealloc failed>
               .endif
               RestoreReg <si,di,dx,cx,bx,ax,es,ds>
           .endif
           RestoreReg      <cx>                                 ;restore count
         .endif
      .until          <FileOpenFlag ne FALSE> or
         add             di,word ptr DirEntrySize             ;es:di -> next entry
         dec             cx
      .until          <cxz>   near
       mov             FileOpenFlag,FALSE                     ;set open flag
   .endif
   ;======End of check for BOOT subdirectory================================

.else                                           ;Mini-FSD
 mov      MFSD_Stage,1                          ;set stage to 1 for Bootable
  ; Call the init routine for this mini-FSD.
  push    VectorRIPL.msw
  push    VectorRIPL.lsw
  mov     VectorRIPL.msw,0
  mov     VectorRIPL.lsw,0
  push    DOSGROUP
  push    offset NumIORipl              ; NumIORipl = # of remote drives (CDB)
  push    DOSGROUP
  push    offset VectorRIPL
  push    es
  push    bx
  push    ds
  lea     ax,ds:pMiniFSD
  push    ax
  DosInitContext ds
  mov     si,offset DOSINITDATA:mfscInitTemplate
  push    DOSGROUP                               ; segment
  push    offset DOSGROUP:DumpProc               ; Offset to dump address
  call    DWORD ptr ds:[si].MFS_INIT
  .if     <nonzero ax>          ; did the init fail?
    lea   si,tbl_mFSD_failure_2   ; Yes, handle the failure
    call  SYIAbort
  .endif
.endif

RestoreReg      <es,ds,bp,di,si,dx,cx,bx,ax>    ;restore registers
ret
EndProc syiInitSIFS


;
; SUBROUTINE NAME:      SYIOpenFile
;
; DESCRIPTIVE NAME:     Open File via SysInit File System
;
; FUNCTION:     Establish access information for a subsequent read.
;
; NOTES:        The file name is passed as an ASCIIZ string. It may contain a
;               device and path, but they will be ignored! ALL FILES, for the
;               time being, ARE ASSUMED TO BE IN THE ROOT DIRECTORY OF THE BOOT
;               DRIVE.
;
; ENTRY POINT:  SYIOpenFile in DOSCODE
;    LINKAGE:   call (hybrid, protect mode)
;
; INPUT:        es:di -> filespec:ASCIIZ
;
; EXIT-NORMAL:  c-flag = 0 => file found
;               ax:bx = file size
;               FileOpenFlag = true
;
; EXIT-ERROR:   c-flag = 1 => file not found or drive or path specified
;               FileOpenFlag = false
;
; EFFECTS:      none
;
; INTERNAL REFERENCES:
;    ROUTINES:  ParseFilespec
;               DriveCheck
;
; EXTERNAL REFERENCES:
;    ROUTINES:  MFS_Open
;
; Pseudo Code:
;       Clear openflag
;       If drive not specified then
;         If mini-FSD then
;           call MFS_OPEN
;           If no error then
;             move FileSize to ax:bx
;             set openflag
;             clear cary
;           else (error)
;             set cary
;         else (useFAT)
;          IF available flag false then
;            Panic - SIFS not unavailable
;          Parse filename from filespec (call ParseFilespec)
;          If no error
;            Init pointer to first directory entry
;            REPEAT
;              Compare directory entry to filename
;              IF match
;                Set FileClusterBase to file's starting cluster number
;                Set FileSize to file's size
;                Set FileOpenFlag to true
;              ELSE
;                Next entry
;            UNTIL match OR no more entries
;       Return
;

Procedure SYIOpenFile,<hybrid,far16>
    assume ds:nothing,es:nothing,fs:nothing,gs:nothing,ss:nothing
SaveReg         <cx,edx,si,di,bp,ds,es>  ;save registers
DosContext      ds
mov             FileOpenFlag,FALSE      ;clear open flag
call            DriveCheck
.if             < nc> near  .then           ;ok, no drive letter specified
  DosContext      ds            ;ds:si -> filename buffer
  lea             si,FileNameBuffer
  .if     <mFSD_FLAG ne FALSE> NEAR              ;mini FSD present
     call ParseFilespec           ;parse the filespec
     .if          < nc>   NEAR            ;ok, no path specified
        DosInitContext ds,si
        mov   al,ConfigSysFilename[8]
        mov   si,offset ConfigSysFilename
        DosContext  ds
        ;check to see if we need to load the alternate CONFIG.SYS
        .if  <di eq si> AND
        .if  <zero al>
           push        di                      ;address
           push        es                      ;save buffer
           ;Set up to open file in the OS2\BOOT directory
           ; append file name to \OS2\OS2BOOT\
                                                 ; address of file name after parsefilespec
           pop         ds                        ; in es;di moved to ds:si
           pop         si
           DosContext      es
           lea         di,MfsdOS2BOOTNameBuffer ;Get address MfsdOS2BOOTNameBuffer
           add         di,10                    ;Advance past \OS2\BOOT\
           .repeat
             movsb                                ;to the MfsdOS2NameBuffer
           .until   <<byte ptr ds:[si]> eq 0>
           movsb
           push        es                         ;push file name address
           lea         di,MfsdOS2BOOTNameBuffer   ;Get address of file to open
           push        di
           push        es                         ;push address of file size
           lea         ax,FileSize
           push        ax
           DosInitContext      ds
           mov         si,offset DOSINITDATA:mfscInitTemplate
           call        DWORD ptr ds:[si].MFS_OPEN
           DosContext  ds
           .if         <zero ax>       .then
              mov       ax,FileSize.msw
              mov       bx,FileSize.lsw
              mov       FileOpenFlag,TRUE
              clc
           .else
              stc
           .endif
        .else NEAR
           push        di                      ;address
           push        es                      ;save buffer
           push        es                      ;push file name address
           push        di
           push        ds                      ;push address of file size
           lea         ax,FileSize
           push        ax
           DosInitContext      ds
           mov         si,offset DOSINITDATA:mfscInitTemplate
           call        DWORD ptr ds:[si].MFS_OPEN
           DosContext  ds
           .if         <ax eq 0>       .then
              pop       es
              pop       di
              mov       ax,FileSize.msw
              mov       bx,FileSize.lsw
              mov       FileOpenFlag,TRUE
              clc
           .else  NEAR ; Failed to open in the root, try OS2 directory

              ;### DCR 403 ###
              ;Set up to open file in the OS2 directory
              ; append file name to \OS2\
                                                    ; address of file name after parsefilespec
              pop         ds                        ; in es;di moved to ds:si
              pop         si
              push        si                        ; Put address back on stack
              push        ds                        ; in case we need to go to
              DosContext      es                    ; OS2 directory
              lea         di,MfsdOS2NameBuffer      ;Get address MfsdOS2NameBuffer
              add         di,5                       ;Advance past \OS2\
              .repeat
                movsb                                ;to the MfsdOS2NameBuffer
              .until   <<byte ptr ds:[si]> eq 0>
              movsb
              push        es                         ;push file name address
              lea         di,MfsdOS2NameBuffer       ;Get address of file to open
              push        di
              push        es                         ;push address of file size
              lea         ax,FileSize
              push        ax
              DosInitContext      ds
              mov         si,offset DOSINITDATA:mfscInitTemplate
              call        DWORD ptr ds:[si].MFS_OPEN
              DosContext  ds
              .if         <zero ax>       .then
                 pop       ax                     ; Clear extra address off
                 pop       ax                     ; stack
                 mov       ax,FileSize.msw
                 mov       bx,FileSize.lsw
                 mov       FileOpenFlag,TRUE
                 clc
              ;### DCR 403 ###
              .else  ; Failed to open in the OS2 directory, try OS2\BOOT

                 ;Set up to open file in the OS2BOOT directory
                 ; append file name to \OS2\BOOT\
                                                       ; address of file name after parsefilespec
                 pop         ds                        ; in es;di moved to ds:si
                 pop         si
                 DosContext      es
                 lea         di,MfsdOS2BOOTNameBuffer  ;Get address MfsdOS2BOOTNameBuffer
                 add         di,10                      ;Advance past \OS2\BOOT\
                 .repeat
                   movsb                                ;to the MfsdOS2BOOTNameBuffer
                 .until   <<byte ptr ds:[si]> eq 0>
                 movsb
                 push        es                         ;push file name address
                 lea         di,MfsdOS2BOOTNameBuffer   ;Get address of file to open
                 push        di
                 push        es                         ;push address of file size
                 lea         ax,FileSize
                 push        ax
                 DosInitContext      ds
                 mov         si,offset DOSINITDATA:mfscInitTemplate
                 call        DWORD ptr ds:[si].MFS_OPEN
                 DosContext  ds
                 .if         <zero ax>       .then
                    mov       ax,FileSize.msw
                    mov       bx,FileSize.lsw
                    mov       FileOpenFlag,TRUE
                    clc
                 .else
                    stc
                 .endif
              .endif

           .endif
        .endif
     .endif
  .else    near                         ;no mini FSD
    .panic      <SIFSAvailableFlag eq 0>,<SIFS: OpenFile: SIFS not available>
    call        ParseFilespec           ;parse the filespec
    .if         < nc>   NEAR            ;ok, no path specified
       DosContext  ds

       xor     dx,dx                   ;dx = 0 for root
       mov     es,DirBufferSelector    ;es:di -> first directory entry
       xor     di,di                   ;bias di for name field
       mov     cx,DirEntryCount        ;load counter

    ;dx = 0 for root       (default)
    ;dx = 1 for \OS2       (OS2 should be second for compatibility)
    ;dx = 2 for \OS2\BOOT
    ;dx = -1 for found

   ;If file is not in the root jump here to begin searching the next dir
OS2DIR:
       .repeat
         SaveReg    <cx>                    ;save count
         mov        cx,11                   ;check for matching entry
         SaveReg    <si,di>
         repe       cmpsb
         RestoreReg <di,si>
         .if        <eq>
           mov        FileOpenFlag,TRUE       ;set open flag
           mov        ax,es:[di].dir_firstfile    ;get first cluster
           mov        FileClusterBase,ax
           mov        StartFileClusterBase,ax
           mov        ax,es:[di].dir_size_h   ;get file size
           mov        FileSize.msw,ax
           mov        bx,es:[di].dir_size_l
           mov        FileSize.lsw,bx
           mov        dx,-1                 ; Flag found.
         .endif
         RestoreReg <cx>                    ;restore count
       .until     <FileOpenFlag ne FALSE> or
         add        di,word ptr DirEntrySize ;es:di -> next entry
         dec        cx
         stc                                ;possible file not found
       .until     <cxz>
       ; If the file is not found in the root directory (dx = 0)
       ; then set up for scanning the OS2 directory for entry

       ; If the file is not found in the OS2 directory (dx = 1)
       ; then set up for scanning the OS2\BOOT directory for entry

       .if      <zero dx> and
       .if      <OS2AVAIL ne 0>
         inc    dx
         mov    es,OS2DirBufferSelector ;es:di -> first OS2 directory entry
         xor    di,di                   ;bias di for name field
         mov    cx,OS2DirEntryCount     ;load counter
         jmp    OS2DIR
       .elseif   <zero dx>
         inc    dx
       .endif

       .if      <dx eq 1> and
       .if      <OS2BOOTAVAIL ne 0>
         inc    dx
         mov    es,OS2BOOTDirBufferSelector ;es:di -> first OS2\BOOT directory entry
         xor    di,di                   ;bias di for name field
         mov    cx,OS2BOOTDirEntryCount     ;load counter
         jmp    OS2DIR
       .elseif <dx eq 1>
         inc    dx
       .endif

       .if      <FileOpenFlag eq FALSE>   ;if file not opened,
         stc                              ;make sure carry bit is set
       .endif                               ;path specified, error
     .endif
  .endif                                 ;end of else for no mini-fsd
.endif                                   ;drive letter specified, error
.if      <FileOpenFlag eq FALSE>   ;if file not opened,
   stc                              ;make sure carry bit is set
.else
   xor        edx,edx               ;initialize cache parameters
   mov        CacheStartByte,edx
   mov        CacheByteSize,edx
   clc
.endif                               ;path specified, error
RestoreReg      <es,ds,bp,di,si,edx,cx>  ;restore registers
Ret
EndProc SYIOpenFile


;
; SUBROUTINE NAME:      ParseFilespec
;
; DESCRIPTIVE NAME:     Parse Filespec
;
; FUNCTION:     Parse a file name and extension form a filespec.
;
; NOTES:        none
;
; ENTRY POINT:  ParseFilespec
;    LINKAGE:   call (near)
;
; INPUT:        es:di -> filespec
;
; EXIT-NORMAL:  cary clear
;
; EXIT-ERROR:   cary set  = path specified
;
; EFFECTS:      none
;
; INTERNAL REFERENCES:
;    ROUTINES:  none
;
; EXTERNAL REFERENCES:
;    ROUTINES:  none
;
; Pseudo Code:
;       Scan for path
;       If path doesn't exist then
;         Fill FileNameBuffer with spaces
;         Copy first 8 characters of name
;         Copy first 3 characters of extension if it exists
;         Convert lower case characters to upper case
;         Clear cary (no error)
;       Else
;         Set cary (error)
;       Return
;

Procedure ParseFilespec,near,local
    assume ds:nothing,es:nothing,fs:nothing,gs:nothing,ss:nothing
SaveReg         <ax,cx,si,di,bp,ds,es>  ;save registers
; find length of filespec
SaveReg         <di>            ;es:di -> filespec
mov             cx,-1           ;cx = count
mov             al,0            ;scan for <nul>
repne           scasb
inc             cx              ;account for starting at -1
neg             cx              ;cx = length of filespec
dec             cx              ;don't include the <nul> terminator
RestoreReg      <di>            ;es:di -> filespec
; return cary if path exists
mov             bp,di           ;save pointer and count
mov             bx,cx
mov             al,"\"          ;scan for "\"
repne           scasb
.if             <ne>            ;if not found
  mov             di,bp           ;restore pointer and count
  mov             cx,bx
  mov             al,"/"          ;scan for "/"
  repne           scasb
  .if             <ne>            ;if not found
    mov             di,bp           ;restore pointer and count
    mov             cx,bx
; set up ds:si and es:di for coping
    push            es          ;ds:si -> filespec
    pop             ds
    mov             si,di
    DosContext      es              ;es:di -> buffer
    lea             di,FileNameBuffer
    SaveReg         <di>            ;save pointer for case check
; fill buffer with spaces
    SaveReg         <cx,di>         ;save count and pointer
    mov             cx,11           ;cx = length of buffer
    mov             al,' '          ;fill with " "
    rep             stosb
    RestoreReg      <di,cx>         ;restore count and pointer
; copy first 8 character of name
    mov             ah,'.'          ;"." delimits the name
    .for            dl = 1 to 8     ;handle first 8 characters
      .if             <cx ne 0> and   ;if not end of string AND not end of name
      .if             <<byte ptr [si]> ne ah>
        movsb                           ;copy character
        dec             cx              ;simulate "rep"
      .else
        inc             di              ;copy nothing, just bump the pointer
      .endif
    .next           dl
; scan to "." if it exists
    .while          <cx ne 0> and
      lodsb                           ;skip over character
      dec           cx                ;simulate "rep"
    .while          <al ne ah>
    .endwhile
; copy first 3 character of extension if it exists
    .if             <cx a 3>
      mov             cx,3
    .endif
    rep             movsb
; convert lower case characters to upper case
    RestoreReg      di              ;es:di -> buffer
    mov             si,di           ;es:si -> buffer
    mov             cx,11
    .repeat
      lods            es:FileNameBuffer       ;get character (force ES override)
      .if             <al ae 'a'> and         ;if found lower case character
      .if             <al be 'z'>
        sub             al,'a'-'A'              ;convert to upper case
      .endif
      stosb                                   ;store the character
      dec             cx
    .until          <cxz>
    clc
  .else                                       ;/ found
    stc
  .endif
.else                                         ;\found
  stc
.endif
RestoreReg      <es,ds,bp,di,si,cx,ax>  ;restore registers
ret
EndProc ParseFilespec


;
; SUBROUTINE NAME:      DriveCheck
;
; DESCRIPTIVE NAME:     DriveCheck
;
; FUNCTION:     Check for a drive specification, move ptr if it exists
;
; NOTES:        none
;
; ENTRY POINT:  DriveCheck
;    LINKAGE:   call (near)
;
; INPUT:        es:di -> filespec
;
; EXIT-NORMAL:  cary clear
;
; EXIT-ERROR:
;
; EFFECTS:      none
;
; INTERNAL REFERENCES:
;    ROUTINES:  none
;
; EXTERNAL REFERENCES:
;    ROUTINES:  none
;
; Pseudo Code:
;       Scan for drive
;       If drive doesn't exist then
;         Clear cary (no error)
;       Else
;         update di
;       Return
;

Procedure DriveCheck,near,local
    assume ds:nothing,es:nothing,fs:nothing,gs:nothing,ss:nothing
SaveReg         <cx,ax>         ;save registers
; find length of filespec
SaveReg         <di>            ;es:di -> filespec
mov             cx,-1           ;cx = count
xor             ax,ax           ;scan for <nul>
repne           scasb
inc             cx              ;account for starting at -1
neg             cx              ;cx = length of filespec
dec             cx              ;don't include the <nul> terminator
RestoreReg      <di>            ;es:di -> filespec
push            di
mov             al,":"          ;search for drive
repne           scasb
pop             di
.if             <ne>            ;if not found, return good
  clc
.else                           ;drive found, return error
  stc
  mov           al, "\"
  .if           <es:[di+2] eq al>
    add         di,3
    clc
  .endif
.endif
RestoreReg      <ax,cx>
ret
EndProc DriveCheck

        assume  ds:DOSGROUP,es:nothing,ss:nothing

;
; SUBROUTINE NAME:      syiPreInitSIFS
;
; DESCRIPTIVE NAME:     PreInitialize SysInit File System
;
; FUNCTION:     Save the BPB that bios passed to us.
;
; NOTES:        none
;
; ENTRY POINT:  syiPreInitSIFS in DOSCODE
;    LINKAGE:   call (near, real mode)
;
; INPUT:        ds:si -> boot BPB
;               es = DOSGROUP
;
; EXIT-NORMAL:  nothing
;
; EXIT-ERROR:   none
;
; EFFECTS:      AX, CX, SI, DI, Flags
;
; INTERNAL REFERENCES:
;    ROUTINES:  none
;
; EXTERNAL REFERENCES:
;    ROUTINES:  none
;
; Pseudo Code:
;       Return
;

Procedure syiPreInitSIFS,near
    assume ds:nothing,es:DOSGROUP,fs:nothing,gs:nothing,ss:nothing
mov             al,[mFSD_FLAG]
test            al,01h                          ;if FAT System or
.if             z .then                         ;mFSD uses DOVOLIO
  mov             di,offset DOSGROUP:BootBPB
  mov             ecx,size a_BPB                  ;save BootBPB
  FastRepMov
.endif
ret
EndProc syiPreInitSIFS


;
; SUBROUTINE NAME:      ReadClusters
;
; DESCRIPTIVE NAME:     Read Clusters
;
; FUNCTION:     Read consecutive clusters from disk to memory. The specified
;               number of clusters or sufficient clusters to fill the buffer
;               (whichever comes first) are read.
;
; NOTES:        None
;
; ENTRY POINT:  ReadClusters
;    LINKAGE:   call (near)
;
; INPUT:        ax = starting cluster number
;               cx = number of clusters to read
;
; EXIT-NORMAL:  nothing
;
; EXIT-ERROR:   none
;
; EFFECTS:      none
;
; INTERNAL REFERENCES:
;    ROUTINES:  Cluster2Sector
;               ReadSectors
;
; EXTERNAL REFERENCES:
;    ROUTINES:  none
;
; Pseudo Code:
;       Calculate start sector (call Cluster2Sector)
;       SectorCount = ClusterCount * sectors per cluster
;       Read sectors (call ReadSectors)
;       Return
;

Procedure ReadClusters,near,local
    assume ds:DOSGROUP,es:nothing,fs:nothing,gs:nothing,ss:nothing
SaveReg         <ax,cx,dx>
call            Cluster2Sector          ;dx:ax = sector number
push            dx
xchg            ax,cx                   ;ax = cluster count, cx = low word of sector number
mul             SectorsPerCluster       ;dx:ax = sector count
.panic          <dx ne 0>,<SIFS: ReadClusters: too many clusters to read>
xchg            ax,cx                   ;cx = sector count, ax = low word of sector number
pop             dx                      ; dx:ax = sector number
call            SYIReadSectors
RestoreReg      <dx,cx,ax>
ret
EndProc ReadClusters


;
; SUBROUTINE NAME:      SYIReadFile
;
; DESCRIPTIVE NAME:     Read File via SysInit File System
;
; FUNCTION:     Read the entire file into memory.
;
; NOTES:        The file must first be opened via SYIOpenFile and the
;               buffer address must be virtual and with-in the first Meg.
;               The maximum file size which can be read is one segment.
;               The file must be closed with SYICloseFile
;
; ENTRY POINT:  SYIReadFile in DOSCODE
;    LINKAGE:   call (hybrid, protect mode)
;
; INPUT:        ax:bx -> file buffer (virtual address!)
;               cx:dx = number of bytes to read
;                       0 => entire file
;
; EXIT-NORMAL:  FileOpenFlag = false
;
; EXIT-ERROR:   Panic - hard error on boot device
;               Panic - read of undefined file attempted
;               Panic - invalid buffer address
;               Panic - Length of greater than 1 segment attempted
;               Abort - mFS_ReadFile returned an error code
;               Panic - SysInit File System not available
;
; EFFECTS:      none
;
; INTERNAL REFERENCES:
;    ROUTINES:  GetNextCluster
;               ReadClusters
;
; EXTERNAL REFERENCES:
;    ROUTINES:  mFS_ReadFile
;               SYIAbort
;
; Pseudo Code:
;       IF FileOpenFlag is false
;         Panic - no file open
;       Store buffer address
;       IF number of bytes to read is zero
;         Set number of bytes to read to file's size
;       If length is greater than 64kb then
;         Panic - Read greater than one segment not allowed
;       If Mini-FSD then
;         Call mFS_Read
;         If error returned then
;           Abort - mFS_Read returned an error
;       Else
;         IF available flag false
;           Panic - SIFS not available
;         Call VirtToPhys
;         If error returned then
;           Panic - VirtToPhys returned an error
;         IF buffer address not in low memory
;           Panic - invalid buffer address
;         Set StartCluster to FileClusterBase
;         WHILE StartCluster exists
;           ClusterCount = 0
;           Set NextCluster to StartCluster
;           REPEAT
;             Increment ClusterCount
;             Set CurrentCluster to NextCluster
;             Get NextCluster (call GetNextCluster)
;           UNTIL CurrentCluster and NextCluster not contiguous
;           Read contiguous clusters (call ReadClusters)
;           Set StartCluster to NextCluster
;         ENDWHILE
;         Store Current Cluster
;       Return
;
;
; Local Variables:
;       StartCluster     = dx
;       CurrentCluster   = ax
;       CurrentCluster+1 = bx
;       NextCluster      = ax
;       ClusterCount     = cx

Procedure SYIReadFile,<hybrid,far16>
    assume ds:nothing,es:nothing,fs:nothing,gs:nothing,ss:nothing
SaveReg         <ax,bx,cx,dx,si,di,bp,ds,es>    ;save registers
DosContext      ds
.panic          <FileOpenFlag eq 0>,<SIFS: ReadFile: no file open>
mov             FileBufferAddress.msw,ax ;store buffer address
mov             FileBufferAddress.lsw,bx
mov             ax,cx                   ;check if reading entire file
or              ax,dx
.if             <z>                     ;if so
  mov             cx,FileSize.msw         ;get the file's size
  mov             dx,FileSize.lsw
.endif
.if     <cx gt 1>        or
.if     <cx eq 1>        and
.if     <nonzero dx>
  .panic  <SIFS: Readfile: cannot read more than one segment>
.endif
mov             FileBufferLength.msw,cx ;establish number of bytes to read
mov             FileBufferLength.lsw,dx
.if             <mFSD_FLAG ne FALSE>    .then
  .if           <cx eq 1>               .then   ;can't read 64kb with MiniFsd,
    mov         FileBufferLength.lsw,8000H      ;so read 32kb twice
    push        FileBufferAddress.msw
    push        bx                              ;bx = FileBufferAddress.lsw
    push        ds
    push        offset FileBufferLength.lsw
    DosInitContext        ds
    mov         si,offset mfscInitTemplate
    call        dword ptr ds:[si].MFS_READ
    .if     <nonzero ax>          ; did the read fail?
      lea   si,tbl_syi_boot_err ; Yes, handle the failure
      call  SYIAbort
    .endif
  ; .panic      <ax ne 0>,<SIFS: Readfile: MFS_READ returned an error code>
    DosContext  ds
    mov         bx,FileBufferAddress.lsw
    add         bx,FileBufferLength.lsw
    mov         FileBufferLength.lsw,8000H
  .endif
  push          FileBufferAddress.msw
  push          bx                              ;bx = FileBufferAddress.lsw
  push          ds
  push          offset FileBufferLength.lsw
  DosInitContext        ds
  mov           si,offset mfscInitTemplate
  call          dword ptr ds:[si].MFS_READ
  .if     <nonzero ax>          ; did the read fail?
    lea   si,tbl_syi_boot_err ; Yes, handle the failure
    call  SYIAbort
  .endif
; .panic        <ax ne 0>,<SIFS: Readfile: MFS_READ returned an error code>
  DosContext    ds
.else   near
  .panic          <SIFSAvailableFlag eq 0>,<SIFS: ReadFile: SIFS not available>
  SaveReg       <ds>
  mov           si,FileBufferAddress.lsw
  mov           ds,FileBufferAddress.msw
  CALLFAR       VirtToPhys
  .panic        <c>, <SIFS: ReadFile: Error from VirtToPhys>
  RestoreReg    <ds>
  mov           FileBufferAddress.msw,ax
  mov           FileBufferAddress.lsw,bx
  test          ax,0FFF0h
  .panic        <nz>,<SIFS: ReadFile: file buffer is above the 1 MB bound>
  mov             dx,FileClusterBase      ;dx = StartCluster
  .while          <dx ne 0> and           ;0 => free cluster
    mov             ax,dx                   ;ax = StartCluster
    call            ValidateCluster
  .while          <nz> and                ;nz => more clusters available
    mov           ax,FileBufferLength.msw
    or            ax,FileBufferLength.lsw
  .while          <nz>                    ;nz => room left in the buffer
    xor             cx,cx                   ;cx = ClusterCount
    mov             ax,dx                   ;ax = CurrentCluster
    .repeat
      mov             bx,ax                   ;bx = CurrentCluster + 1
      inc             bx
      inc             cx                      ;cx = ClusterCount
      call            GetNextCluster          ;ax = NextCluster
    .until          <ax ne bx>              ;ne => not contiguous
    xchg            ax,dx                   ;ax = StartCluster, dx = NextCluster
    SaveReg         <dx>
    mov             dx,FileBufferLength.msw ;save starting buffer length
    mov             bx,FileBufferLength.lsw ;to calculate clusters read
    call            ReadClusters
    sub             bx,FileBufferLength.lsw ;dx:bx = bytes read
    sbb             dx,FileBufferLength.msw
    xchg            ax,bx                    ;dx:ax = bytes read,bx = start cluster
    div             BytesPerSector           ;ax = sectorsread
    xor dx,dx
    div             SectorsPerCluster        ;ax = clustersread
    RestoreReg      <dx>
    .if             <ax eq cx>  .then        ;if all contiguous clusters read then
      mov           FileClusterBase,dx       ;save next cluster from GetNextCluster
    .else
      add           bx,ax                    ;bx = next cluster if contiguous
      mov           FileClusterBase,bx       ;save calculated next cluster
    .endif
  .endwhile
.endif
RestoreReg      <es,ds,bp,di,si,dx,cx,bx,ax>    ;restore registers
ret
EndProc SYIReadFile

;
; SUBROUTINE NAME:      syiReadAtFile
;
; DESCRIPTIVE NAME:     Read beginning at specified location
;
; FUNCTION:     Read Seek from begining of file
;
; NOTES:        The file must first be opened via SYIOpenFile and the
;               buffer address must be virtual and with-in the first Meg.
;               The maximum file size which can be read is one segment.
;               The file must be closed with SYICloseFile
;
; ENTRY POINT:  syiReadAtFile in DOSCODE
;    LINKAGE:   call (hybrid, protect mode)
;
; INPUT:        eax -> file buffer (virtual address!)
;               ecx = number of bytes to read
;               ebx = Seek offset
;
; EXIT-NORMAL:
;
; EFFECTS:      flags
;
; INTERNAL REFERENCES:
;    ROUTINES:  SYIReadFile
;
; EXTERNAL REFERENCES:
;    ROUTINES:
;
; Pseudo Code:
;   If miniFSD then
;      push  seek offset
;      push  0   (seek from beginning of file)
;      CALL  MFS_CHGFILEPTR
;      ax:bx   <- Temporary file buffer address
;      cx:dx   <- pcBytes   (number of bytes to read)
;      CALL  SYIReadFile
;      copy data to file buffer from temp file buffer
;   Else
;      Find Cluster absolute seek offset is in
;      Update FileClusterBase to point to Cluster
;      if total read length (including offset into first cluster) > 64kb
;        ax:bx   <- Temporary file buffer address
;        cx:dx   <- cluster size
;        Call    SYIReadFile to read first cluster
;        copy appropriate section to file buffer from temp file buffer
;      ax:bx   <- Temporary file buffer address
;      cx:dx   <- pcBytes   (number of bytes to read)
;      Call    SYIReadFile to read file
;      Copy file begining at offset in temp buffer to file buffer
;   Return
;

Procedure syiReadAtFile,<hybrid,far16>
assume ds:nothing,es:nothing,fs:nothing,gs:nothing,ss:nothing

; Local Variables
;
LocalVar        Bytes2Copy,DWORD

EnterProc

SaveReg         <es,ds>
pushad
DosInitContext <ds>
mov     SIFilePointer,ecx
add     SIFilePointer,ebx
DosContext      ds

;Cases to consider:
;   Initial pass through (CacheByteSize ==0)
;   Request is completely within cache
;   Request is partially within cache
;   Request is outside of cache, before cache
;   Request is outside of cache, after cache
;   Request is == 64K
;   Request is for entire file (64K or less)
;   Request starts at offset within first sector and is for almost 64K
;       so we need to read 1 cluster + 64K

;On entry:
; eax -> file buffer (virtual address!)
; ecx = number of bytes to read
; ebx = Seek offset

mov   esi,CacheStartByte       ;Get starting file offset in cache
mov   edi,esi
add   edi,CacheByteSize        ;Get ending file offset in cache

mov   edx,ebx
add   edx,ecx                  ;Get ending file offset from request

; esi = CacheStartByte
; edi = Ending file offset in cache
; edx = Ending file offset from request

.if   <ebx ae esi> AND         ; Read begins after start of cache
.if   <ebx b  edi> AND          ; Read begins before end of cache
.if   <edx be edi>              ; Read ends before end of cache
   ; Read begins and ends inside of the cache
   ; Just copy data and return

   sub      ebx,esi
   mov      esi,ebx
   mov      ds, FileReadBuffer       ; ds:si = file buffer:offset
   mov      di,ax               ; es:di = user provided address
   ror      eax,16
   mov      es,ax
   FastRepMov

.else near
   .if <ebx ae esi> AND      ; Read begins after start of cache
   .if <ebx b edi> AND       ; Read begins before end of cache
   .if <edx a edi>           ; Read ends outside of cache
      ; Read starts inside of the cache, but not enough data is cached
      ; Copy as much data as we have, and re-fill the cache
      ; esi = CacheStartByte
      ; edi = Ending file offset in cache
      ; edx = Ending file offset from request
      push     edi              ; Save new file offset to read
      sub      edx,edi          ; Number of remaining bytes to read
      sub      edi,ebx          ; Number of bytes in buffer
      mov      ecx,edi

      mov      di,ax            ; di = user provided offset address
      add      ax,cx            ; Adjust user's offset for next read

      push     eax              ; Save new user-buffer sel:offset
      push     edx              ; Save number of remaining bytes to read
      push     ds

      sub      ebx,esi
      mov      esi,ebx
      mov      ds, FileReadBuffer  ; ds:si = file buffer:offset
      ror      eax,16
      mov      es,ax
      FastRepMov  nosaveeax

      pop      ds
      pop      ecx               ; Number of remaining bytes to read
      pop      eax               ; Sel:offset to put data
      pop      ebx               ; File offset to read

   ;Else read starts before or after cache, so re-fill the cache
   .endif

   ; eax -> file buffer (virtual address!)
   ; ecx = number of bytes to read
   ; ebx = Seek offset
   ;
   ; CACHE MISS:  Setup next read to read ahead.
   ;

   mov    Bytes2Copy,ecx          ;Save number of bytes to copy
   mov    CacheStartByte,ebx      ;New starting file offset in cache

   .if    <ecx b 010000h>
      mov    edi,ecx
      add    edi,ebx                 ;Ending byte to read in file
      mov    esi,FileSize            ;esi = FileSize
      sub    esi,edi                 ;Remaining bytes left in file to read
      add    ecx,esi
      .if    <ecx a 010000h>
         mov    ecx,010000h
      .endif
   .endif
   mov    CacheByteSize,ecx       ;Cache 64K bytes

   .if                 <mFSD_FLAG ne FALSE>    .then
       SaveReg         <eax,ecx>
       push            ebx                   ;seek offset
       push            0
       DosInitContext  ds
       mov             si,offset mfscInitTemplate
       call            dword ptr ds:[si].MFS_CHGFILEPTR
       .if             <nonzero ax>          ; did the read fail?
         lea           si,tbl_syi_boot_err ; Yes, handle the failure
         call          SYIAbort
       .endif
       RestoreReg      <ecx>
       DosContext      ds
   ;  cx:dx = number of bytes to read
       mov             edx,ecx
       ror             ecx,16
   ;  ax:bx -> file buffer (virtual address!)
       mov             ax,FileReadBuffer       ; ax:bx = buffer address
       xor             bx,bx
       Call            SYIReadFile
       mov             ds,ax               ; ds:si = buffer address
       xor             si,si
       RestoreReg      <eax>               ; eax = user buffer address
       mov             ecx,Bytes2Copy      ; get number of bytes to copy
       mov             di,ax               ; es:di = user provided address
       ror             eax,16
       mov             es,ax
       FastRepMov

   .else  near
       SaveReg         <eax>                ; save file store address
       mov             ax, StartFileClusterBase  ; First cluster of file
       mov             FileClusterBase,ax
       movzx           ecx, BytesPerCluster
   ;  bx:dx = uOffset
        mov             edx,ebx
       .while          <nonzero ax> and
       .while          <edx ae ecx>
         call          GetNextCluster       ;ax = NextCluster
         mov           FileClusterBase,ax
         sub           edx,ecx              ;dx = Seek Offset - BytesPerCluster
       .endwhile

       mov             FileDataOffset,dx     ;Save offset into first cluster
       sub             CacheStartByte,edx    ;Set new cache start byte
       add             CacheByteSize,edx     ;Set new cache byte size

       mov             ecx,CacheByteSize
       mov             edx,ecx
       ror             ecx,16

   ; Setup ax:bx to FileReadBuffer (cache buffer)
       mov             ax,FileReadBuffer       ; ax:bx = buffer address
       xor             bx,bx

   ;
   ;  If offset into first cluster is greater than 64K
   ;   Read in the first cluster
   ;   transfer to user's buffer
   ;   update

       .if             <nonzero cx> and NEAR      ; if offset into first cluster
       .if             <nonzero dx> NEAR          ; puts read over 64K
         xor           ecx,ecx                    ; then read first cluster
         mov           dx,BytesPerCluster
         Call          SYIReadFile
         RestoreReg      <eax>                    ; restore store address
         xor           ebx,ebx
         mov           bx,BytesPerCluster         ;
         add           CacheStartByte,ebx         ; New starting file offset in cache
         sub           CacheByteSize,ebx          ; New cache byte size
         sub           bx,FileDataOffset          ; ebx = valid bytes read
         mov             di,ax                    ; es:di = store address
         add             ax,bx                    ; update store address
         SaveReg         <eax>
         SaveReg         <es,ds>
         mov             ecx,Bytes2Copy      ; get number of bytes to copy
         .if             <ecx be ebx>
            mov          Bytes2Copy,0
         .else
            mov          ecx,ebx
            sub          Bytes2Copy,ebx
         .endif
         ror             eax,16
         mov             es, ax
         mov             si, FileDataOffset
         mov             ds, FileReadBuffer       ; ds:si = file buffer:offset
   ; ds:si = tmp file buffer
         FastRepMov      nosaveeax
         RestoreReg      <ds,es>

         mov           FileDataOffset,0     ; already taken care of, blow away
         mov           ax,FileReadBuffer       ; ax:bx = buffer address
         xor           bx,bx
   ;  cx:dx = number of bytes to read
         mov           ecx,CacheByteSize
         mov           edx,ecx
         ror           ecx,16
       .endif

       Call            SYIReadFile

   ;  ax:bx -> file buffer (virtual address!)
       RestoreReg      <eax>
       mov             ecx,Bytes2Copy      ; get number of bytes to copy
       .if             <nonzero ecx>
          mov             ebx,eax
          ror             eax,16               ; ax:bx = file buffer
          mov             es, ax
          mov             di, bx               ; es:di = file buffer
          mov             si, FileDataOffset
          mov             ds, FileReadBuffer
          ; ds:si = tmp file buffer
          FastRepMov
       .endif
   .endif
.endif
syiRAF_Return:

popad
RestoreReg      <ds,es>
LeaveProc
ret

EndProc syiReadAtFile

;
; SUBROUTINE NAME:      SYICloseFile
;
; DESCRIPTIVE NAME:     Close File via SysInit File System
;
; FUNCTION:     Close the file.
;
; NOTES:        The file must first be opened via SYIOpenFile.
;
; ENTRY POINT:  SYICloseFile in DOSCODE
;    LINKAGE:   call (hybrid, protect mode)
;
; INPUT:        None
;
; EXIT-NORMAL:  FileOpenFlag = false
;
; EXIT-ERROR:   None
;
; EFFECTS:      none
;
; INTERNAL REFERENCES:
;    ROUTINES:  None
;
; EXTERNAL REFERENCES:
;    ROUTINES:  MFS_OPEN
;
; Pseudo Code:
;       If Mini-FSD then
;         call MFS_OPEN
;       Set FileOpenFlag to false
;       Return
;
Procedure SYICloseFile,<hybrid,far16>
    assume ds:nothing,es:nothing,fs:nothing,gs:nothing,ss:nothing
SaveReg         <ds,es>
DosContext      ds
.if             <mFSD_FLAG ne FALSE>    .then
  SaveReg       <si>
  DosInitContext        ds
  mov           si,offset mfscInitTemplate
  call          dword ptr ds:[si].MFS_CLOSE
  RestoreReg    <si>
  DosContext      ds
.endif
mov             FileOpenFlag,FALSE
RestoreReg    <es,ds>
ret
EndProc SYICloseFile

;
; SUBROUTINE NAME:      SYIReadSectors
;
; DESCRIPTIVE NAME:     Read Sectors
;
; FUNCTION:     Read consecutive sectors from disk to memory. The specified
;               number of sectors or sufficient sectors to fill the buffer
;               (whichever comes first) are read.
;
; NOTES:        Interrupts must be disabled cause of mode switching.
;
; ENTRY POINT:  SYIReadSectors
;    LINKAGE:   CALLFAR
;
; INPUT:        dx:ax = starting sector number
;               cx = number of sectors to read
;               FileBufferAddress = physical address for buffer
;               FileBufferLength = number of bytes in buffer
;
; EXIT-NORMAL:  FileBufferAddress = incremented by number of bytes read
;               FileBufferLength = decremented by number of bytes read
;
; EXIT-ERROR:   none
;
; EFFECTS:      none
;
; INTERNAL REFERENCES:
;
; EXTERNAL REFERENCES:
;
;    ROUTINES:
;               RealModeIC
;               ProtModeIC
;               SelToSeg
;               DHReadSC
;
; Pseudo Code:
;       Switch to real mode (call RealMode)
;       get number of bytes per sector from BPB information
;       determine how many bytes must be read from last sector
;       convert address to paragraph aligned address
;       call DHReadSC
;       update file buffer length and starting location
;       Restore mode (call ProtModeIC)
;       Return
;
;
;
; Local Variables:
;       bl = CurrentSectorPhys+1
;       cx = SectorCount
;       si = Length
;       di = Address

Procedure SYIReadSectors,hybrid
    assume ds:DOSGROUP,es:nothing,fs:nothing,gs:nothing,ss:nothing

  SaveReg               <ds,es>                 ;save registers


  NullContext es
  pusha
  pushf                                 ;save interrupt state
  cli                                   ;disable interrupts for the duration
  RM            di,bx                   ;switch to real mode

  call    GetBPB                          ;read in the BPB

  mov     bx,es:[bx].BPB_BytesPerSector
  push    bx                ;save for post DosHlp calc
  push    ax
  push    dx

  ;see how many bytes we will be reading from last sector

  mov     ax,FileBufferLength.lsw
  mov     dx,FileBufferLength.msw
  div     bx            ;fileBufferLength DIV bytesPerSector
  cmp     cx,ax           ;if this read includes the last sector of file
  jbe     readSec1      ;then see if we need all of the last sector
  mov     cx,ax   ; new
  cmp     dx,0
  je      readSec1
  inc     cx      ; new
  mov     bx,dx           ;BX = #bytes in last sector
readSec1:
  push    cx
  mov     ax,FileBufferAddress.msw        ;get physical buffer address
  mov     di,FileBufferAddress.lsw

  ; convert physical address to paragraph aligned segment:offset
  mov cx, di            ; preserve value
  and cx, 0fff0h        ; remove low nibble
  or  ax,cx             ; high 3 nibbles from low to high word
  ror ax,PARASHIFT      ; get low nibble of phys addr and put in high nibble of segment
  and di, 0fh           ; save low nibble only, which is in paragraph range
  mov es,ax

  ; es:di now paragraph:offset
  pop     cx              ;recall sector count
  pop     dx
  pop     ax

  ; dx:ax = starting sector
  ; bx = bytes to read from last sector
  ; cx = sectors to read
  ; es:di - buffer segment:offset
  call    DHF.DosHlpReadSectors
  jnc     readSec2
  call    HardError
readSec2:
  dec     cx              ;determine # of full sectors read
  mov     ax,cx           ;setup dx:ax pair for Bytes Read
  xor     dx,dx           ;
  pop     cx              ; restore BPB.BytesPerSector
  mul     cx              ; #SecsRead * BytesPerSector
  add     ax,bx           ;add # bytes read in last sector
  adc     dx,0            ;

  add     FileBufferAddress.lsw,ax    ; update FileBufferAddress
  adc     FileBufferAddress.msw,dx    ; update FileBufferAddress
  sub     FileBufferLength.lsw,ax     ; update FileBufferLength
  sbb     FileBufferLength.msw,dx     ; update FileBufferLength

  PM            dx                      ;switch back to protected mode
  popf                                  ;restore interrupt state
  popa                                  ;restore registers
  RestoreReg    <es,ds>
  ret

HardError:
    DosContext <ds>
    mov           ax,MSG_SYSINIT_BOOT_ERROR
    call          DHF.DosHlpRealGetMessage              ; (ds:si) = msg length + text
    lodsw                                       ; (ax)= length
    mov           cx, ax
    movzx         edx,si
    CALLFAR       WrtToScrn
    DosContext <ds>
    mov           ax,MSG_SYSINIT_INSER_DK
    call          DHF.DosHlpRealGetMessage              ; (ds:si) = msg length + text
    lodsw                                       ; (ax)= length
    mov           cx, ax
    movzx         edx,si
    CALLFAR       WrtToScrn
Hang:
    sti
    jmp           Hang

EndProc SYIReadSectors


;
; SUBROUTINE NAME:      syiReInitSIFS
;
; DESCRIPTIVE NAME:     Reinitialize SysInit File System
;
; FUNCTION:     Reinitialize the mini file system. This is to pick up the
;               patch to the CBIOS diskette device driver.
;
; NOTES:        none
;
; ENTRY POINT:  syiReInitSIFS in DOSCODE
;    LINKAGE:   call (hybrid, protect mode)
;
; INPUT:        nothing
;
; EXIT-NORMAL:  nothing
;
; EXIT-ERROR:   Panic - invalid initialization
;
; EFFECTS:      no registers preserved
;
; INTERNAL REFERENCES:
;    ROUTINES:
;
; EXTERNAL REFERENCES:
;    ROUTINES:  none
;
; Pseudo Code:
;       Return
;

Procedure syiReInitSIFS,hybrid
    assume ds:nothing,es:nothing,fs:nothing,gs:nothing,ss:nothing
        ret
EndProc syiReInitSIFS


;
; SUBROUTINE NAME:      syiTermSIFS
;
; DESCRIPTIVE NAME:     Terminate SysInit File System
;
; FUNCTION:     Terminate the mini file system.
;
; NOTES:        none
;
; ENTRY POINT:  syiTermSIFS in DOSCODE
;    LINKAGE:   call (hybrid, protect mode)
;
; INPUT:        nothing
;
; EXIT-NORMAL:  nothing
;
; EXIT-ERROR:   Panic - can not free memory
;
; EFFECTS:      no registers preserved
;
; INTERNAL REFERENCES:
;    ROUTINES:  none
;
; EXTERNAL REFERENCES:
;    ROUTINES:  SegFree
;
; Pseudo Code:
; Free the real mode stack memory
; IF error Panic - can not free memory
; If FAT or Mini-FSD uses Dovolio then
;   Free sector buffer memory
;   IF error Panic - can not free memory
; If FAT then
;   IF available flag false
;     Panic - attempt to terminate SIFS when unavailable
;   Set available flag to false
;   Release FAT Buffer memory
;   IF error Panic - can not free memory
; Return
;

Procedure syiTermSIFS,hybrid
    assume ds:nothing,es:nothing,fs:nothing,gs:nothing,ss:nothing
SaveReg         <ax,bx,cx,dx,si,di,bp,ds,es>    ;save registers
DosContext      ds
mov             ax,FileReadBuffer      ;free the sector buffer
CALLFAR         SegFree
.panic          <c>,<SIFS: syiTermSIFS: can not free memory for read buffer>
DosContext      ds

.if             <mFSD_FLAG eq FALSE> near .then         ;If FAT system
  .panic          <SIFSAvailableFlag eq 0>,<SIFS: Term: invalid termination>
  mov             SIFSAvailableFlag,0     ;make SIFS unavailable
  mov             ax,FATBufferSelector1   ;free the first FAT buffer
  CALLFAR         SegFree
  .panic          <c>,<SIFS: Term: can not free memory for first FAT buffer>
  DosContext      ds
  mov             ax,FATBufferSelector2   ;free the second FAT buffer
  .if <nonzero ax>
    CALLFAR         SegFree
    .panic          <c>,<SIFS: Term: can not free memory for second FAT buffer>
    DosContext      ds
  .endif
  mov             ax,DirBufferSelector    ;free the directory buffer
  CALLFAR         SegFree
  .panic          <c>,<SIFS: Term: can not free memory for root directory buffer>
  DosContext      ds
  mov             ax,OS2DirBufferSelector    ;free the directory buffer
  .if             <nonzero ax>
    CALLFAR         SegFree
    .panic          <c>,<SIFS: Term: can not free memory for OS2 dir buffer>
    DosContext      ds
  .endif
  DosContext      ds
  DosContext      ds
  mov             ax,OS2BOOTDirBufferSelector  ;free the directory buffer
  .if             <nonzero ax>
    CALLFAR         SegFree
    .panic          <c>,<SIFS: Term: can not free memory for OS2\BOOT Dir buff>
    DosContext      ds
  .endif
.endif
RestoreReg      <es,ds,bp,di,si,dx,cx,bx,ax>    ;restore registers
ret
EndProc syiTermSIFS


;
; SUBROUTINE NAME:      ValidateCluster
;
; DESCRIPTIVE NAME:     Validate the Cluster Number
;
; FUNCTION:     Check the cluster number to see if it is the end-of-file
;               marker.
;
; NOTES:        none
;
; ENTRY POINT:  ValidateCluster
;    LINKAGE:   call (near)
;
; INPUT:        ax = cluster number
;
; EXIT-NORMAL:  z-flag = status
;                       NZ => valid cluster number
;                       Z => end of file encountered
;
; EXIT-ERROR:   none
;
; EFFECTS:      ax destroyed
;
; INTERNAL REFERENCES:
;    ROUTINES:  none
;
; EXTERNAL REFERENCES:
;    ROUTINES:  none
;
; Pseudo Code:
;       IF the FAT has 12-bit entries
;         IF cluster number .and. 0FF8h is 0FF8h
;           Indicate end-of-file
;         ELSE
;           Indicate valid cluster number
;         ENDIF
;       ELSE
;         IF cluster number .and. 0FFF8h is 0FFF8h
;           Indicate end-of-file
;         ELSE
;           Indicate valid cluster number
;         ENDIF
;       ENDIF
;       Return
;

Procedure ValidateCluster,near,local
    assume ds:DOSGROUP,es:nothing,fs:nothing,gs:nothing,ss:nothing
.if             <FATEntrySize eq 12>
  and             ax,0FF8h
  cmp             ax,0FF8h
.else
  and             ax,0FFF8h
  cmp             ax,0FFF8h
.endif
ret
EndProc ValidateCluster

INITCODE ends


        FARCODE HIGH32
CINIT_TEXT segment


;**EP   SIReadAt - thunk for SIReadAt
;
;       SIReadAt is a translator thunk between the 32-bit C
;       routine SIReadAt and the 16-bit assembler routine
;       syiReadAtFile with byte seeking.
;
;       ENTRY:        [esp]   ret addr
;                     [esp+4] SFN, zero extended to a dword
;                     [esp+12] pointer to count of bytes to read
;                     [esp+16] 0:32 transfer address
;                     [esp+20] 16:16 transfer address
;                     [esp+24] file offset to read from
;
;       EXIT:         eax = 0
;
;       USES:         eax,flags
;
;       Pseudo Code:
;         Call    syiReadAtFile to read file
;         Return
;

        ASSUME DS:FLAT,ES:FLAT,FS:NOTHING,GS:NOTHING,SS:NOTHING
Procedure SIReadAt,near
ArgVar  uSFN,DWORD
ArgVar  pcBytes,DWORD
ArgVar  pXferAddr,DWORD
ArgVar  psXferAddr,DWORD
ArgVar  uOffset,DWORD
LocalVar        SelTemp,DWORD

EnterProc

SaveReg <ebx,esi,edi>
mov     SelTemp,0                       ; Allocate a new selector
SSToDS  eax,SelTemp
mov     edi, [pcBytes]
CCALL32 _SELLdrDesc,<pXferAddr,<dword ptr [edi]>,eax>
.if     <zero eax>

  ;  ecx = number of bytes to read
  mov     edi, [pcBytes]
  mov     ecx,[edi]
  ;  eax -> file buffer (virtual address!)
  mov     eax,SelTemp
  rol     eax,16
  ;  ebx = uOffset
  mov     ebx,[uOffset]
  CALL16  syiReadAtFile
  CCALL32 _SELFreeGDT,SelTemp
  xor     eax,eax
.endif
RestoreReg <edi,esi,ebx>
LeaveProc
RETC

EndProc SIReadAt

;**EP   SIOpen - thunk for SIOpen
;
;       SIOpen is a translator thunk between the 32-bit C
;       routine SIOpen and the 16-bit assembler routine
;       SYIOpenFile.
;
;       ENTRY:  [esp]   ret addr
;               [esp+4] 32-bit near pointer to name of file to open
;               [esp+8] NULL
;               [esp+12] NULL
;               [esp+16] 32-bit near addr of location to store SFN in
;
;       EXIT:         eax = error code
;
;       USES:         eax,flags
;
;       Pseudo Code:
;         Get 16 bit selector for file name (call SELLdrDesc)
;         Call SYIOpenFile
;         Free file name selector (cal SELFreeGDT)
;         Return

    ASSUME DS:FLAT,ES:FLAT,FS:NOTHING,GS:NOTHING,SS:NOTHING
Procedure SIOpen,near
ArgVar  pszFname,DWORD          ; pointer to file name
ArgVar  FileMode,DWORD          ; share, access, etc. mode
ArgVar  OpenFlag,DWORD          ; open flags (fail if !exist, etc.)
ArgVar  pSFN,DWORD              ; pointer to SFN to use

LocalVar SelTemp,DWORD

    EnterProc
    SaveReg <ebx,esi,edi>

    mov     SelTemp,0                       ; Allocate a new selector
    SSToDS  eax,SelTemp
    CCALL32 _SELLdrDesc,<pszFname,MAXPATHLEN,eax>
    .if     <zero eax>
      SaveReg <es>
      mov     es,SelTemp
      xor     di,di
      CALL16  SYIOpenFile
      .if     <nc>
        xor   eax,eax
        SaveReg <ds>                          ; set the filepointer
        DosInitContext <ds>
        mov     SIFilePointer,eax
        RestoreReg <ds>
      .else
        mov   eax,ERROR_FILE_NOT_FOUND
      .endif
      RestoreReg <es>
      SaveReg <eax>
      CCALL32 _SELFreeGDT,SelTemp             ; free the alias
      RestoreReg <eax>
    .endif
    RestoreReg <edi,esi,ebx>
    LeaveProc
    RETC
EndProc SIOpen

;**EP   SIClose - thunk for SIClose
;
;       SIClose is a translator thunk between the 32-bit C
;       routine SIClose and the 16-bit assembler routine
;       SYICloseFile.
;
;       ENTRY:  [esp]   ret addr
;               [esp+4] SFN, zero extended to a dword
;
;       EXIT    eax = 0
;
;       Pseudo Code:
;         Call SYICloseFile
;         Return

Procedure SIClose,near
    assume ds:FLAT,es:FLAT,fs:nothing,gs:nothing,ss:nothing
    ArgVar      uSFN,DWORD

    EnterProc
    SaveReg     <ds,es>
    pushad
    CALL16      SYICloseFile
    popad
    RestoreReg  <es,ds>
    xor         eax,eax
    LeaveProc
    RETC
EndProc SIClose

;**LP   SIIOSftTransPath
;
;       SIIOSftTransPath is stub to prevent the loader from
;       calling _IOSftTransPath at init time.
;
;       ENTRY
;               pchName         : ASCIIZ filename to canonicalize
;
;       EXIT
;               The Return Value is held in EAX on exit
;
;               Return Value == NO_ERROR
;                       TransPathCnvPathChars was successful
;
;                   Side Effects :
;                       [_ldrFileNameBuf] -> canonicalized filename
;
;               Return Value = NO_ERROR
;
;       USES            EAX, ECX, EDX, EFlags
;
;       Pseudocode :
;       Copy name to ptda searchbuf
;       Return no error
;

        ASSUME  DS:FLAT, ES:FLAT, FS:NOTHING, GS:NOTHING, SS:NOTHING
Procedure       SIIOSftTransPath,near
ArgVar  pchName,DWORD
        EnterProc
        SaveReg <edi,esi,edx>
        mov     edi,pchName
        cld
        mov     ecx,MAXPATHLEN
        xor     al,al
        repne   scasb
        mov     ecx,edi
        sub     ecx,pchName
        mov     esi,pchName
        mov     edi,_ldrpFileNameBuf
        mov     dx,[SISData].SIS_BootDrv
        add     dl,'A'-1
        mov     es:[edi],dl
        mov     dl,':'
        mov     es:[edi+1],dl
        mov     dl,'\'
        mov     es:[edi+2],dl
        add     edi, 3
        FastRepMov nosaveeax
        xor     eax,eax
        RestoreReg <edx,esi,edi>
        LeaveProc
        RETC

EndProc SIIOSftTransPath


;*      SIldrGetMedia
;
;       SIldrGetMedia is stub to prevent the loader from
;       calling ldrGetMedia at init time.
;
;       ENTRY
;               EAX     SFN
;               ECX     Pointer to Media bits
;
;       EXIT
;               (EAX) = NO_ERROR
;               (ECX) = Media bits
;           or
;               (EAX) = Error Code
;
;       Pseudocode :
;       Return no error removeable media

    assume DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure       SIldrGetMedia,near
;       PMONLY
        xor     eax,eax
        xor     ecx,ecx
        RETC
EndProc SIldrGetMedia

CINIT_TEXT ends
        end
