     1                                  ;	SCCSID = @(#)fcbio.asm	1.5 85/07/30
     2                                  ;	SCCSID = @(#)fcbio.asm	1.5 85/07/30
     3                                  ;TITLE	FCBIO - FCB system calls
     4                                  ;NAME	FCBIO
     5                                  
     6                                  ;
     7                                  ; Ancient 1.0 1.1 FCB system calls
     8                                  ;				    regen   save
     9                                  ;   $GET_FCB_POSITION	    written none    none
    10                                  ;   $FCB_DELETE 	    written none    none
    11                                  ;   $GET_FCB_FILE_LENGTH    written none    none
    12                                  ;   $FCB_CLOSE		    written close   none
    13                                  ;   $FCB_RENAME 	    written none    none
    14                                  ;   SaveFCBInfo
    15                                  ;   ResetLRU
    16                                  ;   SetOpenAge
    17                                  ;   LRUFCB
    18                                  ;   FCBRegen
    19                                  ;   BlastSFT
    20                                  ;   CheckFCB
    21                                  ;   SFTFromFCB
    22                                  ;   FCBHardErr
    23                                  ;
    24                                  ;   Revision history:
    25                                  ;
    26                                  ;	Created: ARR 4 April 1983
    27                                  ;		 MZ  6 June  1983 completion of functions
    28                                  ;		 MZ 15 Dec   1983 Brain damaged programs close FCBs multiple
    29                                  ;				  times.  Change so successive closes work by
    30                                  ;				  always returning OK.	Also, detect I/O to
    31                                  ;				  already closed FCB and return EOF.
    32                                  ;		 MZ 16 Jan   1984 More braindamage.  Need to separate info
    33                                  ;				  out of sft into FCB for reconnection
    34                                  ;
    35                                  ;	A000	 version 4.00  Jan. 1988
    36                                  ;
    37                                  [list -]
    37          ******************       warning: redefining multi-line macro `struc' [-w+pp-macro-redef-multi]
    14                              <4> [list -]
    14                              <3> [list -]
     3                              <2> 
     4                              <2> addsection DOSSTART, align=16 PUBLIC class=DOSSTART
     5                              <2> ; (no prior section) ; DOSSTART		ENDS
     6                              <2> 
     7                              <2> addsection DOSSTARTJUMP, align=1 PUBLIC class=START
     8                              <2> ; (no prior section) ; DOSSTARTJUMP		ENDS
     9                              <2> 
    10                              <2> addsection CONSTANTS, align=2 PUBLIC class=CONST
    11                              <2> ; (no prior section) ; CONSTANTS	ENDS
    12                              <2> 
    13                              <2> addsection DATA, align=2 PUBLIC class=DATA
    14                              <2> ; (no prior section) ; DATA		ENDS
    15                              <2> 
    16                              <2> addsection TABLE, align=2 PUBLIC class=TABLE
    17                              <2> ; (no prior section) ; TABLE		ENDS
    18                              <2> 
    19                              <2> addsection DOSDATATABLE, align=2 PUBLIC class=DOSDATACODE
    20                              <2> ; (no prior section) ; DOSDATATABLE		ENDS
    21                              <2> 
    22                              <2> addsection DOSDATACODE, align=1 PUBLIC class=DOSDATACODE
    23                              <2> ; (no prior section) ; DOSDATACODE		ENDS
    24                              <2> 
    25                              <2> addsection DOSBIODATA, align=2 PUBLIC class=DOSBIODATA
    26                              <2> 
    27                              <2> addsection LAST, align=16 PUBLIC class=LAST
    28                              <2> ; (no prior section) ; LAST		ENDS
    29                              <2> 
    30                              <2> group DOSGROUP DOSSTART DOSSTARTJUMP CONSTANTS DATA TABLE DOSDATATABLE DOSDATACODE DOSBIODATA LAST
     8                              <1> 
     9                              <1> %include "dcodeseg.nas"
     1                              <2> 
     2                              <2> %ifndef DCODESEGNAS
     3                              <2> %assign DCODESEGNAS 1
     4                              <2> 
     5                              <2> section DOSCODETABLE align=2 PUBLIC class=DOSCODE
     6                              <2> ; (no prior section) ; DOSCODETABLE		ENDS
     7                              <2> section DOSCODECODE align=1 PUBLIC class=DOSCODE
     8                              <2> ; (no prior section) ; DOSCODECODE		ENDS
     9                              <2> section DOSBIOCODE align=2 PUBLIC class=DOSCODE
    10                              <2> section BIOCODE	align=2 PUBLIC class=DOSCODE
    11                              <2> 
    12                              <2> %ifnidni DOSENTRYGROUP, DOSCODEGROUP
    13                              <2>  group DOSCODEGROUP DOSCODETABLE DOSCODECODE DOSBIOCODE BIOCODE
    14                              <2> %endif
    15                              <2> 
    16                              <2> %endif
    10                              <1> 
    11                              <1> section LAST
    12                              <1> ; (no prior section) ; LAST		ENDS
    42                                  
    43                                  [list +]
    44                                  section DOSCODECODE
    45                                  [list -]
    45          ******************       warning: out: ... for DOS Version 4.00 ... [-w+user]
    45          ******************       warning: out: BPB.INC... [-w+user]
    45          ******************       warning: out: ... CLONE version build switch on ... [-w+user]
    45          ******************       warning: out: DEVSYM.INC... [-w+user]
    53                                  
    54                                  %ifndef Kanji
    55                                   %iassign Kanji 0
    56                                  %endif
    57                                  
    58                                  	I_need	OpenBuf,128		; buffer for translating paths
    59                                  	I_need	RenBuf,128		; buffer for rename paths
    60                                  	i_need	THISDPB,DWORD
    61                                  	i_need	EXTERR,WORD
    62                                  	i_need	ALLOWED,BYTE
    63                                  	I_need	ThisSFT,DWORD		; SFT in use
    64                                  	I_need	WFP_start,WORD		; pointer to canonical name
    65                                  	I_need	Ren_WFP,WORD		; pointer to canonical name
    66                                  	I_need	Attrib,BYTE		; Attribute for match attributes
    67                                  	I_need	sftFCB,DWORD		; pointer to SFTs for FCB cache
    68                                  	I_need	FCBLRU,WORD		; least recently used count
    69                                  	I_need	Proc_ID,WORD		; current process ID
    70                                  	I_Need	Name1,14		; place for device names
    71                                  	I_need	DEVPT,DWORD		; device pointer
    72                                  	I_need	OpenLRU,WORD		; open age
    73                                  	I_need	KeepCount,WORD		; number of fcbs to keep
    74                                  	I_need	User_In_AX,WORD 	; user input system call.
    75                                  	I_need	JShare,DWORD		; share jump table
    76                                  	I_need	FastOpenTable,BYTE	; DOS 3.3 fastopen
    77                                  %if debug
    78                                  	I_need	BugLev,WORD
    79                                  	I_need	BugTyp,WORD
    80                                  	%include "bugtyp.nas"
    81                                  %endif
    82                                  
    83                                  
    84                                  Break <$Get_FCB_Position - set random record fields to current pos>
    85                                  
    86                                  ;
    87                                  ;   $Get_FCB_Position - look at an FCB, retrieve the current position from the
    88                                  ;	extent and next record field and set the random record field to point
    89                                  ;	to that record
    90                                  ;
    91                                  ;   Inputs:	DS:DX point to a possible extended FCB
    92                                  ;   Outputs:	The random record field of the FCB is set to the current record
    93                                  ;   Registers modified: all
    94                                  
    95                                  Procedure D_Get_FCB_Position,NEAR
    95          ******************       warning: proc D_Get_FCB_Position... [-w+user]
    96                                   ASSUME DS:NOTHING,ES:NOTHING,SS:DOSGroup
    97 00000000 E8(0000)                	invoke	GetExtended		; point to FCB
    98 00000003 E8(0000)                	invoke	GetExtent		; DX:AX is current record
    99 00000006 894421                  	MOV	WORD PTR [SI + fcb_RR],AX ; drop in low order piece
   100 00000009 885423                  	MOV	[SI+fcb_RR+2],DL	; drop in high order piece
   101 0000000C 837C0E40                	CMP	word [SI + fcb_RECSIZ],64
   102 00000010 7303                    	JAE	GetFCBBye
   103 00000012 887424                  	MOV	[SI+fcb_RR+2+1],DH	; Set 4th byte only if record size < 64
   104                                  GetFCBBye:
   105 00000015 E9(0000)                	transfer    FCB_Ret_OK
   106                                  EndProc D_GET_FCB_POSITION
   107                                  
   108                                  Break <$FCB_Delete - remove several files that match the input FCB>
   109                                  
   110                                  ;
   111                                  ;   $FCB_delete - given an FCB, remove all directory entries in the current
   112                                  ;	directory that have names that match the FCB's ?  marks.
   113                                  ;
   114                                  ;   Inputs:	DS:DX - point to an FCB
   115                                  ;   Outputs:	directory entries matching the FCB are deleted
   116                                  ;		AL = FF if no entries were deleted.
   117                                  ;   Registers modified: all
   118                                  
   119                                  Procedure D_FCB_Delete,NEAR
   119          ******************       warning: proc D_FCB_Delete... [-w+user]
   120                                   ASSUME DS:NOTHING,ES:NOTHING,SS:DOSGroup
   121                                  DOSGroup equ DOSGROUP	; NASM port equate
   122 00000018 BF[0000]                	MOV	DI,OFFSET OpenBuf wrt DOSGroup  ; appropriate place
   123 0000001B E8(0000)                	invoke	TransFCB		; convert FCB to path
   124 0000001E 7209                    	JC	BadPath 		; signal no deletions
   125 00000020 161F                    	Context DS
   126 00000022 E8(0000)                	invoke	DOS_Delete		; wham
   127 00000025 7202                    	JC	BadPath
   128                                  GoodPath:
   129 00000027 EBEC                    	transfer    FCB_Ret_OK		; do a good return
   130                                  BadPath:
   131                                  ;
   132                                  
   133                                  ; Error code is in AX
   134                                  ;
   135 00000029 E9(0000)                	transfer    FCB_Ret_Err 	; let someone else signal the error
   136                                  EndProc D_FCB_DELETE
   137                                  
   138                                  Break <$Get_FCB_File_Length - return the length of a file>
   139                                  
   140                                  ;
   141                                  ;   $Get_FCB_File_Length - set the random record field to the length of the
   142                                  ;	file in records (rounded up if partial).
   143                                  ;
   144                                  ;   Inputs:	DS:DX - point to a possible extended FCB
   145                                  ;   Outputs:	Random record field updated to reflect the number of records
   146                                  ;   Registers modified: all
   147                                  
   148                                  Procedure   D_Get_FCB_File_Length,NEAR
   148          ******************       warning: proc D_Get_FCB_File_Length... [-w+user]
   149                                   ASSUME DS:NOTHING,ES:NOTHING,SS:DOSGroup
   150 0000002C E8(0000)                	invoke	GetExtended		; get real FCB pointer
   151                                  					; DX points to Input FCB
   152 0000002F BF[0000]                	MOV	DI,OFFSET OpenBuf wrt DOSGroup  ; appropriate buffer
   153 00000032 1E56                    	SaveReg <DS,SI> 		; save pointer to true FCB
   154 00000034 E8(0000)                	Invoke	TransFCB		; Trans name DS:DX, sets SATTRIB
   155 00000037 5E1F                    	RestoreReg  <SI,DS>
   156 00000039 72EE                    	JC	BadPath
   157 0000003B 1E56                    	SaveReg <DS,SI> 		; save pointer
   158 0000003D 161F                    	Context DS
   159 0000003F E8(0000)                	invoke	Get_File_Info		; grab the info
   160 00000042 5E1F                    	RestoreReg  <SI,DS>		; get pointer back
   161 00000044 72E3                    	JC	BadPath 		; invalid something
   162 00000046 89DA                    	MOV	DX,BX			; get high order size
   163 00000048 89F8                    	MOV	AX,DI			; get low order size
   164 0000004A 8B5C0E                  	MOV	BX,[SI + fcb_RECSIZ]	; get his record size
   165 0000004D 09DB                    	OR	BX,BX			; empty record => 0 size for file
   166 0000004F 7503                    	JNZ	GetSize 		; not empty
   167 00000051 BB8000                  	MOV	BX,128
   168                                  GetSize:
   169 00000054 89C7                    	MOV	DI,AX			; save low order word
   170 00000056 89D0                    	MOV	AX,DX			; move high order for divide
   171 00000058 31D2                    	XOR	DX,DX			; clear out high
   172 0000005A F7F3                    	DIV	BX			; wham
   173 0000005C 50                      	PUSH	AX			; save dividend
   174 0000005D 89F8                    	MOV	AX,DI			; get low order piece
   175 0000005F F7F3                    	DIV	BX			; wham
   176 00000061 89D1                    	MOV	CX,DX			; save remainder
   177 00000063 5A                      	POP	DX			; get high order dividend
   178 00000064 E306                    	JCXZ	LengthStore		; no roundup
   179 00000066 83C001                  	ADD	AX,1
   180 00000069 83D200                  	ADC	DX,0			; 32-bit increment
   181                                  LengthStore:
   182                                  FCB_RR equ fcb_RR	; NASM port label
   183 0000006C 894421                  	MOV	WORD PTR [SI + FCB_RR],AX ; store low order
   184 0000006F 885423                  	MOV	[SI + FCB_RR+2],DL	; store high order
   185 00000072 08F6                    	OR	DH,DH
   186 00000074 74B1                    	JZ	GoodPath		; not storing insignificant zero
   187 00000076 887424                  	MOV	[SI + FCB_RR+3],DH	; save that high piece
   188                                  GoodRet:
   189 00000079 EBAC                    	transfer    FCB_Ret_OK
   190                                  EndProc D_GET_FCB_FILE_LENGTH
   191                                  
   192                                  Break <$FCB_Close - close a file>
   193                                  
   194                                  ;
   195                                  ;   $FCB_Close - given an FCB, look up the SFN and close it.  Do not free it
   196                                  ;	as the FCB may be used for further I/O
   197                                  ;
   198                                  ;   Inputs:	DS:DX point to FCB
   199                                  ;   Outputs:	AL = FF if file was not found on disk
   200                                  ;   Registers modified: all
   201                                  
   202                                  Procedure D_FCB_Close,NEAR
   202          ******************       warning: proc D_FCB_Close... [-w+user]
   203                                   ASSUME DS:NOTHING,ES:NOTHING,SS:DOSGroup
   204 0000007B 30C0                    	XOR	AL,AL			; default search attributes
   205 0000007D E8(0000)                	invoke	GetExtended		; DS:SI point to real FCB
   206 00000080 7403                    	JZ	NoAttr			; not extended
   207 00000082 8A44FF                  	MOV	AL,[SI-1]		; get attributes
   208                                  NoAttr:
   209 00000085 36A2[0000]              	MOV	[ss:Attrib],AL		; stash away found attributes
   210 00000089 E8F803                  	invoke	SFTFromFCB
   211 0000008C 72EB                    	JC	GoodRet 		; MZ 16 Jan Assume death
   212                                  ;
   213                                  ; If the sharer is present, then the SFT is not regenable.  Thus, there is
   214                                  ; no need to set the SFT's attribute.
   215                                  ;
   216                                  ;;; 9/8/86 F.C. save SFT attribute and restore it back when close is done
   217 0000008E 268A4504                	MOV	AL,[ES:DI + sf_attr]
   218 00000092 30E4                    	XOR	AH,AH
   219 00000094 50                      	PUSH	AX
   220                                  ;;; 9/8/86 F.C. save SFT attribute and restore it back when close is done
   221 00000095 E8(0000)                	invoke	CheckShare
   222 00000098 7508                    	JNZ	NoStash
   223 0000009A 36A0[0000]              	MOV	AL,[ss:Attrib]
   224 0000009E 26884504                	MOV	[ES:DI + sf_attr],AL	; attempted attribute for close
   225                                  NoStash:
   226                                  FCB_FDATE equ fcb_FDATE	; NASM port label
   227 000000A2 8B4414                  	MOV	AX,[SI + FCB_FDATE]	; move in the time and date
   228 000000A5 2689450F                	MOV	[ES:DI + sf_date],AX
   229                                  FCB_FTIME equ fcb_FTIME	; NASM port label
   230 000000A9 8B4416                  	MOV	AX,[SI + FCB_FTIME]
   231 000000AC 2689450D                	MOV	[ES:DI + sf_time],AX
   232                                  FCB_FilSiz equ fcb_FILSIZ	; NASM port label
   233 000000B0 8B4410                  	MOV	AX,[SI + FCB_FilSiz]
   234 000000B3 26894511                	MOV	WORD PTR [ES:DI + sf_size],AX
   235 000000B7 8B4412                  	MOV	AX,[SI + FCB_FilSiz + 2]
   236 000000BA 26894513                	MOV	WORD PTR [ES:DI + sf_size + 2],AX
   237                                  sf_Flags equ sf_flags	; NASM port label
   238 000000BE 26814D050040            	OR	word [ES:DI + sf_Flags],sf_close_nodate
   239 000000C4 161F                    	Context DS			; let Close see variables
   240 000000C6 E8(0000)                	invoke	DOS_Close		; wham
   241 000000C9 C43E[0000]              	LES	DI,[ThisSFT]
   242                                  ;;; 9/8/86 F.C. restore SFT attribute
   243 000000CD 59                      	POP	CX
   244 000000CE 26884D04                	MOV	[ES:DI + sf_attr],CL
   245                                  ;;; 9/8/86 F.C. restore SFT attribute
   246 000000D2 9C                      	PUSHF
   247 000000D3 26F705FFFF              	TEST	word [ES:DI + sf_ref_count],-1 ; zero ref count gets blasted
   248 000000D8 7507                    	JNZ	CloseOK
   249 000000DA 50                      	PUSH	AX
   250 000000DB B04D                    	MOV	AL,'M'
   251 000000DD E8D202                  	invoke	BlastSFT
   252 000000E0 58                      	POP	AX
   253                                  CloseOK:
   254 000000E1 9D                      	POPF
   255 000000E2 7395                    	JNC	GoodRet
   256 000000E4 3C06                    	CMP	AL,error_invalid_handle
   257 000000E6 7491                    	JZ	GoodRet
   258 000000E8 B002                    	MOV	AL,error_file_not_found
   259 000000EA E9(0000)                	transfer    FCB_Ret_Err
   260                                  EndProc D_FCB_CLOSE
   261                                  
   262                                  Break	<$FCB_Rename - change names in place>
   263                                  
   264                                  ;
   265                                  ;   $FCB_Rename - rename a file in place within a directory.  Renames multiple
   266                                  ;	files copying from the meta characters.
   267                                  ;
   268                                  ;   Inputs:	DS:DX point to an FCB.	The normal name field is the source
   269                                  ;		    name of the files to be renamed.  Starting at offset 11h
   270                                  ;		    in the FCB is the destination name.
   271                                  ;   Outputs:	AL = 0 -> no error occurred and all files were renamed
   272                                  ;		AL = FF -> some files may have been renamed but:
   273                                  ;		    rename to existing file or source file not found
   274                                  ;   Registers modified: all
   275                                  
   276                                  Procedure D_FCB_Rename,NEAR
   276          ******************       warning: proc D_FCB_Rename... [-w+user]
   277                                   ASSUME DS:NOTHING,ES:NOTHING,SS:DOSGroup
   278 000000ED E8(0000)                	invoke	GetExtended		; get pointer to real FCB
   279 000000F0 52                      	SaveReg <DX>
   280 000000F1 8A04                    	MOV	AL,[SI] 		; get drive byte
   281 000000F3 83C610                  	ADD	SI,10h			; point to destination
   282 000000F6 BF[0000]                	MOV	DI,OFFSET RenBuf wrt DOSGroup   ; point to destination buffer
   283 000000F9 FF341E56                	SaveReg <<WORD PTR [SI]>,DS,SI>  ; save source pointer for TransFCB
   284 000000FD 8804                    	MOV	[SI],AL		; drop in real drive
   285 000000FF 89F2                    	MOV	DX,SI			; let TransFCB know where the FCB is
   286 00000101 E8(0000)                	invoke	TransFCB		; munch this pathname
   287 00000104 5E1F8F04                	RestoreReg  <SI,DS,<WORD PTR [SI]>>	; get path back
   288 00000108 5A                      	RestoreReg  <DX>		; Original FCB pointer
   289 00000109 721A                    	JC	BadRen			; bad path -> error
   290                                  WFP_Start equ WFP_start	; NASM port label
   291 0000010B 368B36[0000]            	MOV	SI,[ss:WFP_Start]		; get pointer
   292 00000110 368936[0000]            	MOV	[ss:Ren_WFP],SI		; stash it
   293 00000115 BF[0000]                	MOV	DI,OFFSET OpenBuf wrt DOSGroup  ; appropriate spot
   294 00000118 E8(0000)                	invoke	TransFCB		; wham
   295                                  					; NOTE that this call is pointing
   296                                  					;  back to the ORIGINAL FCB so
   297                                  					;  SATTRIB gets set correctly
   298 0000011B 7208                    	JC	BadRen			; error
   299 0000011D E8(0000)                	invoke	DOS_Rename
   300 00000120 7203                    	JC	BadRen
   301 00000122 E9(0000)                	transfer    FCB_Ret_OK
   302                                  BadRen:
   303                                  ;
   304                                  ; AL has error code
   305                                  ;
   306 00000125 EBC3                    	transfer    FCB_Ret_Err
   307                                  
   308                                  EndProc D_FCB_RENAME
   309                                  
   310                                  Break <Misbehavior fixers>
   311                                  
   312                                  ;
   313                                  ;   FCBs suffer from several problems.	First, they are maintained in the
   314                                  ;   user's space so he may move them at will.  Second, they have a small
   315                                  ;   reserved area that may be used for system information.  Third, there was
   316                                  ;   never any "rules for behavior" for FCBs; there was no protocol for their
   317                                  ;   usage.
   318                                  ;
   319                                  ;   This results in the following misbehavior:
   320                                  ;
   321                                  ;	infinite opens of the same file:
   322                                  ;
   323                                  ;	While (TRUE) {			While (TRUE) {
   324                                  ;	    FCBOpen (FCB);		    FCBOpen (FCB);
   325                                  ;	    Read (FCB); 		    Write (FCB);
   326                                  ;	    }				    }
   327                                  ;
   328                                  ;	infinite opens of different files:
   329                                  ;
   330                                  ;	While (TRUE) {			While (TRUE) {
   331                                  ;	    FCBOpen (FCB[i++]); 	    FCBOpen (FCB[i++]);
   332                                  ;	    Read (FCB); 		    Write (FCB);
   333                                  ;	    }				    }
   334                                  ;
   335                                  ;	multiple closes of the same file:
   336                                  ;
   337                                  ;	FCBOpen (FCB);
   338                                  ;	while (TRUE)
   339                                  ;	    FCBClose (FCB);
   340                                  ;
   341                                  ;	I/O after closing file:
   342                                  ;
   343                                  ;	FCBOpen (FCB);
   344                                  ;	while (TRUE) {
   345                                  ;	    FCBWrite (FCB);
   346                                  ;	    FCBClose (FCB);
   347                                  ;	    }
   348                                  ;
   349                                  ;   The following is am implementation of a methodology for emulating the
   350                                  ;   above with the exception of I/O after close.  We are NOT attempting to
   351                                  ;   resolve that particular misbehavior.  We will enforce correct behaviour in
   352                                  ;   FCBs when they refer to a network file or when there is file sharing on
   353                                  ;   the local machine.
   354                                  ;
   355                                  ;   The reserved fields of the FCB (10 bytes worth) is divided up into various
   356                                  ;   structures depending on the file itself and the state of operations of the
   357                                  ;   OS.  The information contained in this reserved field is enough to
   358                                  ;   regenerate the SFT for the local non-shared file.  It is assumed that this
   359                                  ;   regeneration procedure may be expensive.  The SFT for the FCB is
   360                                  ;   maintained in a LRU cache as the ONLY performance inprovement.
   361                                  ;
   362                                  ;   No regeneration of SFTs is attempted for network FCBs.
   363                                  ;
   364                                  ;   To regenerate the SFT for a local FCB, it is necessary to determine if the
   365                                  ;   file sharer is working.  If the file sharer is present then the SFT is not
   366                                  ;   regenerated.
   367                                  ;
   368                                  ;   Finally, if there is no local sharing, the full name of the file is no
   369                                  ;   longer available.  We can make up for this by using the following
   370                                  ;   information:
   371                                  ;
   372                                  ;	The Drive number (from the DPB).
   373                                  ;	The physical sector of the directory that contains the entry.
   374                                  ;	The relative position of the entry in the sector.
   375                                  ;	The first cluster field.
   376                                  ;	The last used SFT.
   377                                  ;      OR In the case of a device FCB
   378                                  ;	The low 6 bits of sf_flags (indicating device type)
   379                                  ;	The pointer to the device header
   380                                  ;
   381                                  ;
   382                                  ;   We read in the particular directory sector and examine the indicated
   383                                  ;   directory entry.  If it matches, then we are kosher; otherwise, we fail.
   384                                  ;
   385                                  ;   Some key items need to be remembered:
   386                                  ;
   387                                  ;	Even though we are caching SFTs, they may contain useful sharing
   388                                  ;	information.  We enforce good behavior on the FCBs.
   389                                  ;
   390                                  ;	Network support must not treat FCBs as impacting the ref counts on
   391                                  ;	open VCs.  The VCs may be closed only at process termination.
   392                                  ;
   393                                  ;	If this is not an installed version of the DOS, file sharing will
   394                                  ;	always be present.
   395                                  ;
   396                                  ;	We MUST always initialize lstclus to = firclus when regenerating a
   397                                  ;	file. Otherwise we start allocating clusters up the wazoo.
   398                                  ;
   399                                  ;	Always initialize, during regeneration, the mode field to both isFCB
   400                                  ;	and open_for_both.  This is so the FCB code in the sharer can find the
   401                                  ;	proper OI record.
   402                                  ;
   403                                  ;   The test bits are:
   404                                  ;
   405                                  ;	00 -> local file
   406                                  ;	40 -> sharing local
   407                                  ;	80 -> network
   408                                  ;	C0 -> local device
   409                                  
   410                                  Break	<SaveFCBInfo - store pertinent information from an SFT into the FCB>
   411                                  
   412                                  ;
   413                                  ;   SaveFCBInfo - given an FCB and its associated SFT, copy the relevant
   414                                  ;	pieces of information into the FCB to allow for subsequent
   415                                  ;	regeneration. Poke LRU also.
   416                                  ;
   417                                  ;   Inputs:	ThisSFT points to a complete SFT.
   418                                  ;		DS:SI point to the FCB (not an extended one)
   419                                  ;   Outputs:	The relevant reserved fields in the FCB are filled in.
   420                                  ;		DS:SI preserved
   421                                  ;		ES:DI point to sft
   422                                  ;   Registers modified: All
   423                                  ;
   424                                  
   425                                  Procedure   SaveFCBInfo,NEAR
   425          ******************       warning: proc SaveFCBInfo... [-w+user]
   426                                   ASSUME DS:NOTHING,ES:NOTHING,SS:DOSGroup
   427 00000127 36C43E[0000]            	LES	DI,[ss:ThisSFT]
   428                                  	Assert	ISSFT,<ES,DI>,"SaveFCBInfo"
   429 0000012C E8(0000)                	invoke	IsSFTNet
   430 0000012F 740B                    	JZ	SaveLocal		; if not network then save local info
   431                                  ;
   432                                  ;----- In net support -----
   433                                  ;
   434 00000131 268B450B                	MOV	AX,WORD PTR [ES:DI + sf_serial_ID]	;AN000;;IFS.  save IFS ID
   435 00000135 89441C                  	MOV	WORD PTR [SI + FCB_netID],ax		;AN000;;IFS.
   436                                  ;	SaveReg <ES,DI>
   437                                  ;	LES	DI,DWORD PTR [ES:DI].sf_netid
   438                                  ;	MOV	WORD PTR [SI].FCB_netID,DI  ; save net ID
   439                                  ;	MOV	WORD PTR [SI].FCB_netID+2,ES
   440                                  ;	RestoreReg  <DI,ES>
   441 00000138 B380                    	MOV	BL,FCBNETWORK
   442                                  ;
   443                                  ;----- END In net support -----
   444                                  ;
   445                                  %IF debug
   446                                  	JMP	SaveSFN
   447                                  %ELSE
   448 0000013A EB4E                    	JMP	SHORT SaveSFN
   449                                  %ENDIF
   450                                  SaveLocal:
   451                                  	%IF	Installed
   452 0000013C E8(0000)                	Invoke	CheckShare
   453 0000013F 7403                    	JZ	SaveNoShare		; no sharer
   454 00000141 EB42                    	JMP	SaveShare		; sharer present
   455 00000143 90                      	nop	; identicalise
   456                                  
   457                                  SaveNoShare:
   458 00000144 26F745058000            	TEST	word [ES:DI + sf_flags],devid_device
   459 0000014A 7527                    	JNZ	SaveNoShareDev		; Device
   460                                  ;
   461                                  ; Save no sharing local file information
   462                                  ;
   463 0000014C 268B451B                	MOV	AX,WORD PTR [ES:DI + sf_dirsec] ; get directory sector F.C.
   464 00000150 89441D                  	MOV	[SI + fcb_nsl_dirsec],AX
   465 00000153 268A451F                	MOV	AL,[ES:DI + sf_dirpos]	; location in sector
   466 00000157 88441F                  	MOV	[SI + fcb_nsl_dirpos],AL
   467 0000015A 268B450B                	MOV	AX,[ES:DI + sf_firclus]	; first cluster
   468 0000015E 89441B                  	MOV	[SI + fcb_nsl_firclus],AX
   469 00000161 B300                    	MOV	BL,00
   470                                  ;
   471                                  ; Create the bits field from the dirty/device bits of the flags word and the
   472                                  ; mode byte
   473                                  ;
   474                                  SetFCBBits:
   475 00000163 268B4505                	MOV	AX,[ES:DI + sf_flags]
   476 00000167 24C0                    	AND	AL,0C0h 		; mask off drive bits
   477 00000169 260A4502                	OR	AL,BYTE PTR [ES:DI + sf_mode] ; stick in open mode
   478 0000016D 88441A                  	MOV	[SI + fcb_nsl_bits],AL	; save dirty info
   479 00000170 EB18                    	JMP	SaveSFN 		; go and save SFN
   480 00000172 90                      	nop	; identicalise
   481                                  
   482                                  ;
   483                                  ; Save no sharing local device information
   484                                  ;
   485                                  SaveNoShareDev:
   486 00000173 268B4507                	MOV	AX,WORD PTR [ES:DI + sf_devptr]
   487 00000177 89441A                  	MOV	WORD PTR [SI + FCB_nsld_drvptr],AX
   488 0000017A 268B4509                	MOV	AX,WORD PTR [ES:DI + sf_devptr + 2]
   489 0000017E 89441C                  	MOV	WORD PTR [SI + FCB_nsld_drvptr + 2],AX
   490 00000181 B340                    	MOV	BL,FCBDEVICE
   491 00000183 EBDE                    	JMP	SetFCBBits		; go and save SFN
   492                                  
   493                                  SaveShare:
   494                                  	%ENDIF
   495                                  ;
   496                                  ;----- In share support -----
   497                                  ;
   498                                  %if installed
   499 00000185 36FF1E[2800]            	Call	far [ss:JShare + 10 * 4]
   500                                  %else
   501                                  	Call	ShSave
   502                                  %endif
   503                                  ;
   504                                  ;----- end in share support -----
   505                                  ;
   506                                  SaveSFN:
   507 0000018A 268B4505                	MOV	AX,[ES:DI + sf_flags]
   508 0000018E 243F                    	AND	AL,3Fh			; get real drive
   509 00000190 08D8                    	OR	AL,BL
   510 00000192 884419                  	MOV	[SI + fcb_l_drive],AL
   511 00000195 8D45FA                  	LEA	AX,[DI-SFTable]
   512                                  ;
   513                                  ; Adjust for offset to table.
   514                                  ;
   515                                  SftFCB equ sftFCB	; NASM port label
   516 00000198 362B06[0000]            	SUB	AX,WORD PTR [ss:SftFCB]
   517 0000019D B33B                    	MOV	BL,sf_entry_struc_size
   518 0000019F F6F3                    	DIV	BL
   519 000001A1 884418                  	MOV	[SI + FCB_sfn],AL 	; last used SFN
   520 000001A4 36A1[0000]              	MOV	AX,[ss:FCBLRU]		; get lru count
   521 000001A8 40                      	INC	AX
   522 000001A9 26894515                	MOV	WORD PTR [ES:DI + sf_LRU],AX
   523 000001AD 7506                    	JNZ	SimpleStuff
   524                                  ;
   525                                  ; lru flag overflowed.	Run through all FCB sfts and adjust:  LRU < 8000h
   526                                  ; get set to 0.  Others -= 8000h.  This LRU = 8000h
   527                                  ;
   528 000001AF BB1500                  	MOV	BX, offset sf_position
   529 000001B2 E80500                  	invoke	ResetLRU
   530                                  ;
   531                                  ; Set new LRU to AX
   532                                  ;
   533                                  SimpleStuff:
   534 000001B5 36A3[0000]              	MOV	[ss:FCBLRU],AX
   535 000001B9 C3                      	return
   536                                  EndProc SaveFCBInfo
   537                                  
   538                                  Break	<ResetLRU - reset overflowed lru counts>
   539                                  
   540                                  ;
   541                                  ;   ResetLRU - during lru updates, we may wrap at 64K.	We must walk the
   542                                  ;   entire set of SFTs and subtract 8000h from their lru counts and truncate
   543                                  ;   at 0.
   544                                  ;
   545                                  ;   Inputs:	BX is offset into SFT field where lru firld is kept
   546                                  ;		ES:DI point to SFT currently being updated
   547                                  ;   Outputs:	All FCB SFTs have their lru fields truncated
   548                                  ;		AX has 8000h
   549                                  ;   Registers modified: none
   550                                  
   551                                  Procedure   ResetLRU,NEAR
   551          ******************       warning: proc ResetLRU... [-w+user]
   552                                   ASSUME DS:NOTHING,ES:NOTHING,SS:DOSGROUP
   553                                  	Assert	ISSFT,<ES,DI>,"ResetLRU"
   554 000001BA B80080                  	MOV	AX,8000h
   555 000001BD 0657                    	SaveReg <ES,DI>
   556 000001BF 36C43E[0000]            	LES	DI,[ss:sftFCB]		; get pointer to head
   557                                  sfCount equ SFCount	; NASM port label
   558 000001C4 268B4D04                	MOV	CX,[ES:DI + sfCount]
   559                                  sfTable equ SFTable	; NASM port label
   560 000001C8 8D7D06                  	LEA	DI,[DI + sfTable] 	; point at table
   561                                  ovScan:
   562 000001CB 262901                  	SUB	WORD PTR [ES:DI+BX],AX	; decrement lru count
   563 000001CE 7703                    	JA	ovLoop
   564 000001D0 268901                  	MOV	WORD PTR [ES:DI + BX],AX	; truncate at 0
   565                                  ovLoop:
   566                                  SF_Entry_struc_size equ sf_entry_struc_size	; NASM port equate
   567 000001D3 83C73B                  	ADD	DI,SF_Entry_struc_size	; advance to next
   568 000001D6 E2F3                    	LOOP	ovScan
   569 000001D8 5F07                    	RestoreReg  <DI,ES>
   570 000001DA 268901                  	MOV	[ES:DI+BX],AX
   571 000001DD C3                      	return
   572                                  EndProc ResetLRU
   573                                  
   574                                  Break	<SetOpenAge - update the open age of a SFT>
   575                                  
   576                                  ;
   577                                  ;   SetOpenAge - In order to maintain the first N open files in the FCB cache,
   578                                  ;   we keep the 'open age' or an LRU count based on opens.  We update the
   579                                  ;   count here and fill in the appropriate field.
   580                                  ;
   581                                  ;   Inputs:	ES:DI point to SFT
   582                                  ;   Outputs:	ES:DI has the open age field filled in.
   583                                  ;		If open age has wraparound, we will have subtracted 8000h
   584                                  ;		    from all open ages.
   585                                  ;   Registers modified: AX
   586                                  ;
   587                                  
   588                                  Procedure   SetOpenAge,NEAR
   588          ******************       warning: proc SetOpenAge... [-w+user]
   589                                   ASSUME DS:NOTHING,ES:NOTHING,SS:DOSGROUP
   590                                  	Assert	ISSFT,<ES,DI>,"SetOpenAge"
   591 000001DE 36A1[0000]              	MOV	AX,[ss:OpenLRU]
   592 000001E2 40                      	INC	AX
   593 000001E3 26894517                	MOV	[ES:DI + sf_OpenAge],AX
   594 000001E7 7506                    	JNZ	SetDone
   595                                  sf_Position equ sf_position	; NASM port label
   596 000001E9 BB1700                  	MOV	BX, offset sf_Position+2
   597 000001EC E8CBFF                  	invoke	ResetLRU
   598                                  SetDone:
   599 000001EF 36A3[0000]              	MOV	[ss:OpenLRU],AX
   600 000001F3 C3                      	return
   601                                  EndProc SetOpenAge
   602                                  
   603                                  Break	<LRUFCB - perform LRU on FCB sfts>
   604                                  
   605                                  ;
   606                                  ;   LRUFCB - find LRU fcb in cache.  Set ThisSFT and return it.  We preserve
   607                                  ;	the first keepcount sfts if they are network sfts or if sharing is
   608                                  ;	loaded.  If carry is set then NO BLASTING is NECESSARY.
   609                                  ;
   610                                  ;   Inputs:	none
   611                                  ;   Outputs:	ES:DI point to SFT
   612                                  ;		ThisSFT points to SFT
   613                                  ;		SFT is zeroed
   614                                  ;		Carry set of closes failed
   615                                  ;   Registers modified: none
   616                                  ;
   617                                  
   618                                  Procedure   LRUFCB,NEAR
   618          ******************       warning: proc LRUFCB... [-w+user]
   619                                   ASSUME DS:NOTHING,ES:NOTHING,SS:DOSGROUP
   620 000001F4 E8(0000)                	Invoke	Save_World
   621                                  ;
   622                                  ; Find nth oldest NET/SHARE FCB.  We want to find its age for the second scan
   623                                  ; to find the lease recently used one that is younger than the open age.  We
   624                                  ; operate be scanning the list n times finding the least age that is greater
   625                                  ; or equal to the previous minimum age.
   626                                  ;
   627                                  ;   BP is the count of times we need to go through this loop.
   628                                  ;   AX is the current acceptable minimum age to consider
   629                                  ;
   630 000001F7 368B2E[0000]            	mov	bp,[ss:KeepCount]		; k = keepcount;
   631 000001FC 31C0                    	XOR	AX,AX			; low = 0;
   632                                  ;
   633                                  ; If we've scanned the table n times, then we are done.
   634                                  ;
   635                                  lru1:
   636 000001FE 83FD00                  	CMP	bp,0			; while (k--) {
   637 00000201 7452                    	JZ	lru75
   638 00000203 4D                      	DEC	bp
   639                                  ;
   640                                  ; Set up for scan.
   641                                  ;
   642                                  ;   AX is the minimum age for consideration
   643                                  ;   BX is the minimum age found during the scan
   644                                  ;   SI is the position of the entry that corresponds to BX
   645                                  ;
   646 00000204 BBFFFF                  	MOV	BX,-1			;     min = 0xffff;
   647 00000207 89DE                    	MOV	si,BX			;     pos = 0xffff;
   648                                  SFTFCB equ sftFCB	; NASM port label
   649 00000209 36C43E[0000]            	LES	DI,[ss:SFTFCB]		;     for (CX=FCBCount; CX>0; CX--)
   650 0000020E 268B4D04                	MOV	CX,[ES:DI + sfCount]
   651 00000212 8D7D06                  	LEA	DI,[DI + sfTable]
   652                                  ;
   653                                  ; Innermost loop.  If the current entry is free, then we are done.  Or, if the
   654                                  ; current entry is busy (indicating a previous aborted allocation), then we
   655                                  ; are done.  In both cases, we use the found entry.
   656                                  ;
   657                                  lru2:
   658 00000215 26833D00                	cmp	word [es:di + sf_ref_count],0
   659 00000219 7406                    	jz	lru25
   660 0000021B 26833DFF                	cmp	word [es:di + sf_ref_count],sf_busy
   661 0000021F 7505                    	jnz	lru3
   662                                  ;
   663                                  ; The entry is usable without further scan.  Go and use it.
   664                                  ;
   665                                  lru25:
   666 00000221 89FE                    	MOV	si,DI			;	      pos = i;
   667 00000223 EB6A                    	JMP	lru11			;	      goto got;
   668 00000225 90                      	nop	; identicalise
   669                                  ;
   670                                  ; See if the entry is for the network or for the sharer.
   671                                  ;
   672                                  ;  If for the sharer or network then
   673                                  ;	if the age < current minimum AND >= allowed minimum then
   674                                  ;	    this entry becomes current minimum
   675                                  ;
   676                                  lru3:
   677 00000226 26F745050080            	TEST	word [ES:DI + sf_flags],sf_isnet   ;	  if (!net[i]
   678 0000022C 7505                    	JNZ	lru35
   679                                  %if installed
   680 0000022E E8(0000)                	Invoke	CheckShare		;		&& !sharing)
   681 00000231 7410                    	JZ	lru5			;	  else
   682                                  %ENDIF
   683                                  ;
   684                                  ; This SFT is for the net or is for the sharer.  See if it less than the
   685                                  ; current minimum.
   686                                  ;
   687                                  lru35:
   688 00000233 268B5517                	MOV	DX,[ES:DI + sf_OpenAge]
   689 00000237 39C2                    	CMP	DX,AX			;	  if (age[i] >= low &&
   690 00000239 7208                    	JB	lru5
   691 0000023B 39DA                    	CMP	DX,BX
   692 0000023D 7304                    	JAE	lru5			;	      age[i] < min) {
   693                                  ;
   694                                  ; entry is new minimum.  Remember his age.
   695                                  ;
   696 0000023F 89D3                    	mov	bx,DX			;	      min = age[i];
   697 00000241 89FE                    	mov	si,di			;	      pos = i;
   698                                  ;
   699                                  ; End of loop.	gp back for more
   700                                  ;
   701                                  lru5:
   702 00000243 83C73B                  add	di,sf_entry_struc_size
   703 00000246 E2CD                    	loop	lru2			;	      }
   704                                  ;
   705                                  ; The scan is complete.  If we have successfully found a new minimum (pos != -1)
   706                                  ; set then threshold value to this new minimum + 1.  Otherwise, the scan is
   707                                  ; complete.  Go find LRU.
   708                                  ;
   709 00000248 83FEFF                  lru6:	cmp	si,-1			; position not -1?
   710 0000024B 7408                    	jz	lru75			; no, done with everything
   711 0000024D 8D4701                  	lea	ax,[bx+1]		; set new threshold age
   712 00000250 EBAC                    	jmp	lru1			; go and loop for more
   713 00000252 F9                      lru65:	stc
   714                                  lruDead equ LRUDead	; NASM port label
   715 00000253 EB70                    	jmp	short	lruDead 	;	  return -1;
   716                                  ;
   717                                  ; Main loop is done.  We have AX being the age+1 of the nth oldest sharer or
   718                                  ; network entry.  We now make a second pass through to find the LRU entry
   719                                  ; that is local-no-share or has age >= AX
   720                                  ;
   721                                  lru75:
   722 00000255 BBFFFF                  	mov	bx,-1			; min = 0xffff;
   723 00000258 89DE                    	mov	si,bx			; pos = 0xffff;
   724 0000025A 36C43E[0000]            	LES	DI,[ss:SFTFCB]		; for (CX=FCBCount; CX>0; CX--)
   725 0000025F 268B4D04                	MOV	CX,[ES:DI + sfCount]
   726 00000263 8D7D06                  	LEA	DI,[DI + sfTable]
   727                                  ;
   728                                  ; If this is is local-no-share then go check for LRU else if age >= threshold
   729                                  ; then check for lru.
   730                                  ;
   731                                  lru8:
   732 00000266 26F745050080            	TEST	word [ES:DI + sf_flags],sf_isnet
   733 0000026C 7505                    	jnz	lru85			; is for network, go check age
   734 0000026E E8(0000)                	invoke	CheckShare		; sharer here?
   735 00000271 7406                    	jz	lru86			; no, go check lru
   736                                  ;
   737                                  ; Network or sharer.  Check age
   738                                  ;
   739                                  lru85:
   740 00000273 26394517                	cmp	[es:di + sf_OpenAge],ax
   741 00000277 720C                    	jb	lru9			; age is before threshold, skip it
   742                                  ;
   743                                  ; Check LRU
   744                                  ;
   745                                  lru86:
   746 00000279 26395D15                	cmp	[es:di + sf_LRU],bx	; is LRU less than current LRU?
   747 0000027D 7306                    	jae	lru9			; no, skip this
   748 0000027F 89FE                    	mov	si,di			; remember position
   749 00000281 268B5D15                	mov	bx,[es:di + sf_LRU]	; remember new minimum LRU
   750                                  ;
   751                                  ; Done with this entry, go back for more.
   752                                  ;
   753                                  lru9:
   754 00000285 83C73B                  	add	di,sf_entry_struc_size
   755 00000288 E2DC                    	loop	lru8
   756                                  ;
   757                                  ; Scan is complete.  If we found NOTHING that satisfied us then we bomb
   758                                  ; out.	The conditions here are:
   759                                  ;
   760                                  ;   No local-no-shares AND all net/share entries are older than threshold
   761                                  ;
   762                                  lru10:
   763 0000028A 83FEFF                  	cmp	si,-1			; if no one f
   764 0000028D 74C3                    	jz	lru65			;     return -1;
   765                                  lru11:
   766 0000028F 89F7                    	mov	di,si
   767 00000291 36893E[0000]            	MOV	WORD PTR [ss:ThisSFT],DI	; set thissft
   768 00000296 368C06[0200]            	MOV	WORD PTR [ss:ThisSFT+2],ES
   769                                  ;
   770                                  ; If we have sharing or thisSFT is a net sft, then close it until ref count
   771                                  ; is 0.
   772                                  ;
   773                                  sf_isNet equ sf_isnet	; NASM port equate
   774 0000029B 26F745050080            	TEST	word [ES:DI + sf_flags],sf_isNet
   775 000002A1 7505                    	JNZ	LRUClose
   776                                  %IF INSTALLED
   777 000002A3 E8(0000)                	Invoke	CheckShare
   778 000002A6 7418                    	JZ	LRUDone
   779                                  %ENDIF
   780                                  ;
   781                                  ; Repeat close until ref count is 0
   782                                  ;
   783                                  LRUClose:
   784 000002A8 161F                    	Context DS
   785 000002AA C43E[0000]              	LES	DI,[ThisSFT]
   786 000002AE 26833D00                	CMP	word [ES:DI + sf_ref_count],0	; is ref count still <> 0?
   787 000002B2 740C                    	JZ	LRUDone 		; nope, all done
   788                                  
   789                                  ;	Message     1,"LRUFCB: closing "
   790                                  ;	MessageNum  <WORD PTR THISSFT+2>
   791                                  ;	Message     1,":"
   792                                  ;	MessageNum  <WORD PTR THISSFT>
   793                                  
   794 000002B4 E8(0000)                	Invoke	DOS_Close
   795 000002B7 73EF                    	jnc	LRUClose		; no error => clean up
   796 000002B9 3C06                    	cmp	al,error_invalid_handle
   797 000002BB 74EB                    	jz	LRUClose
   798 000002BD F9                      	stc
   799 000002BE EB05                    	JMP	short LRUDead
   800                                  LRUDone:
   801 000002C0 30C0                    	XOR	AL,AL
   802 000002C2 E8ED00                  	invoke	BlastSFT		; fill SFT with 0 (AL)
   803                                  LRUDead:
   804 000002C5 E8(0000)                	Invoke	Restore_World
   805                                  	ASSUME	DS:NOTHING
   806 000002C8 36C43E[0000]            	LES	DI,[ss:ThisSFT]
   807                                  	Assert	ISSFT,<ES,DI>,"LRUFCB return"
   808 000002CD 7201C3                  	retnc
   809 000002D0 B023                    	MOV	AL,error_FCB_unavailable
   810 000002D2 C3                      	return
   811                                  EndProc LRUFCB
   812                                  
   813                                  Break	<FCBRegen - regenerate a sft from the info in the FCB>
   814                                  
   815                                  ;
   816                                  ;   FCBRegen - examine reserved field of FCB and attempt to generate the SFT
   817                                  ;	from it.
   818                                  ;
   819                                  ;   Inputs:	DS:SI point to FCB
   820                                  ;   Outputs:	carry clear Filled in SFT
   821                                  ;		Carry set unrecoverable error
   822                                  ;   Registers modified: all
   823                                  
   824                                  Procedure   FCBRegen,NEAR
   824          ******************       warning: proc FCBRegen... [-w+user]
   825                                  	ASSUME	DS:NOTHING,ES:NOTHING, ss:DOSGROUP
   826                                  ;
   827                                  ; General data filling.  Mode is sf_isFCB + open_for_both, date/time we do
   828                                  ; not fill, size we do no fill, position we do not fill,
   829                                  ; bit 14 of flags = TRUE, other bits = FALSE
   830                                  ;
   831 000002D3 8A4419                  	MOV	AL,[SI + fcb_l_drive]
   832                                  ;
   833                                  ; We discriminate based on the first two bits in the reserved field.
   834                                  ;
   835 000002D6 A880                    	TEST	AL,FCBSPECIAL		; check for no sharing test
   836 000002D8 741C                    	JZ	RegenNoSharing		; yes, go regen from no sharing
   837                                  ;
   838                                  ; The FCB is for a network or a sharing based system.  At this point we have
   839                                  ; already closed the SFT for this guy and reconnection is impossible.
   840                                  ;
   841                                  ; Remember that he may have given us a FCB with bogus information in it.
   842                                  ; Check to see if sharing is present or if the redir is present.  If either is
   843                                  ; around, presume that we have cycled out the FCB and give the hard error.
   844                                  ; Otherwise, just return with carry set.
   845                                  ;
   846 000002DA E8(0000)                	invoke	CheckShare		; test for sharer
   847 000002DD 7509                    	JNZ	RegenFail		; yep, fail this.
   848                                  multNet equ MultNET	; NASM port equate
   849 000002DF B80011                  	MOV	AX,multNet << 8	; install check on multnet
   850 000002E2 CD2F                    	INT	2FH
   851 000002E4 08C0                    	OR	AL,AL			; is it there?
   852 000002E6 740C                    	JZ	RegenDead		; no, just fail the operation
   853                                  RegenFail:
   854 000002E8 36A1[0000]              	MOV	AX,[ss:User_In_AX]
   855                                  fcb_close equ FCB_Close	; NASM port equate
   856 000002EC 80FC10                  	cmp	AH,fcb_close
   857 000002EF 7403                    	jz	RegenDead
   858 000002F1 E8C501                  	invoke	FCBHardErr		; massive hard error.
   859                                  RegenDead:
   860 000002F4 F9                      	STC
   861 000002F5 C3                      	return				; carry set
   862                                  ;
   863                                  ; Local FCB without sharing.  Check to see if sharing is loaded.  If so
   864                                  ; fail the operation.
   865                                  ;
   866                                  RegenNoSharing:
   867 000002F6 E8(0000)                	invoke	CheckShare		; Sharing around?
   868 000002F9 75ED                    	JNZ	RegenFail
   869                                  ;
   870                                  ; Find an SFT for this guy.
   871                                  ;
   872 000002FB E8(0000)                	invoke	LRUFcb
   873 000002FE 72F5                    	retc
   874                                  SF_IsFCB equ sf_isfcb	; NASM port equate
   875 00000300 26C745020280            	MOV	word [ES:DI + sf_mode],SF_IsFCB + open_for_both + sharing_compat
   876 00000306 243F                    	AND	AL,3Fh			; get drive number for flags
   877 00000308 98                      	CBW
   878                                  sf_close_noDate equ sf_close_nodate	; NASM port equate
   879 00000309 0D0040                  	OR	AX,sf_close_noDate	; normal FCB operation
   880                                  ;
   881                                  ; The bits field consists of the upper two bits (dirty and device) from the
   882                                  ; SFT and the low 4 bits from the open mode.
   883                                  ;
   884 0000030C 8A4C1A                  	MOV	CL,[SI + FCB_nsl_bits]	; stick in dirty bits.
   885 0000030F 88CD                    	MOV	CH,CL
   886 00000311 80E5C0                  	AND	CH,0C0h 		; mask off the dirty/device bits
   887 00000314 08E8                    	OR	AL,CH
   888 00000316 80E10F                  	AND	CL,access_mask		; get the mode bits
   889 00000319 26884D02                	MOV	BYTE PTR [ES:DI + sf_mode],CL
   890 0000031D 26894505                	MOV	[ES:DI + sf_flags],AX	; initial flags
   891 00000321 36A1[0000]              	MOV	AX,[ss:Proc_ID]
   892 00000325 26894531                	MOV	[ES:DI + sf_PID],AX
   893 00000329 1E560657                	SaveReg <DS,SI,ES,DI>
   894 0000032D 1607                    	Context ES
   895 0000032F BF[0000]                	MOV	DI,OFFSET Name1 wrt DOSGroup
   896 00000332 B90800                  	MOV	CX,8
   897 00000335 46                      	INC	SI			; Skip past drive byte to name in FCB
   898                                  RegenCopyName2:
   899 00000336 AC                      	LODSB
   900                                  
   901                                   %IF  DBCS				;AN000;
   902                                  	invoke	testkanj		;AN000;
   903                                  	jz	notkanj9		;AN000;
   904                                  	STOSB				;AN000;
   905                                  	DEC	CX			;AN000;
   906                                  	JCXZ	DoneNam2		;AN000; ; Ignore split kanji char error
   907                                  	LODSB				;AN000;
   908                                  	jmp	short StuffChar2	;AN000;
   909                                  					;AN000;
   910                                  notkanj9:				;AN000;
   911                                   %ENDIF					;AN000;
   912                                  
   913 00000337 E8(0000)                	Invoke	UCase
   914                                  StuffChar2:
   915 0000033A AA                      	STOSB
   916 0000033B E2F9                    	LOOP	RegenCopyName2
   917                                  DoneNam2:
   918 0000033D 161F                    	Context DS
   919                                  ATTRIB equ Attrib	; NASM port label
   920 0000033F C606[0000]16            	MOV	byte [ATTRIB],attr_hidden + attr_system + attr_directory
   921                                  					; Must set this to something interesting
   922                                  					; to call DEVNAME.
   923 00000344 E8(0000)                	Invoke	DevName 		; check for device
   924                                  	ASSUME	DS:NOTHING,ES:NOTHING
   925 00000347 5F075E1F                	RestoreReg  <DI,ES,SI,DS>
   926 0000034B 7219                    	JC	RegenFileNoSharing	; not found on device list => file
   927                                  ;
   928                                  ; Device found.  We can ignore disk-specific info
   929                                  ;
   930 0000034D 26887D05                	MOV	BYTE PTR [ES:DI + sf_flags],BH   ; device parms
   931 00000351 26C6450400              	MOV	byte [ES:DI + sf_attr],0	; attribute
   932 00000356 36C536[0000]            	LDS	SI,[ss:DEVPT]		; get device driver
   933 0000035B 26897507                	MOV	WORD PTR [ES:DI + sf_devptr],SI
   934 0000035F 268C5D09                	MOV	WORD PTR [ES:DI + sf_devptr + 2],DS
   935 00000363 C3                      	return				; carry is clear
   936                                  
   937                                  RegenDeadJ:
   938 00000364 EB8E                    	JMP	RegenDead
   939                                  ;
   940                                  ; File found.  Just copy in the remaining pieces.
   941                                  ;
   942                                  RegenFileNoSharing:
   943 00000366 268B4505                	MOV	AX,[ES:DI + sf_flags]
   944 0000036A 83E03F                  	AND	AX,03Fh
   945 0000036D 1E56                    	SaveReg <DS,SI>
   946 0000036F E8(0000)                	Invoke	Find_DPB
   947 00000372 26897507                	MOV	WORD PTR [ES:DI + sf_devptr],SI
   948 00000376 268C5D09                	MOV	WORD PTR [ES:DI + sf_devptr + 2],DS
   949 0000037A 5E1F                    	RestoreReg  <SI,DS>
   950 0000037C 72E6                    	jc	RegenDeadJ		; if find DPB fails, then drive
   951                                  					; indicator was bogus
   952 0000037E 8B441D                  	MOV	AX,[SI + FCB_nsl_dirsec]
   953 00000381 2689451B                	MOV	WORD PTR [ES:DI + sf_dirsec],AX
   954 00000385 26C7451D0000            	MOV	WORD PTR [ES:DI + sf_dirsec + 2],0	;AN000;>32mb
   955 0000038B 8B441B                  	MOV	AX,[SI + FCB_nsl_firclus]
   956 0000038E 2689450B                	MOV	[ES:DI + sf_firclus],AX
   957 00000392 26894535                	MOV	[ES:DI + sf_lstclus],AX
   958 00000396 8A441F                  	MOV	AL,[SI + FCB_nsl_dirpos]
   959 00000399 2688451F                	MOV	[ES:DI + sf_dirpos],AL
   960 0000039D 26FF05                  	INC	word [ES:DI + sf_ref_count]	; Increment reference count.
   961                                  					; Existing FCB entries would be
   962                                  					; flushed unnecessarily because of
   963                                  					; check in CheckFCB of the ref_count.
   964                                  					; July 22/85 - BAS
   965                                  FCB_name equ fcb_name	; NASM port label
   966 000003A0 8D7401                  	LEA	SI,[SI + FCB_name]
   967 000003A3 8D7D20                  	LEA	DI,[DI + sf_name]
   968                                  fcb_extent equ fcb_EXTENT	; NASM port label
   969 000003A6 B90B00                  	MOV	CX,fcb_extent-fcb_name
   970                                  RegenCopyName:
   971 000003A9 AC                      	LODSB
   972                                  
   973                                  	%IF	DBCS			;AN000;
   974                                  	invoke	testkanj
   975                                  	jz	notkanj1
   976                                  	STOSB
   977                                  	DEC	CX
   978                                  	JCXZ	DoneNam 		; Ignore split kanji char error
   979                                  	LODSB
   980                                  	jmp	short StuffChar
   981                                  
   982                                  notkanj1:
   983                                  	%ENDIF				;AN000;
   984                                  
   985 000003AA E8(0000)                	Invoke	UCase
   986                                  StuffChar:
   987 000003AD AA                      	STOSB
   988 000003AE E2F9                    	LOOP	RegenCopyName
   989                                  DoneNam:
   990 000003B0 F8                      	clc
   991 000003B1 C3                      	return
   992                                  EndProc FCBRegen
   993                                  
   994                                  ;
   995                                  ;   BlastSFT - fill SFT with garbage
   996                                  ;
   997                                  ;   Inputs: ES:DI point to SFT
   998                                  ;	    AL has fill
   999                                  ;   Outputs: SFT is filled with nonsense
  1000                                  ;	    *FLAGS PRESERVED*
  1001                                  ;   Registers modified: CX
  1002                                  
  1003                                  Procedure   BlastSFT,NEAR
  1003          ******************       warning: proc BlastSFT... [-w+user]
  1004 000003B2 57                      	SaveReg <DI>
  1005 000003B3 B93B00                  	MOV	CX,sf_entry_struc_size
  1006 000003B6 F3AA                    	REP	STOSB
  1007 000003B8 5F                      	RestoreReg  <DI>
  1008 000003B9 26C7050000              	MOV	word [ES:DI + sf_ref_count],0	; set ref count
  1009 000003BE 26C745150000            	MOV	word [ES:DI + sf_LRU],0	; set lru
  1010 000003C4 26C74517FFFF            	MOV	word [ES:DI + sf_OpenAge],-1	; Set open age
  1011 000003CA C3                      	return
  1012                                  EndProc BlastSFT
  1013                                  
  1014                                  Break	<CheckFCB - see if the SFT pointed to by the FCB is still OK>
  1015                                  
  1016                                  ;   CheckFCB - examine an FCB and its contents to see if it needs to be
  1017                                  ;   regenerated.
  1018                                  ;
  1019                                  ;   Inputs:	DS:SI point to FCB (not extended)
  1020                                  ;		AL is SFT index
  1021                                  ;   Outputs:	Carry Set - FCB needs to be regened
  1022                                  ;		Carry clear - FCB is OK. ES:DI point to SFT
  1023                                  ;   Registers modified: AX and BX
  1024                                  
  1025                                  Procedure   CheckFCB,NEAR
  1025          ******************       warning: proc CheckFCB... [-w+user]
  1026                                  	ASSUME DS:NOTHING,ES:NOTHING
  1027 000003CB 36C43E[0000]            	LES	DI,[ss:sftFCB]
  1028 000003D0 26384504                	CMP	BYTE PTR [ES:DI + SFCount],AL
  1029 000003D4 7244                    	JC	BadSFT
  1030 000003D6 B33B                    	MOV	BL,sf_entry_struc_size
  1031 000003D8 F6E3                    	MUL	BL
  1032                                  sftable equ SFTable	; NASM port label
  1033 000003DA 8D7D06                  	LEA	DI,[DI + sftable]
  1034 000003DD 01C7                    	ADD	DI,AX
  1035 000003DF 36A1[0000]              	MOV	AX,[ss:Proc_ID]
  1036 000003E3 26394531                	CMP	[ES:DI + sf_PID],AX
  1037 000003E7 7531                    	JNZ	BadSFT			; must match process
  1038 000003E9 26833D00                	CMP	word [ES:DI + sf_ref_count],0
  1039 000003ED 742B                    	JZ	BadSFT			; must also be in use
  1040 000003EF 8A4419                  	MOV	AL,[SI + FCB_l_Drive]
  1041 000003F2 A880                    	TEST	AL,FCBSPECIAL		; a special FCB?
  1042 000003F4 7430                    	JZ	CheckNoShare		; No. try local or device
  1043                                  ;
  1044                                  ; Since we are a special FCB, try NOT to use a bogus test instruction.
  1045                                  ; FCBSHARE is a superset of FCBNETWORK.
  1046                                  ;
  1047 000003F6 50                      	PUSH	AX
  1048 000003F7 24C0                    	AND	AL,FCBMASK
  1049 000003F9 3CC0                    	CMP	AL,FCBSHARE		; net FCB?
  1050 000003FB 58                      	POP	AX
  1051 000003FC 751E                    	JNZ	CheckNet		; yes
  1052                                  ;
  1053                                  ;----- In share support -----
  1054                                  ;
  1055                                  %if installed
  1056 000003FE 36FF1E[2C00]            	Call	far [ss:JShare + 11 * 4]
  1057                                  %else
  1058                                  	Call	ShChk
  1059                                  %endif
  1060 00000403 7215                    	JC	BadSFT
  1061 00000405 EB06                    	JMP	SHORT CheckD
  1062                                  ;
  1063                                  ;----- End in share support -----
  1064                                  ;
  1065                                  CheckFirClus:
  1066 00000407 263B5D0B                	CMP	BX,[ES:DI + sf_firclus]
  1067 0000040B 750D                    	JNZ	BadSFT
  1068 0000040D 243F                    CheckD: AND	AL,3Fh
  1069 0000040F 268A6505                	MOV	AH,BYTE PTR [ES:DI + sf_flags]
  1070 00000413 80E43F                  	AND	AH,3Fh
  1071 00000416 38C4                    	CMP	AH,AL
  1072 00000418 74B0                    	retz				; carry is clear
  1073 0000041A F9                      BadSFT: STC
  1074 0000041B C3                      	return				; carry is clear
  1075                                  CheckNet:
  1076                                  ;
  1077                                  ;----- In net support -----
  1078                                  ;
  1079                                  ;	MOV	AX,[SI].FCB_net_handle
  1080                                  ;	CMP	AX,WORD PTR [ES:DI].sf_NETID+4
  1081                                  ;	JNZ	BadSFT
  1082                                  ;	MOV	AX,WORD PTR [SI].FCB_netID
  1083                                  ;	CMP	AX,WORD PTR [ES:DI].sf_netid
  1084                                  ;	JNZ	BadSFT
  1085 0000041C 8B441C                  	MOV	AX,WORD PTR [SI + FCB_netID]	  ;AN000;IFS.DOS 4.00
  1086 0000041F 263B450B                	CMP	AX,WORD PTR [ES:DI + sf_serial_ID]  ;AN000;IFS.DOS 4.00
  1087 00000423 75F5                    	JNZ	BadSFT
  1088                                  ;
  1089                                  ;----- END In net support -----
  1090                                  ;
  1091 00000425 C3                      	return
  1092                                  
  1093                                  CheckNoShare:
  1094 00000426 A840                    	TEST	AL,FCBDEVICE		; Device?
  1095 00000428 7546                    	JNZ	CheckNoShareDev 	; Yes
  1096                                  ;
  1097                                  ; Check no sharing local file
  1098                                  ;
  1099 0000042A 8B5C1D                  	MOV	BX,[SI + FCB_nsl_Dirsec]
  1100 0000042D 26837D1D00              	CMP	WORD PTR [ES:DI + sf_dirsec + 2],0	;AN000;F.C. >32mb
  1101                                  BadSFt equ BadSFT	; NASM port label
  1102 00000432 75E6                    	JNZ	BadSFt				;AN000;F.C. >32mb
  1103                                  
  1104 00000434 263B5D1B                	CMP	BX,WORD PTR [ES:DI + sf_dirsec]	;AN000;F.C. >32mb
  1105 00000438 75E0                    	JNZ	BadSFT
  1106 0000043A 8A5C1F                  	MOV	BL,[SI + FCB_nsl_Dirpos]
  1107 0000043D 263A5D1F                	CMP	BL,[ES:DI + sf_dirpos]
  1108 00000441 75D7                    	JNZ	BadSFt
  1109                                  ;
  1110                                  ; Since the bits field comes from two different spots, compare them separately.
  1111                                  ;
  1112 00000443 8A5C1A                  	MOV	BL,[SI + FCB_nsl_bits]
  1113 00000446 268A7D05                	MOV	BH,BYTE PTR [ES:DI + sf_flags]
  1114 0000044A 30DF                    	XOR	BH,BL
  1115 0000044C 80E7C0                  	AND	BH,0C0h
  1116 0000044F 75C9                    	JNZ	BadSFT			; dirty/device bits are different
  1117 00000451 26325D02                	XOR	BL,BYTE PTR [ES:DI + sf_mode]
  1118 00000455 80E30F                  	AND	BL,access_mask
  1119 00000458 75C0                    	JNZ	BadSFT			; access modes are different
  1120                                  ; Make sure that the names are the same in the FCB and the SFT
  1121                                  ; This case can appear under the following scenario:
  1122                                  ;		Create	FOO
  1123                                  ;		Rename	FOO -> BAR
  1124                                  ;		Open	BAR
  1125                                  ; The SFT will still contain the name for the old file name.
  1126                                  ; July 30/85 - BAS
  1127 0000045A 57                      	PUSH	DI
  1128 0000045B 56                      	PUSH	SI
  1129 0000045C 8D7D20                  	LEA	DI,[DI + sf_name]
  1130 0000045F 8D7401                  	LEA	SI,[SI + fcb_name]
  1131 00000462 B90B00                  	MOV	CX,11
  1132 00000465 F3A6                    	REPE	CMPSB
  1133 00000467 5E                      	POP	SI
  1134 00000468 5F                      	POP	DI
  1135 00000469 75AF                    	JNZ	BadSFT
  1136 0000046B 8B5C1B                  	MOV	BX,[SI + FCB_nsl_firclus]
  1137 0000046E EB97                    	JMP	CheckFirClus
  1138                                  
  1139                                  CheckNoShareDev:
  1140 00000470 8B5C1A                  	MOV	BX,WORD PTR [SI + FCB_nsld_drvptr]
  1141 00000473 263B5D07                	CMP	BX,WORD PTR [ES:DI + sf_devptr]
  1142 00000477 75A1                    	JNZ	BadSFT
  1143 00000479 8B5C1C                  	MOV	BX,WORD PTR [SI + FCB_nsld_drvptr + 2]
  1144 0000047C 263B5D09                	CMP	BX,WORD PTR [ES:DI + sf_devptr + 2]
  1145 00000480 7598                    	JNZ	BadSFT
  1146 00000482 EB89                    	JMP	CheckD
  1147                                  
  1148                                  EndProc CheckFCB
  1149                                  
  1150                                  Break	<SFTFromFCB - take a FCB and obtain a SFT from it>
  1151                                  
  1152                                  ;
  1153                                  ;   SFTFromFCB - the workhorse of this compatability crap.  Check to see if
  1154                                  ;	the SFT for the FCB is Good.  If so, make ThisSFT point to it.	If not
  1155                                  ;	good, get one from the cache and regenerate it.  Overlay the LRU field
  1156                                  ;	with PID
  1157                                  ;
  1158                                  ;   Inputs:	DS:SI point to FCB
  1159                                  ;   Outputs:	ThisSFT point to appropriate SFT
  1160                                  ;		Carry clear -> OK ES:DI -> SFT
  1161                                  ;		Carry set -> error in ax
  1162                                  ;   Registers modified: ES,DI, AX
  1163                                  
  1164                                  Procedure   SFTFromFCB,NEAR
  1164          ******************       warning: proc SFTFromFCB... [-w+user]
  1165                                  	ASSUME	DS:NOTHING,ES:NOTHING
  1166 00000484 5053                    	SaveReg <AX,BX>
  1167 00000486 8A4418                  	MOV	AL,[SI + fcb_sfn] 	; set SFN for check
  1168 00000489 E83FFF                  	invoke	CheckFCB
  1169 0000048C 5B58                    	RestoreReg  <BX,AX>
  1170 0000048E 36893E[0000]            	MOV	WORD PTR [ss:ThisSFT],DI	; set thissft
  1171 00000493 368C06[0200]            	MOV	WORD PTR [ss:ThisSFT+2],ES
  1172 00000498 7310                    	JNC	SetSFT			; no problems, just set thissft
  1173                                  
  1174                                  	fmt	typFCB,LevCheck,<"FCB $x:$x does not match SFT $x:$x\n">,<DS,SI,ES,DI>
  1175                                  
  1176 0000049A E8(0000)                	Invoke	Save_World
  1177 0000049D E833FE                  	invoke	FCBRegen
  1178 000004A0 E8(0000)                	Invoke	Restore_World		; restore world
  1179 000004A3 36A1[0000]              	MOV	AX,[ss:EXTERR]
  1180 000004A7 7301C3                  	retc
  1181                                  
  1182                                  ;	Message 1,<"FCBRegen Succeeded",13,10>
  1183                                  
  1184 000004AA 36C43E[0000]            SetSFT: LES	DI,[ss:ThisSFT]
  1185 000004AF 36FF36[0000]            	PUSH	word [ss:Proc_ID] 		; set process id
  1186 000004B4 268F4531                	POP	word [ES:DI + sf_PID]
  1187 000004B8 C3                      	return				; carry is clear
  1188                                  EndProc SFTFromFCB
  1189                                  
  1190                                  Break	<FCBHardErr - generate INT 24 for hard errors on FCBS>
  1191                                  
  1192                                  ;
  1193                                  ;   FCBHardErr - signal to a user app that he is trying to use an
  1194                                  ;	unavailable FCB.
  1195                                  ;
  1196                                  ;   Inputs:	none.
  1197                                  ;   Outputs:	none.
  1198                                  ;   Registers modified: all
  1199                                  ;
  1200                                  
  1201                                  Procedure   FCBHardErr,NEAR
  1201          ******************       warning: proc FCBHardErr... [-w+user]
  1202                                  	ASSUME	DS:NOTHING,ES:NOTHING
  1203                                  error_FCB_Unavailable equ error_FCB_unavailable	; NASM port equate
  1204 000004B9 B82300                  	MOV	AX,error_FCB_Unavailable
  1205                                  allowed_FAIL equ Allowed_FAIL	; NASM port equate
  1206 000004BC 36C606[0000]08          	MOV	byte [ss:ALLOWED],allowed_FAIL
  1207 000004C2 36C42E[0000]            	LES	BP,[ss:THISDPB]
  1208 000004C7 BF0100                  	MOV	DI,1				; Fake some registers
  1209 000004CA 89F9                    	MOV	CX,DI
  1210 000004CC 268B560B                	MOV	DX,[ES:BP + dpb_first_sector]
  1211 000004D0 E8(0000)                	invoke	HARDERR_DOS
  1212 000004D3 F9                      	STC
  1213 000004D4 C3                      	return
  1214                                  EndProc FCBHardErr
  1215                                  
  1216                                  END
