From 2d04cacc5322951f187bb17e017c12920ac8ebe2 Mon Sep 17 00:00:00 2001 From: Mark Zbikowski Date: Thu, 25 Apr 2024 21:24:10 +0100 Subject: MZ is back! --- v4.0/src/DOS/FCBIO.ASM | 1185 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1185 insertions(+) create mode 100644 v4.0/src/DOS/FCBIO.ASM (limited to 'v4.0/src/DOS/FCBIO.ASM') diff --git a/v4.0/src/DOS/FCBIO.ASM b/v4.0/src/DOS/FCBIO.ASM new file mode 100644 index 0000000..8b27d72 --- /dev/null +++ b/v4.0/src/DOS/FCBIO.ASM @@ -0,0 +1,1185 @@ +; SCCSID = @(#)fcbio.asm 1.5 85/07/30 +; SCCSID = @(#)fcbio.asm 1.5 85/07/30 +TITLE FCBIO - FCB system calls +NAME FCBIO + +; +; Ancient 1.0 1.1 FCB system calls +; regen save +; $GET_FCB_POSITION written none none +; $FCB_DELETE written none none +; $GET_FCB_FILE_LENGTH written none none +; $FCB_CLOSE written close none +; $FCB_RENAME written none none +; SaveFCBInfo +; ResetLRU +; SetOpenAge +; LRUFCB +; FCBRegen +; BlastSFT +; CheckFCB +; SFTFromFCB +; FCBHardErr +; +; Revision history: +; +; Created: ARR 4 April 1983 +; MZ 6 June 1983 completion of functions +; MZ 15 Dec 1983 Brain damaged programs close FCBs multiple +; times. Change so successive closes work by +; always returning OK. Also, detect I/O to +; already closed FCB and return EOF. +; MZ 16 Jan 1984 More braindamage. Need to separate info +; out of sft into FCB for reconnection +; +; A000 version 4.00 Jan. 1988 +; +.xlist +; +; get the appropriate segment definitions +; +include dosseg.asm + +CODE SEGMENT BYTE PUBLIC 'CODE' + ASSUME SS:DOSGROUP,CS:DOSGROUP + +.xcref +INCLUDE DOSSYM.INC +INCLUDE DEVSYM.INC +INCLUDE FASTOPEN.INC +.cref +.list + + AsmVars + + I_need OpenBuf,128 ; buffer for translating paths + I_need RenBuf,128 ; buffer for rename paths + i_need THISDPB,DWORD + i_need EXTERR,WORD + i_need ALLOWED,BYTE + I_need ThisSFT,DWORD ; SFT in use + I_need WFP_start,WORD ; pointer to canonical name + I_need Ren_WFP,WORD ; pointer to canonical name + I_need Attrib,BYTE ; Attribute for match attributes + I_need sftFCB,DWORD ; pointer to SFTs for FCB cache + I_need FCBLRU,WORD ; least recently used count + I_need Proc_ID,WORD ; current process ID + I_Need Name1,14 ; place for device names + I_need DEVPT,DWORD ; device pointer + I_need OpenLRU,WORD ; open age + I_need KeepCount,WORD ; number of fcbs to keep + I_need User_In_AX,WORD ; user input system call. + I_need JShare,DWORD ; share jump table + I_need FastOpenTable,BYTE ; DOS 3.3 fastopen +if debug + I_need BugLev,WORD + I_need BugTyp,WORD + include bugtyp.asm +endif + + +Break <$Get_FCB_Position - set random record fields to current pos> + +; +; $Get_FCB_Position - look at an FCB, retrieve the current position from the +; extent and next record field and set the random record field to point +; to that record +; +; Inputs: DS:DX point to a possible extended FCB +; Outputs: The random record field of the FCB is set to the current record +; Registers modified: all + +Procedure $Get_FCB_Position,NEAR + ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:DOSGroup + invoke GetExtended ; point to FCB + invoke GetExtent ; DX:AX is current record + MOV WORD PTR [SI.fcb_RR],AX ; drop in low order piece + MOV [SI+fcb_RR+2],DL ; drop in high order piece + CMP [SI.fcb_RECSIZ],64 + JAE GetFCBBye + MOV [SI+fcb_RR+2+1],DH ; Set 4th byte only if record size < 64 +GetFCBBye: + transfer FCB_Ret_OK +EndProc $GET_FCB_POSITION + +Break <$FCB_Delete - remove several files that match the input FCB> + +; +; $FCB_delete - given an FCB, remove all directory entries in the current +; directory that have names that match the FCB's ? marks. +; +; Inputs: DS:DX - point to an FCB +; Outputs: directory entries matching the FCB are deleted +; AL = FF if no entries were deleted. +; Registers modified: all + +Procedure $FCB_Delete,NEAR + ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:DOSGroup + MOV DI,OFFSET DOSGroup:OpenBuf ; appropriate place + invoke TransFCB ; convert FCB to path + JC BadPath ; signal no deletions + Context DS + invoke DOS_Delete ; wham + JC BadPath +GoodPath: + transfer FCB_Ret_OK ; do a good return +BadPath: +; + +; Error code is in AX +; + transfer FCB_Ret_Err ; let someone else signal the error +EndProc $FCB_DELETE + +Break <$Get_FCB_File_Length - return the length of a file> + +; +; $Get_FCB_File_Length - set the random record field to the length of the +; file in records (rounded up if partial). +; +; Inputs: DS:DX - point to a possible extended FCB +; Outputs: Random record field updated to reflect the number of records +; Registers modified: all + +Procedure $Get_FCB_File_Length,NEAR + ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:DOSGroup + invoke GetExtended ; get real FCB pointer + ; DX points to Input FCB + MOV DI,OFFSET DOSGroup:OpenBuf ; appropriate buffer + SaveReg ; save pointer to true FCB + Invoke TransFCB ; Trans name DS:DX, sets SATTRIB + RestoreReg + JC BadPath + SaveReg ; save pointer + Context DS + invoke Get_File_Info ; grab the info + RestoreReg ; get pointer back + JC BadPath ; invalid something + MOV DX,BX ; get high order size + MOV AX,DI ; get low order size + MOV BX,[SI.fcb_RECSIZ] ; get his record size + OR BX,BX ; empty record => 0 size for file + JNZ GetSize ; not empty + MOV BX,128 +GetSize: + MOV DI,AX ; save low order word + MOV AX,DX ; move high order for divide + XOR DX,DX ; clear out high + DIV BX ; wham + PUSH AX ; save dividend + MOV AX,DI ; get low order piece + DIV BX ; wham + MOV CX,DX ; save remainder + POP DX ; get high order dividend + JCXZ LengthStore ; no roundup + ADD AX,1 + ADC DX,0 ; 32-bit increment +LengthStore: + MOV WORD PTR [SI.FCB_RR],AX ; store low order + MOV [SI.FCB_RR+2],DL ; store high order + OR DH,DH + JZ GoodPath ; not storing insignificant zero + MOV [SI.FCB_RR+3],DH ; save that high piece +GoodRet: + transfer FCB_Ret_OK +EndProc $GET_FCB_FILE_LENGTH + +Break <$FCB_Close - close a file> + +; +; $FCB_Close - given an FCB, look up the SFN and close it. Do not free it +; as the FCB may be used for further I/O +; +; Inputs: DS:DX point to FCB +; Outputs: AL = FF if file was not found on disk +; Registers modified: all + +Procedure $FCB_Close,NEAR + ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:DOSGroup + XOR AL,AL ; default search attributes + invoke GetExtended ; DS:SI point to real FCB + JZ NoAttr ; not extended + MOV AL,[SI-1] ; get attributes +NoAttr: + MOV [Attrib],AL ; stash away found attributes + invoke SFTFromFCB + JC GoodRet ; MZ 16 Jan Assume death +; +; If the sharer is present, then the SFT is not regenable. Thus, there is +; no need to set the SFT's attribute. +; +;;; 9/8/86 F.C. save SFT attribute and restore it back when close is done + MOV AL,ES:[DI].sf_attr + XOR AH,AH + PUSH AX +;;; 9/8/86 F.C. save SFT attribute and restore it back when close is done + invoke CheckShare + JNZ NoStash + MOV AL,Attrib + MOV ES:[DI].sf_attr,AL ; attempted attribute for close +NoStash: + MOV AX,[SI].FCB_FDATE ; move in the time and date + MOV ES:[DI].sf_date,AX + MOV AX,[SI].FCB_FTIME + MOV ES:[DI].sf_time,AX + MOV AX,[SI].FCB_FilSiz + MOV WORD PTR ES:[DI].sf_size,AX + MOV AX,[SI].FCB_FilSiz+2 + MOV WORD PTR ES:[DI].sf_size+2,AX + OR ES:[DI].sf_Flags,sf_close_nodate + Context DS ; let Close see variables + invoke DOS_Close ; wham + LES DI,ThisSFT +;;; 9/8/86 F.C. restore SFT attribute + POP CX + MOV ES:[DI].sf_attr,CL +;;; 9/8/86 F.C. restore SFT attribute + PUSHF + TEST ES:[DI.sf_ref_count],-1 ; zero ref count gets blasted + JNZ CloseOK + PUSH AX + MOV AL,'M' + invoke BlastSFT + POP AX +CloseOK: + POPF + JNC GoodRet + CMP AL,error_invalid_handle + JZ GoodRet + MOV AL,error_file_not_found + transfer FCB_Ret_Err +EndProc $FCB_CLOSE + +Break <$FCB_Rename - change names in place> + +; +; $FCB_Rename - rename a file in place within a directory. Renames multiple +; files copying from the meta characters. +; +; Inputs: DS:DX point to an FCB. The normal name field is the source +; name of the files to be renamed. Starting at offset 11h +; in the FCB is the destination name. +; Outputs: AL = 0 -> no error occurred and all files were renamed +; AL = FF -> some files may have been renamed but: +; rename to existing file or source file not found +; Registers modified: all + +Procedure $FCB_Rename,NEAR + ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:DOSGroup + invoke GetExtended ; get pointer to real FCB + SaveReg + MOV AL,[SI] ; get drive byte + ADD SI,10h ; point to destination + MOV DI,OFFSET DOSGroup:RenBuf ; point to destination buffer + SaveReg <,DS,SI> ; save source pointer for TransFCB + MOV DS:[SI],AL ; drop in real drive + MOV DX,SI ; let TransFCB know where the FCB is + invoke TransFCB ; munch this pathname + RestoreReg > ; get path back + RestoreReg ; Original FCB pointer + JC BadRen ; bad path -> error + MOV SI,WFP_Start ; get pointer + MOV Ren_WFP,SI ; stash it + MOV DI,OFFSET DOSGroup:OpenBuf ; appropriate spot + invoke TransFCB ; wham + ; NOTE that this call is pointing + ; back to the ORIGINAL FCB so + ; SATTRIB gets set correctly + JC BadRen ; error + invoke DOS_Rename + JC BadRen + transfer FCB_Ret_OK +BadRen: +; +; AL has error code +; + transfer FCB_Ret_Err + +EndProc $FCB_RENAME + +Break + +; +; FCBs suffer from several problems. First, they are maintained in the +; user's space so he may move them at will. Second, they have a small +; reserved area that may be used for system information. Third, there was +; never any "rules for behavior" for FCBs; there was no protocol for their +; usage. +; +; This results in the following misbehavior: +; +; infinite opens of the same file: +; +; While (TRUE) { While (TRUE) { +; FCBOpen (FCB); FCBOpen (FCB); +; Read (FCB); Write (FCB); +; } } +; +; infinite opens of different files: +; +; While (TRUE) { While (TRUE) { +; FCBOpen (FCB[i++]); FCBOpen (FCB[i++]); +; Read (FCB); Write (FCB); +; } } +; +; multiple closes of the same file: +; +; FCBOpen (FCB); +; while (TRUE) +; FCBClose (FCB); +; +; I/O after closing file: +; +; FCBOpen (FCB); +; while (TRUE) { +; FCBWrite (FCB); +; FCBClose (FCB); +; } +; +; The following is am implementation of a methodology for emulating the +; above with the exception of I/O after close. We are NOT attempting to +; resolve that particular misbehavior. We will enforce correct behaviour in +; FCBs when they refer to a network file or when there is file sharing on +; the local machine. +; +; The reserved fields of the FCB (10 bytes worth) is divided up into various +; structures depending on the file itself and the state of operations of the +; OS. The information contained in this reserved field is enough to +; regenerate the SFT for the local non-shared file. It is assumed that this +; regeneration procedure may be expensive. The SFT for the FCB is +; maintained in a LRU cache as the ONLY performance inprovement. +; +; No regeneration of SFTs is attempted for network FCBs. +; +; To regenerate the SFT for a local FCB, it is necessary to determine if the +; file sharer is working. If the file sharer is present then the SFT is not +; regenerated. +; +; Finally, if there is no local sharing, the full name of the file is no +; longer available. We can make up for this by using the following +; information: +; +; The Drive number (from the DPB). +; The physical sector of the directory that contains the entry. +; The relative position of the entry in the sector. +; The first cluster field. +; The last used SFT. +; OR In the case of a device FCB +; The low 6 bits of sf_flags (indicating device type) +; The pointer to the device header +; +; +; We read in the particular directory sector and examine the indicated +; directory entry. If it matches, then we are kosher; otherwise, we fail. +; +; Some key items need to be remembered: +; +; Even though we are caching SFTs, they may contain useful sharing +; information. We enforce good behavior on the FCBs. +; +; Network support must not treat FCBs as impacting the ref counts on +; open VCs. The VCs may be closed only at process termination. +; +; If this is not an installed version of the DOS, file sharing will +; always be present. +; +; We MUST always initialize lstclus to = firclus when regenerating a +; file. Otherwise we start allocating clusters up the wazoo. +; +; Always initialize, during regeneration, the mode field to both isFCB +; and open_for_both. This is so the FCB code in the sharer can find the +; proper OI record. +; +; The test bits are: +; +; 00 -> local file +; 40 -> sharing local +; 80 -> network +; C0 -> local device + +Break + +; +; SaveFCBInfo - given an FCB and its associated SFT, copy the relevant +; pieces of information into the FCB to allow for subsequent +; regeneration. Poke LRU also. +; +; Inputs: ThisSFT points to a complete SFT. +; DS:SI point to the FCB (not an extended one) +; Outputs: The relevant reserved fields in the FCB are filled in. +; DS:SI preserved +; ES:DI point to sft +; Registers modified: All +; + +Procedure SaveFCBInfo,NEAR + ASSUME CS:DOSGroup,DS:NOTHING,ES:NOTHING,SS:DOSGroup + LES DI,ThisSFT + Assert ISSFT,,"SaveFCBInfo" + invoke IsSFTNet + JZ SaveLocal ; if not network then save local info +; +;----- In net support ----- +; + MOV AX,WORD PTR ES:[DI].sf_serial_ID ;AN000;;IFS. save IFS ID + MOV WORD PTR [SI].FCB_netID,ax ;AN000;;IFS. +; SaveReg +; LES DI,DWORD PTR ES:[DI].sf_netid +; MOV WORD PTR [SI].FCB_netID,DI ; save net ID +; MOV WORD PTR [SI].FCB_netID+2,ES +; RestoreReg + MOV BL,FCBNETWORK +; +;----- END In net support ----- +; +IF debug + JMP SaveSFN +ELSE + JMP SHORT SaveSFN +ENDIF +SaveLocal: + IF Installed + Invoke CheckShare + JZ SaveNoShare ; no sharer + JMP SaveShare ; sharer present + +SaveNoShare: + TEST ES:[DI].sf_flags,devid_device + JNZ SaveNoShareDev ; Device +; +; Save no sharing local file information +; + MOV AX,WORD PTR ES:[DI].sf_dirsec ; get directory sector F.C. + MOV [SI].fcb_nsl_dirsec,AX + MOV AL,ES:[DI].sf_dirpos ; location in sector + MOV [SI].fcb_nsl_dirpos,AL + MOV AX,ES:[DI].sf_firclus ; first cluster + MOV [SI].fcb_nsl_firclus,AX + MOV BL,00 +; +; Create the bits field from the dirty/device bits of the flags word and the +; mode byte +; +SetFCBBits: + MOV AX,ES:[DI].sf_flags + AND AL,0C0h ; mask off drive bits + OR AL,BYTE PTR ES:[DI].sf_mode ; stick in open mode + MOV [SI].fcb_nsl_bits,AL ; save dirty info + JMP SaveSFN ; go and save SFN + +; +; Save no sharing local device information +; +SaveNoShareDev: + MOV AX,WORD PTR ES:[DI].sf_devptr + MOV WORD PTR [SI].FCB_nsld_drvptr,AX + MOV AX,WORD PTR ES:[DI].sf_devptr + 2 + MOV WORD PTR [SI].FCB_nsld_drvptr + 2,AX + MOV BL,FCBDEVICE + JMP SetFCBBits ; go and save SFN + +SaveShare: + ENDIF +; +;----- In share support ----- +; +if installed + Call JShare + 10 * 4 +else + Call ShSave +endif +; +;----- end in share support ----- +; +SaveSFN: + MOV AX,ES:[DI].sf_flags + AND AL,3Fh ; get real drive + OR AL,BL + MOV [SI].fcb_l_drive,AL + LEA AX,[DI-SFTable] +; +; Adjust for offset to table. +; + SUB AX,WORD PTR SftFCB + MOV BL,SIZE sf_entry + DIV BL + MOV [SI].FCB_sfn,AL ; last used SFN + MOV AX,FCBLRU ; get lru count + INC AX + MOV WORD PTR ES:[DI].sf_LRU,AX + JNZ SimpleStuff +; +; lru flag overflowed. Run through all FCB sfts and adjust: LRU < 8000h +; get set to 0. Others -= 8000h. This LRU = 8000h +; + MOV BX,sf_position + invoke ResetLRU +; +; Set new LRU to AX +; +SimpleStuff: + MOV FCBLRU,AX + return +EndProc SaveFCBInfo + +Break + +; +; ResetLRU - during lru updates, we may wrap at 64K. We must walk the +; entire set of SFTs and subtract 8000h from their lru counts and truncate +; at 0. +; +; Inputs: BX is offset into SFT field where lru firld is kept +; ES:DI point to SFT currently being updated +; Outputs: All FCB SFTs have their lru fields truncated +; AX has 8000h +; Registers modified: none + +Procedure ResetLRU,NEAR + ASSUME CS:DOSGroup,DS:NOTHING,ES:NOTHING,SS:NOTHING + Assert ISSFT,,"ResetLRU" + MOV AX,8000h + SaveReg + LES DI,sftFCB ; get pointer to head + MOV CX,ES:[DI].sfCount + LEA DI,[DI].sfTable ; point at table +ovScan: + SUB WORD PTR ES:[DI+BX],AX ; decrement lru count + JA ovLoop + MOV WORD PTR ES:[DI.BX],AX ; truncate at 0 +ovLoop: + ADD DI,SIZE SF_Entry ; advance to next + LOOP ovScan + RestoreReg + MOV ES:[DI+BX],AX + return +EndProc ResetLRU + +Break + +; +; SetOpenAge - In order to maintain the first N open files in the FCB cache, +; we keep the 'open age' or an LRU count based on opens. We update the +; count here and fill in the appropriate field. +; +; Inputs: ES:DI point to SFT +; Outputs: ES:DI has the open age field filled in. +; If open age has wraparound, we will have subtracted 8000h +; from all open ages. +; Registers modified: AX +; + +Procedure SetOpenAge,NEAR + ASSUME CS:DOSGroup,DS:NOTHING,ES:NOTHING,SS:NOTHING + Assert ISSFT,,"SetOpenAge" + MOV AX,OpenLRU + INC AX + MOV ES:[DI].sf_OpenAge,AX + JNZ SetDone + MOV BX,sf_Position+2 + invoke ResetLRU +SetDone: + MOV OpenLRU,AX + return +EndProc SetOpenAge + +Break + +; +; LRUFCB - find LRU fcb in cache. Set ThisSFT and return it. We preserve +; the first keepcount sfts if they are network sfts or if sharing is +; loaded. If carry is set then NO BLASTING is NECESSARY. +; +; Inputs: none +; Outputs: ES:DI point to SFT +; ThisSFT points to SFT +; SFT is zeroed +; Carry set of closes failed +; Registers modified: none +; + +Procedure LRUFCB,NEAR + ASSUME CS:DOSGroup,DS:NOTHING,ES:NOTHING,SS:NOTHING + Invoke Save_World +; +; Find nth oldest NET/SHARE FCB. We want to find its age for the second scan +; to find the lease recently used one that is younger than the open age. We +; operate be scanning the list n times finding the least age that is greater +; or equal to the previous minimum age. +; +; BP is the count of times we need to go through this loop. +; AX is the current acceptable minimum age to consider +; + mov bp,KeepCount ; k = keepcount; + XOR AX,AX ; low = 0; +; +; If we've scanned the table n times, then we are done. +; +lru1: + CMP bp,0 ; while (k--) { + JZ lru75 + DEC bp +; +; Set up for scan. +; +; AX is the minimum age for consideration +; BX is the minimum age found during the scan +; SI is the position of the entry that corresponds to BX +; + MOV BX,-1 ; min = 0xffff; + MOV si,BX ; pos = 0xffff; + LES DI,SFTFCB ; for (CX=FCBCount; CX>0; CX--) + MOV CX,ES:[DI].sfCount + LEA DI,[DI].sfTable +; +; Innermost loop. If the current entry is free, then we are done. Or, if the +; current entry is busy (indicating a previous aborted allocation), then we +; are done. In both cases, we use the found entry. +; +lru2: + cmp es:[di].sf_ref_count,0 + jz lru25 + cmp es:[di].sf_ref_count,sf_busy + jnz lru3 +; +; The entry is usable without further scan. Go and use it. +; +lru25: + MOV si,DI ; pos = i; + JMP lru11 ; goto got; +; +; See if the entry is for the network or for the sharer. +; +; If for the sharer or network then +; if the age < current minimum AND >= allowed minimum then +; this entry becomes current minimum +; +lru3: + TEST ES:[DI].sf_flags,sf_isnet ; if (!net[i] + JNZ lru35 +if installed + Invoke CheckShare ; && !sharing) + JZ lru5 ; else +ENDIF +; +; This SFT is for the net or is for the sharer. See if it less than the +; current minimum. +; +lru35: + MOV DX,ES:[DI].sf_OpenAge + CMP DX,AX ; if (age[i] >= low && + JB lru5 + CMP DX,BX + JAE lru5 ; age[i] < min) { +; +; entry is new minimum. Remember his age. +; + mov bx,DX ; min = age[i]; + mov si,di ; pos = i; +; +; End of loop. gp back for more +; +lru5: +add di,size sf_entry + loop lru2 ; } +; +; The scan is complete. If we have successfully found a new minimum (pos != -1) +; set then threshold value to this new minimum + 1. Otherwise, the scan is +; complete. Go find LRU. +; +lru6: cmp si,-1 ; position not -1? + jz lru75 ; no, done with everything + lea ax,[bx+1] ; set new threshold age + jmp lru1 ; go and loop for more +lru65: stc + jmp short lruDead ; return -1; +; +; Main loop is done. We have AX being the age+1 of the nth oldest sharer or +; network entry. We now make a second pass through to find the LRU entry +; that is local-no-share or has age >= AX +; +lru75: + mov bx,-1 ; min = 0xffff; + mov si,bx ; pos = 0xffff; + LES DI,SFTFCB ; for (CX=FCBCount; CX>0; CX--) + MOV CX,ES:[DI].sfCount + LEA DI,[DI].sfTable +; +; If this is is local-no-share then go check for LRU else if age >= threshold +; then check for lru. +; +lru8: + TEST ES:[DI].sf_flags,sf_isnet + jnz lru85 ; is for network, go check age + invoke CheckShare ; sharer here? + jz lru86 ; no, go check lru +; +; Network or sharer. Check age +; +lru85: + cmp es:[di].sf_OpenAge,ax + jb lru9 ; age is before threshold, skip it +; +; Check LRU +; +lru86: + cmp es:[di].sf_LRU,bx ; is LRU less than current LRU? + jae lru9 ; no, skip this + mov si,di ; remember position + mov bx,es:[di].sf_LRU ; remember new minimum LRU +; +; Done with this entry, go back for more. +; +lru9: + add di,size sf_entry + loop lru8 +; +; Scan is complete. If we found NOTHING that satisfied us then we bomb +; out. The conditions here are: +; +; No local-no-shares AND all net/share entries are older than threshold +; +lru10: + cmp si,-1 ; if no one f + jz lru65 ; return -1; +lru11: + mov di,si + MOV WORD PTR ThisSFT,DI ; set thissft + MOV WORD PTR ThisSFT+2,ES +; +; If we have sharing or thisSFT is a net sft, then close it until ref count +; is 0. +; + TEST ES:[DI].sf_flags,sf_isNet + JNZ LRUClose +IF INSTALLED + Invoke CheckShare + JZ LRUDone +ENDIF +; +; Repeat close until ref count is 0 +; +LRUClose: + Context DS + LES DI,ThisSFT + CMP ES:[DI].sf_ref_count,0 ; is ref count still <> 0? + JZ LRUDone ; nope, all done + +; Message 1,"LRUFCB: closing " +; MessageNum +; Message 1,":" +; MessageNum + + Invoke DOS_Close + jnc LRUClose ; no error => clean up + cmp al,error_invalid_handle + jz LRUClose + stc + JMP short LRUDead +LRUDone: + XOR AL,AL + invoke BlastSFT ; fill SFT with 0 (AL) +LRUDead: + Invoke Restore_World + ASSUME DS:NOTHING + LES DI,ThisSFT + Assert ISSFT,,"LRUFCB return" + retnc + MOV AL,error_FCB_unavailable + return +EndProc LRUFCB + +Break + +; +; FCBRegen - examine reserved field of FCB and attempt to generate the SFT +; from it. +; +; Inputs: DS:SI point to FCB +; Outputs: carry clear Filled in SFT +; Carry set unrecoverable error +; Registers modified: all + +Procedure FCBRegen,NEAR + ASSUME DS:NOTHING,ES:NOTHING +; +; General data filling. Mode is sf_isFCB + open_for_both, date/time we do +; not fill, size we do no fill, position we do not fill, +; bit 14 of flags = TRUE, other bits = FALSE +; + MOV AL,[SI].fcb_l_drive +; +; We discriminate based on the first two bits in the reserved field. +; + TEST AL,FCBSPECIAL ; check for no sharing test + JZ RegenNoSharing ; yes, go regen from no sharing +; +; The FCB is for a network or a sharing based system. At this point we have +; already closed the SFT for this guy and reconnection is impossible. +; +; Remember that he may have given us a FCB with bogus information in it. +; Check to see if sharing is present or if the redir is present. If either is +; around, presume that we have cycled out the FCB and give the hard error. +; Otherwise, just return with carry set. +; + invoke CheckShare ; test for sharer + JNZ RegenFail ; yep, fail this. + MOV AX,multNet SHL 8 ; install check on multnet + INT 2FH + OR AL,AL ; is it there? + JZ RegenDead ; no, just fail the operation +RegenFail: + MOV AX,User_In_AX + cmp AH,fcb_close + jz RegenDead + invoke FCBHardErr ; massive hard error. +RegenDead: + STC + return ; carry set +; +; Local FCB without sharing. Check to see if sharing is loaded. If so +; fail the operation. +; +RegenNoSharing: + invoke CheckShare ; Sharing around? + JNZ RegenFail +; +; Find an SFT for this guy. +; + invoke LRUFcb + retc + MOV ES:[DI].sf_mode,SF_IsFCB + open_for_both + sharing_compat + AND AL,3Fh ; get drive number for flags + CBW + OR AX,sf_close_noDate ; normal FCB operation +; +; The bits field consists of the upper two bits (dirty and device) from the +; SFT and the low 4 bits from the open mode. +; + MOV CL,[SI].FCB_nsl_bits ; stick in dirty bits. + MOV CH,CL + AND CH,0C0h ; mask off the dirty/device bits + OR AL,CH + AND CL,access_mask ; get the mode bits + MOV BYTE PTR ES:[DI].sf_mode,CL + MOV ES:[DI].sf_flags,AX ; initial flags + MOV AX,Proc_ID + MOV ES:[DI].sf_PID,AX + SaveReg + Context ES + MOV DI,OFFSET DOSGroup:Name1 + MOV CX,8 + INC SI ; Skip past drive byte to name in FCB +RegenCopyName2: + LODSB + + IF DBCS ;AN000; + invoke testkanj ;AN000; + jz notkanj9 ;AN000; + STOSB ;AN000; + DEC CX ;AN000; + JCXZ DoneNam2 ;AN000; ; Ignore split kanji char error + LODSB ;AN000; + jmp short StuffChar2 ;AN000; + ;AN000; +notkanj9: ;AN000; + ENDIF ;AN000; + + Invoke UCase +StuffChar2: + STOSB + LOOP RegenCopyName2 +DoneNam2: + Context DS + MOV [ATTRIB],attr_hidden + attr_system + attr_directory + ; Must set this to something interesting + ; to call DEVNAME. + Invoke DevName ; check for device + ASSUME DS:NOTHING,ES:NOTHING + RestoreReg + JC RegenFileNoSharing ; not found on device list => file +; +; Device found. We can ignore disk-specific info +; + MOV BYTE PTR ES:[DI].sf_flags,BH ; device parms + MOV ES:[DI].sf_attr,0 ; attribute + LDS SI,DEVPT ; get device driver + MOV WORD PTR ES:[DI].sf_devptr,SI + MOV WORD PTR ES:[DI].sf_devptr+2,DS + return ; carry is clear + +RegenDeadJ: + JMP RegenDead +; +; File found. Just copy in the remaining pieces. +; +RegenFileNoSharing: + MOV AX,ES:[DI].sf_flags + AND AX,03Fh + SaveReg + Invoke Find_DPB + MOV WORD PTR ES:[DI].sf_devptr,SI + MOV WORD PTR ES:[DI].sf_devptr+2,DS + RestoreReg + jc RegenDeadJ ; if find DPB fails, then drive + ; indicator was bogus + MOV AX,[SI].FCB_nsl_dirsec + MOV WORD PTR ES:[DI].sf_dirsec,AX + MOV WORD PTR ES:[DI].sf_dirsec+2,0 ;AN000;>32mb + MOV AX,[SI].FCB_nsl_firclus + MOV ES:[DI].sf_firclus,AX + MOV ES:[DI].sf_lstclus,AX + MOV AL,[SI].FCB_nsl_dirpos + MOV ES:[DI].sf_dirpos,AL + INC ES:[DI].sf_ref_count ; Increment reference count. + ; Existing FCB entries would be + ; flushed unnecessarily because of + ; check in CheckFCB of the ref_count. + ; July 22/85 - BAS + LEA SI,[SI].FCB_name + LEA DI,[DI].sf_name + MOV CX,fcb_extent-fcb_name +RegenCopyName: + LODSB + + IF DBCS ;AN000; + invoke testkanj + jz notkanj1 + STOSB + DEC CX + JCXZ DoneNam ; Ignore split kanji char error + LODSB + jmp short StuffChar + +notkanj1: + ENDIF ;AN000; + + Invoke UCase +StuffChar: + STOSB + LOOP RegenCopyName +DoneNam: + clc + return +EndProc FCBRegen + +; +; BlastSFT - fill SFT with garbage +; +; Inputs: ES:DI point to SFT +; AL has fill +; Outputs: SFT is filled with nonsense +; *FLAGS PRESERVED* +; Registers modified: CX + +Procedure BlastSFT,NEAR + SaveReg + MOV CX,SIZE sf_entry + REP STOSB + RestoreReg + MOV ES:[DI].sf_ref_count,0 ; set ref count + MOV ES:[DI].sf_LRU,0 ; set lru + MOV ES:[DI].sf_OpenAge,-1 ; Set open age + return +EndProc BlastSFT + +Break + +; CheckFCB - examine an FCB and its contents to see if it needs to be +; regenerated. +; +; Inputs: DS:SI point to FCB (not extended) +; AL is SFT index +; Outputs: Carry Set - FCB needs to be regened +; Carry clear - FCB is OK. ES:DI point to SFT +; Registers modified: AX and BX + +Procedure CheckFCB,NEAR + ASSUME DS:NOTHING,ES:NOTHING + LES DI,sftFCB + CMP BYTE PTR ES:[DI].SFCount,AL + JC BadSFT + MOV BL,SIZE sf_entry + MUL BL + LEA DI,[DI].sftable + ADD DI,AX + MOV AX,Proc_ID + CMP ES:[DI].sf_PID,AX + JNZ BadSFT ; must match process + CMP ES:[DI].sf_ref_count,0 + JZ BadSFT ; must also be in use + MOV AL,[SI].FCB_l_Drive + TEST AL,FCBSPECIAL ; a special FCB? + JZ CheckNoShare ; No. try local or device +; +; Since we are a special FCB, try NOT to use a bogus test instruction. +; FCBSHARE is a superset of FCBNETWORK. +; + PUSH AX + AND AL,FCBMASK + CMP AL,FCBSHARE ; net FCB? + POP AX + JNZ CheckNet ; yes +; +;----- In share support ----- +; +if installed + Call JShare + 11 * 4 +else + Call ShChk +endif + JC BadSFT + JMP SHORT CheckD +; +;----- End in share support ----- +; +CheckFirClus: + CMP BX,ES:[DI].sf_firclus + JNZ BadSFT +CheckD: AND AL,3Fh + MOV AH,BYTE PTR ES:[DI].sf_flags + AND AH,3Fh + CMP AH,AL + retz ; carry is clear +BadSFT: STC + return ; carry is clear +CheckNet: +; +;----- In net support ----- +; +; MOV AX,[SI].FCB_net_handle +; CMP AX,WORD PTR ES:[DI].sf_NETID+4 +; JNZ BadSFT +; MOV AX,WORD PTR [SI].FCB_netID +; CMP AX,WORD PTR ES:[DI].sf_netid +; JNZ BadSFT + MOV AX,WORD PTR [SI].FCB_netID ;AN000;IFS.DOS 4.00 + CMP AX,WORD PTR ES:[DI].sf_serial_ID ;AN000;IFS.DOS 4.00 + JNZ BadSFT +; +;----- END In net support ----- +; + return + +CheckNoShare: + TEST AL,FCBDEVICE ; Device? + JNZ CheckNoShareDev ; Yes +; +; Check no sharing local file +; + MOV BX,[SI].FCB_nsl_Dirsec + CMP WORD PTR ES:[DI].sf_dirsec+2,0 ;AN000;F.C. >32mb + JNZ BadSFt ;AN000;F.C. >32mb + + CMP BX,WORD PTR ES:[DI].sf_dirsec ;AN000;F.C. >32mb + JNZ BadSFT + MOV BL,[SI].FCB_nsl_Dirpos + CMP BL,ES:[DI].sf_dirpos + JNZ BadSFt +; +; Since the bits field comes from two different spots, compare them separately. +; + MOV BL,[SI].FCB_nsl_bits + MOV BH,BYTE PTR ES:[DI].sf_flags + XOR BH,BL + AND BH,0C0h + JNZ BadSFT ; dirty/device bits are different + XOR BL,BYTE PTR ES:[DI].sf_mode + AND BL,access_mask + JNZ BadSFT ; access modes are different +; Make sure that the names are the same in the FCB and the SFT +; This case can appear under the following scenario: +; Create FOO +; Rename FOO -> BAR +; Open BAR +; The SFT will still contain the name for the old file name. +; July 30/85 - BAS + PUSH DI + PUSH SI + LEA DI,[DI].sf_name + LEA SI,[SI].fcb_name + MOV CX,11 + REPE CMPSB + POP SI + POP DI + JNZ BadSFT + MOV BX,[SI].FCB_nsl_firclus + JMP CheckFirClus + +CheckNoShareDev: + MOV BX,WORD PTR [SI].FCB_nsld_drvptr + CMP BX,WORD PTR ES:[DI].sf_devptr + JNZ BadSFT + MOV BX,WORD PTR [SI].FCB_nsld_drvptr + 2 + CMP BX,WORD PTR ES:[DI].sf_devptr + 2 + JNZ BadSFT + JMP CheckD + +EndProc CheckFCB + +Break + +; +; SFTFromFCB - the workhorse of this compatability crap. Check to see if +; the SFT for the FCB is Good. If so, make ThisSFT point to it. If not +; good, get one from the cache and regenerate it. Overlay the LRU field +; with PID +; +; Inputs: DS:SI point to FCB +; Outputs: ThisSFT point to appropriate SFT +; Carry clear -> OK ES:DI -> SFT +; Carry set -> error in ax +; Registers modified: ES,DI, AX + +Procedure SFTFromFCB,NEAR + ASSUME DS:NOTHING,ES:NOTHING + SaveReg + MOV AL,[SI].fcb_sfn ; set SFN for check + invoke CheckFCB + RestoreReg + MOV WORD PTR ThisSFT,DI ; set thissft + MOV WORD PTR ThisSFT+2,ES + JNC SetSFT ; no problems, just set thissft + + fmt typFCB,LevCheck,<"FCB $x:$x does not match SFT $x:$x\n">, + + Invoke Save_World + invoke FCBRegen + Invoke Restore_World ; restore world + MOV AX,EXTERR + retc + +; Message 1,<"FCBRegen Succeeded",13,10> + +SetSFT: LES DI,ThisSFT + PUSH Proc_ID ; set process id + POP ES:[DI].sf_PID + return ; carry is clear +EndProc SFTFromFCB + +Break + +; +; FCBHardErr - signal to a user app that he is trying to use an +; unavailable FCB. +; +; Inputs: none. +; Outputs: none. +; Registers modified: all +; + +Procedure FCBHardErr,NEAR + ASSUME DS:NOTHING,ES:NOTHING + MOV AX,error_FCB_Unavailable + MOV [ALLOWED],allowed_FAIL + LES BP,[THISDPB] + MOV DI,1 ; Fake some registers + MOV CX,DI + MOV DX,ES:[BP.dpb_first_sector] + invoke HARDERR + STC + return +EndProc FCBHardErr + +CODE ENDS +END -- cgit v1.2.3