1 ; SCCSID = @(#)fcbio.asm 1.5 85/07/30
2 ; SCCSID = @(#)fcbio.asm 1.5 85/07/30
3 TITLE FCBIO
- FCB system calls
7 ; Ancient 1.0 1.1 FCB system calls
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
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
35 ; A000 version 4.00 Jan. 1988
39 ; get the appropriate segment definitions
43 CODE SEGMENT BYTE PUBLIC 'CODE'
44 ASSUME
SS:DOSGROUP
,CS:DOSGROUP
55 I_need OpenBuf
,128 ; buffer for translating paths
56 I_need RenBuf
,128 ; buffer for rename paths
60 I_need ThisSFT
,DWORD ; SFT in use
61 I_need WFP_start
,WORD ; pointer to canonical name
62 I_need Ren_WFP
,WORD ; pointer to canonical name
63 I_need Attrib
,BYTE ; Attribute for match attributes
64 I_need sftFCB
,DWORD ; pointer to SFTs for FCB cache
65 I_need FCBLRU
,WORD ; least recently used count
66 I_need Proc_ID
,WORD ; current process ID
67 I_Need Name1
,14 ; place for device names
68 I_need DEVPT
,DWORD ; device pointer
69 I_need OpenLRU
,WORD ; open age
70 I_need KeepCount
,WORD ; number of fcbs to keep
71 I_need User_In_AX
,WORD ; user input system call.
72 I_need JShare
,DWORD ; share jump table
73 I_need FastOpenTable
,BYTE ; DOS 3.3 fastopen
81 Break <$Get_FCB_Position
- set random record fields to current pos
>
84 ; $Get_FCB_Position - look at an FCB, retrieve the current position from the
85 ; extent and next record field and set the random record field to point
88 ; Inputs: DS:DX point to a possible extended FCB
89 ; Outputs: The random record field of the FCB is set to the current record
90 ; Registers modified: all
92 Procedure $Get_FCB_Position
,NEAR
93 ASSUME
CS:DOSGROUP
,DS:NOTHING
,ES:NOTHING
,SS:DOSGroup
94 invoke GetExtended
; point to FCB
95 invoke GetExtent
; DX:AX is current record
96 MOV WORD PTR [SI.fcb_RR
],AX ; drop in low order piece
97 MOV [SI+fcb_RR
+2],DL ; drop in high order piece
98 CMP [SI.fcb_RECSIZ
],64
100 MOV [SI+fcb_RR
+2+1],DH ; Set 4th byte only if record size < 64
103 EndProc $GET_FCB_POSITION
105 Break <$FCB_Delete
- remove several files that
match the input FCB
>
108 ; $FCB_delete - given an FCB, remove all directory entries in the current
109 ; directory that have names that match the FCB's ? marks.
111 ; Inputs: DS:DX - point to an FCB
112 ; Outputs: directory entries matching the FCB are deleted
113 ; AL = FF if no entries were deleted.
114 ; Registers modified: all
116 Procedure $FCB_Delete
,NEAR
117 ASSUME
CS:DOSGROUP
,DS:NOTHING
,ES:NOTHING
,SS:DOSGroup
118 MOV DI,OFFSET DOSGroup
:OpenBuf
; appropriate place
119 invoke TransFCB
; convert FCB to path
120 JC BadPath
; signal no deletions
122 invoke DOS_Delete
; wham
125 transfer FCB_Ret_OK
; do a good return
129 ; Error code is in AX
131 transfer FCB_Ret_Err
; let someone else signal the error
134 Break <$Get_FCB_File_Length
- return the length of a
file>
137 ; $Get_FCB_File_Length - set the random record field to the length of the
138 ; file in records (rounded up if partial).
140 ; Inputs: DS:DX - point to a possible extended FCB
141 ; Outputs: Random record field updated to reflect the number of records
142 ; Registers modified: all
144 Procedure $Get_FCB_File_Length
,NEAR
145 ASSUME
CS:DOSGROUP
,DS:NOTHING
,ES:NOTHING
,SS:DOSGroup
146 invoke GetExtended
; get real FCB pointer
147 ; DX points to Input FCB
148 MOV DI,OFFSET DOSGroup
:OpenBuf
; appropriate buffer
149 SaveReg
<DS,SI> ; save pointer to true FCB
150 Invoke TransFCB
; Trans name DS:DX, sets SATTRIB
153 SaveReg
<DS,SI> ; save pointer
155 invoke Get_File_Info
; grab the info
156 RestoreReg
<SI,DS> ; get pointer back
157 JC BadPath
; invalid something
158 MOV DX,BX ; get high order size
159 MOV AX,DI ; get low order size
160 MOV BX,[SI.fcb_RECSIZ
] ; get his record size
161 OR BX,BX ; empty record => 0 size for file
162 JNZ GetSize
; not empty
165 MOV DI,AX ; save low order word
166 MOV AX,DX ; move high order for divide
167 XOR DX,DX ; clear out high
169 PUSH AX ; save dividend
170 MOV AX,DI ; get low order piece
172 MOV CX,DX ; save remainder
173 POP DX ; get high order dividend
174 JCXZ LengthStore
; no roundup
176 ADC DX,0 ; 32-bit increment
178 MOV WORD PTR [SI.FCB_RR
],AX ; store low order
179 MOV [SI.FCB_RR
+2],DL ; store high order
181 JZ GoodPath
; not storing insignificant zero
182 MOV [SI.FCB_RR
+3],DH ; save that high piece
185 EndProc $GET_FCB_FILE_LENGTH
187 Break <$FCB_Close
- close a
file>
190 ; $FCB_Close - given an FCB, look up the SFN and close it. Do not free it
191 ; as the FCB may be used for further I/O
193 ; Inputs: DS:DX point to FCB
194 ; Outputs: AL = FF if file was not found on disk
195 ; Registers modified: all
197 Procedure $FCB_Close
,NEAR
198 ASSUME
CS:DOSGROUP
,DS:NOTHING
,ES:NOTHING
,SS:DOSGroup
199 XOR AL,AL ; default search attributes
200 invoke GetExtended
; DS:SI point to real FCB
201 JZ NoAttr
; not extended
202 MOV AL,[SI-1] ; get attributes
204 MOV [Attrib
],AL ; stash away found attributes
206 JC GoodRet
; MZ 16 Jan Assume death
208 ; If the sharer is present, then the SFT is not regenable. Thus, there is
209 ; no need to set the SFT's attribute.
211 ;;; 9/8/86 F.C. save SFT attribute and restore it back when close is done
212 MOV AL,ES:[DI].sf_attr
215 ;;; 9/8/86 F.C. save SFT attribute and restore it back when close is done
219 MOV ES:[DI].sf_attr
,AL ; attempted attribute for close
221 MOV AX,[SI].FCB_FDATE
; move in the time and date
222 MOV ES:[DI].sf_date
,AX
223 MOV AX,[SI].FCB_FTIME
224 MOV ES:[DI].sf_time
,AX
225 MOV AX,[SI].FCB_FilSiz
226 MOV WORD PTR ES:[DI].sf_size
,AX
227 MOV AX,[SI].FCB_FilSiz
+2
228 MOV WORD PTR ES:[DI].sf_size
+2,AX
229 OR ES:[DI].sf_Flags
,sf_close_nodate
230 Context
DS ; let Close see variables
231 invoke DOS_Close
; wham
233 ;;; 9/8/86 F.C. restore SFT attribute
235 MOV ES:[DI].sf_attr
,CL
236 ;;; 9/8/86 F.C. restore SFT attribute
238 TEST ES:[DI.sf_ref_count
],-1 ; zero ref count gets blasted
247 CMP AL,error_invalid_handle
249 MOV AL,error_file_not_found
253 Break <$FCB_Rename
- change names
in place
>
256 ; $FCB_Rename - rename a file in place within a directory. Renames multiple
257 ; files copying from the meta characters.
259 ; Inputs: DS:DX point to an FCB. The normal name field is the source
260 ; name of the files to be renamed. Starting at offset 11h
261 ; in the FCB is the destination name.
262 ; Outputs: AL = 0 -> no error occurred and all files were renamed
263 ; AL = FF -> some files may have been renamed but:
264 ; rename to existing file or source file not found
265 ; Registers modified: all
267 Procedure $FCB_Rename
,NEAR
268 ASSUME
CS:DOSGROUP
,DS:NOTHING
,ES:NOTHING
,SS:DOSGroup
269 invoke GetExtended
; get pointer to real FCB
271 MOV AL,[SI] ; get drive byte
272 ADD SI,10h
; point to destination
273 MOV DI,OFFSET DOSGroup
:RenBuf
; point to destination buffer
274 SaveReg
<<WORD PTR DS:[SI]>,DS,SI> ; save source pointer for TransFCB
275 MOV DS:[SI],AL ; drop in real drive
276 MOV DX,SI ; let TransFCB know where the FCB is
277 invoke TransFCB
; munch this pathname
278 RestoreReg
<SI,DS,<WORD PTR DS:[SI]>> ; get path back
279 RestoreReg
<DX> ; Original FCB pointer
280 JC BadRen
; bad path -> error
281 MOV SI,WFP_Start
; get pointer
282 MOV Ren_WFP
,SI ; stash it
283 MOV DI,OFFSET DOSGroup
:OpenBuf
; appropriate spot
284 invoke TransFCB
; wham
285 ; NOTE that this call is pointing
286 ; back to the ORIGINAL FCB so
287 ; SATTRIB gets set correctly
300 Break <Misbehavior fixers
>
303 ; FCBs suffer from several problems. First, they are maintained in the
304 ; user's space so he may move them at will. Second, they have a small
305 ; reserved area that may be used for system information. Third, there was
306 ; never any "rules for behavior" for FCBs; there was no protocol for their
309 ; This results in the following misbehavior:
311 ; infinite opens of the same file:
313 ; While (TRUE) { While (TRUE) {
314 ; FCBOpen (FCB); FCBOpen (FCB);
315 ; Read (FCB); Write (FCB);
318 ; infinite opens of different files:
320 ; While (TRUE) { While (TRUE) {
321 ; FCBOpen (FCB[i++]); FCBOpen (FCB[i++]);
322 ; Read (FCB); Write (FCB);
325 ; multiple closes of the same file:
331 ; I/O after closing file:
339 ; The following is am implementation of a methodology for emulating the
340 ; above with the exception of I/O after close. We are NOT attempting to
341 ; resolve that particular misbehavior. We will enforce correct behaviour in
342 ; FCBs when they refer to a network file or when there is file sharing on
345 ; The reserved fields of the FCB (10 bytes worth) is divided up into various
346 ; structures depending on the file itself and the state of operations of the
347 ; OS. The information contained in this reserved field is enough to
348 ; regenerate the SFT for the local non-shared file. It is assumed that this
349 ; regeneration procedure may be expensive. The SFT for the FCB is
350 ; maintained in a LRU cache as the ONLY performance inprovement.
352 ; No regeneration of SFTs is attempted for network FCBs.
354 ; To regenerate the SFT for a local FCB, it is necessary to determine if the
355 ; file sharer is working. If the file sharer is present then the SFT is not
358 ; Finally, if there is no local sharing, the full name of the file is no
359 ; longer available. We can make up for this by using the following
362 ; The Drive number (from the DPB).
363 ; The physical sector of the directory that contains the entry.
364 ; The relative position of the entry in the sector.
365 ; The first cluster field.
367 ; OR In the case of a device FCB
368 ; The low 6 bits of sf_flags (indicating device type)
369 ; The pointer to the device header
372 ; We read in the particular directory sector and examine the indicated
373 ; directory entry. If it matches, then we are kosher; otherwise, we fail.
375 ; Some key items need to be remembered:
377 ; Even though we are caching SFTs, they may contain useful sharing
378 ; information. We enforce good behavior on the FCBs.
380 ; Network support must not treat FCBs as impacting the ref counts on
381 ; open VCs. The VCs may be closed only at process termination.
383 ; If this is not an installed version of the DOS, file sharing will
386 ; We MUST always initialize lstclus to = firclus when regenerating a
387 ; file. Otherwise we start allocating clusters up the wazoo.
389 ; Always initialize, during regeneration, the mode field to both isFCB
390 ; and open_for_both. This is so the FCB code in the sharer can find the
396 ; 40 -> sharing local
400 Break <SaveFCBInfo
- store pertinent information
from an SFT
into the FCB
>
403 ; SaveFCBInfo - given an FCB and its associated SFT, copy the relevant
404 ; pieces of information into the FCB to allow for subsequent
405 ; regeneration. Poke LRU also.
407 ; Inputs: ThisSFT points to a complete SFT.
408 ; DS:SI point to the FCB (not an extended one)
409 ; Outputs: The relevant reserved fields in the FCB are filled in.
412 ; Registers modified: All
415 Procedure SaveFCBInfo
,NEAR
416 ASSUME
CS:DOSGroup
,DS:NOTHING
,ES:NOTHING
,SS:DOSGroup
418 Assert ISSFT
,<ES,DI>,"SaveFCBInfo"
420 JZ SaveLocal
; if not network then save local info
422 ;----- In net support -----
424 MOV AX,WORD PTR ES:[DI].sf_serial_ID
;AN000;;IFS. save IFS ID
425 MOV WORD PTR [SI].FCB_netID
,ax ;AN000;;IFS.
427 ; LES DI,DWORD PTR ES:[DI].sf_netid
428 ; MOV WORD PTR [SI].FCB_netID,DI ; save net ID
429 ; MOV WORD PTR [SI].FCB_netID+2,ES
433 ;----- END In net support -----
443 JZ SaveNoShare
; no sharer
444 JMP SaveShare
; sharer present
447 TEST ES:[DI].sf_flags
,devid_device
448 JNZ SaveNoShareDev
; Device
450 ; Save no sharing local file information
452 MOV AX,WORD PTR ES:[DI].sf_dirsec
; get directory sector F.C.
453 MOV [SI].fcb_nsl_dirsec
,AX
454 MOV AL,ES:[DI].sf_dirpos
; location in sector
455 MOV [SI].fcb_nsl_dirpos
,AL
456 MOV AX,ES:[DI].sf_firclus
; first cluster
457 MOV [SI].fcb_nsl_firclus
,AX
460 ; Create the bits field from the dirty/device bits of the flags word and the
464 MOV AX,ES:[DI].sf_flags
465 AND AL,0C0h ; mask off drive bits
466 OR AL,BYTE PTR ES:[DI].sf_mode
; stick in open mode
467 MOV [SI].fcb_nsl_bits
,AL ; save dirty info
468 JMP SaveSFN
; go and save SFN
471 ; Save no sharing local device information
474 MOV AX,WORD PTR ES:[DI].sf_devptr
475 MOV WORD PTR [SI].FCB_nsld_drvptr
,AX
476 MOV AX,WORD PTR ES:[DI].sf_devptr
+ 2
477 MOV WORD PTR [SI].FCB_nsld_drvptr
+ 2,AX
479 JMP SetFCBBits
; go and save SFN
484 ;----- In share support -----
492 ;----- end in share support -----
495 MOV AX,ES:[DI].sf_flags
496 AND AL,3Fh
; get real drive
498 MOV [SI].fcb_l_drive
,AL
501 ; Adjust for offset to table.
503 SUB AX,WORD PTR SftFCB
506 MOV [SI].FCB_sfn
,AL ; last used SFN
507 MOV AX,FCBLRU
; get lru count
509 MOV WORD PTR ES:[DI].sf_LRU
,AX
512 ; lru flag overflowed. Run through all FCB sfts and adjust: LRU < 8000h
513 ; get set to 0. Others -= 8000h. This LRU = 8000h
525 Break <ResetLRU
- reset overflowed lru counts
>
528 ; ResetLRU - during lru updates, we may wrap at 64K. We must walk the
529 ; entire set of SFTs and subtract 8000h from their lru counts and truncate
532 ; Inputs: BX is offset into SFT field where lru firld is kept
533 ; ES:DI point to SFT currently being updated
534 ; Outputs: All FCB SFTs have their lru fields truncated
536 ; Registers modified: none
538 Procedure ResetLRU
,NEAR
539 ASSUME
CS:DOSGroup
,DS:NOTHING
,ES:NOTHING
,SS:NOTHING
540 Assert ISSFT
,<ES,DI>,"ResetLRU"
543 LES DI,sftFCB
; get pointer to head
544 MOV CX,ES:[DI].sfCount
545 LEA DI,[DI].sfTable
; point at table
547 SUB WORD PTR ES:[DI+BX],AX ; decrement lru count
549 MOV WORD PTR ES:[DI.BX],AX ; truncate at 0
551 ADD DI,SIZE SF_Entry
; advance to next
558 Break <SetOpenAge
- update the open age of a SFT
>
561 ; SetOpenAge - In order to maintain the first N open files in the FCB cache,
562 ; we keep the 'open age' or an LRU count based on opens. We update the
563 ; count here and fill in the appropriate field.
565 ; Inputs: ES:DI point to SFT
566 ; Outputs: ES:DI has the open age field filled in.
567 ; If open age has wraparound, we will have subtracted 8000h
568 ; from all open ages.
569 ; Registers modified: AX
572 Procedure SetOpenAge
,NEAR
573 ASSUME
CS:DOSGroup
,DS:NOTHING
,ES:NOTHING
,SS:NOTHING
574 Assert ISSFT
,<ES,DI>,"SetOpenAge"
577 MOV ES:[DI].sf_OpenAge
,AX
586 Break <LRUFCB
- perform LRU
on FCB sfts
>
589 ; LRUFCB - find LRU fcb in cache. Set ThisSFT and return it. We preserve
590 ; the first keepcount sfts if they are network sfts or if sharing is
591 ; loaded. If carry is set then NO BLASTING is NECESSARY.
594 ; Outputs: ES:DI point to SFT
595 ; ThisSFT points to SFT
597 ; Carry set of closes failed
598 ; Registers modified: none
601 Procedure LRUFCB
,NEAR
602 ASSUME
CS:DOSGroup
,DS:NOTHING
,ES:NOTHING
,SS:NOTHING
605 ; Find nth oldest NET/SHARE FCB. We want to find its age for the second scan
606 ; to find the lease recently used one that is younger than the open age. We
607 ; operate be scanning the list n times finding the least age that is greater
608 ; or equal to the previous minimum age.
610 ; BP is the count of times we need to go through this loop.
611 ; AX is the current acceptable minimum age to consider
613 mov bp,KeepCount
; k = keepcount;
616 ; If we've scanned the table n times, then we are done.
619 CMP bp,0 ; while (k--) {
625 ; AX is the minimum age for consideration
626 ; BX is the minimum age found during the scan
627 ; SI is the position of the entry that corresponds to BX
629 MOV BX,-1 ; min = 0xffff;
630 MOV si,BX ; pos = 0xffff;
631 LES DI,SFTFCB
; for (CX=FCBCount; CX>0; CX--)
632 MOV CX,ES:[DI].sfCount
635 ; Innermost loop. If the current entry is free, then we are done. Or, if the
636 ; current entry is busy (indicating a previous aborted allocation), then we
637 ; are done. In both cases, we use the found entry.
640 cmp es:[di].sf_ref_count
,0
642 cmp es:[di].sf_ref_count
,sf_busy
645 ; The entry is usable without further scan. Go and use it.
649 JMP lru11
; goto got;
651 ; See if the entry is for the network or for the sharer.
653 ; If for the sharer or network then
654 ; if the age < current minimum AND >= allowed minimum then
655 ; this entry becomes current minimum
658 TEST ES:[DI].sf_flags
,sf_isnet
; if (!net[i]
661 Invoke CheckShare
; && !sharing)
665 ; This SFT is for the net or is for the sharer. See if it less than the
669 MOV DX,ES:[DI].sf_OpenAge
670 CMP DX,AX ; if (age[i] >= low &&
673 JAE lru5
; age[i] < min) {
675 ; entry is new minimum. Remember his age.
677 mov bx,DX ; min = age[i];
680 ; End of loop. gp back for more
686 ; The scan is complete. If we have successfully found a new minimum (pos != -1)
687 ; set then threshold value to this new minimum + 1. Otherwise, the scan is
688 ; complete. Go find LRU.
690 lru6: cmp si,-1 ; position not -1?
691 jz lru75
; no, done with everything
692 lea ax,[bx+1] ; set new threshold age
693 jmp lru1
; go and loop for more
695 jmp short lruDead
; return -1;
697 ; Main loop is done. We have AX being the age+1 of the nth oldest sharer or
698 ; network entry. We now make a second pass through to find the LRU entry
699 ; that is local-no-share or has age >= AX
702 mov bx,-1 ; min = 0xffff;
703 mov si,bx ; pos = 0xffff;
704 LES DI,SFTFCB
; for (CX=FCBCount; CX>0; CX--)
705 MOV CX,ES:[DI].sfCount
708 ; If this is is local-no-share then go check for LRU else if age >= threshold
709 ; then check for lru.
712 TEST ES:[DI].sf_flags
,sf_isnet
713 jnz lru85
; is for network, go check age
714 invoke CheckShare
; sharer here?
715 jz lru86
; no, go check lru
717 ; Network or sharer. Check age
720 cmp es:[di].sf_OpenAge
,ax
721 jb lru9
; age is before threshold, skip it
726 cmp es:[di].sf_LRU
,bx ; is LRU less than current LRU?
727 jae lru9
; no, skip this
728 mov si,di ; remember position
729 mov bx,es:[di].sf_LRU
; remember new minimum LRU
731 ; Done with this entry, go back for more.
737 ; Scan is complete. If we found NOTHING that satisfied us then we bomb
738 ; out. The conditions here are:
740 ; No local-no-shares AND all net/share entries are older than threshold
743 cmp si,-1 ; if no one f
744 jz lru65
; return -1;
747 MOV WORD PTR ThisSFT
,DI ; set thissft
748 MOV WORD PTR ThisSFT
+2,ES
750 ; If we have sharing or thisSFT is a net sft, then close it until ref count
753 TEST ES:[DI].sf_flags
,sf_isNet
760 ; Repeat close until ref count is 0
765 CMP ES:[DI].sf_ref_count
,0 ; is ref count still <> 0?
766 JZ LRUDone
; nope, all done
768 ; Message 1,"LRUFCB: closing "
769 ; MessageNum <WORD PTR THISSFT+2>
771 ; MessageNum <WORD PTR THISSFT>
774 jnc LRUClose
; no error => clean up
775 cmp al,error_invalid_handle
781 invoke BlastSFT
; fill SFT with 0 (AL)
786 Assert ISSFT
,<ES,DI>,"LRUFCB return"
788 MOV AL,error_FCB_unavailable
792 Break <FCBRegen
- regenerate a sft
from the info
in the FCB
>
795 ; FCBRegen - examine reserved field of FCB and attempt to generate the SFT
798 ; Inputs: DS:SI point to FCB
799 ; Outputs: carry clear Filled in SFT
800 ; Carry set unrecoverable error
801 ; Registers modified: all
803 Procedure FCBRegen
,NEAR
804 ASSUME
DS:NOTHING
,ES:NOTHING
806 ; General data filling. Mode is sf_isFCB + open_for_both, date/time we do
807 ; not fill, size we do no fill, position we do not fill,
808 ; bit 14 of flags = TRUE, other bits = FALSE
810 MOV AL,[SI].fcb_l_drive
812 ; We discriminate based on the first two bits in the reserved field.
814 TEST AL,FCBSPECIAL
; check for no sharing test
815 JZ RegenNoSharing
; yes, go regen from no sharing
817 ; The FCB is for a network or a sharing based system. At this point we have
818 ; already closed the SFT for this guy and reconnection is impossible.
820 ; Remember that he may have given us a FCB with bogus information in it.
821 ; Check to see if sharing is present or if the redir is present. If either is
822 ; around, presume that we have cycled out the FCB and give the hard error.
823 ; Otherwise, just return with carry set.
825 invoke CheckShare
; test for sharer
826 JNZ RegenFail
; yep, fail this.
827 MOV AX,multNet
SHL 8 ; install check on multnet
829 OR AL,AL ; is it there?
830 JZ RegenDead
; no, just fail the operation
835 invoke FCBHardErr
; massive hard error.
840 ; Local FCB without sharing. Check to see if sharing is loaded. If so
841 ; fail the operation.
844 invoke CheckShare
; Sharing around?
847 ; Find an SFT for this guy.
851 MOV ES:[DI].sf_mode
,SF_IsFCB
+ open_for_both
+ sharing_compat
852 AND AL,3Fh
; get drive number for flags
854 OR AX,sf_close_noDate
; normal FCB operation
856 ; The bits field consists of the upper two bits (dirty and device) from the
857 ; SFT and the low 4 bits from the open mode.
859 MOV CL,[SI].FCB_nsl_bits
; stick in dirty bits.
861 AND CH,0C0h ; mask off the dirty/device bits
863 AND CL,access_mask
; get the mode bits
864 MOV BYTE PTR ES:[DI].sf_mode
,CL
865 MOV ES:[DI].sf_flags
,AX ; initial flags
867 MOV ES:[DI].sf_PID
,AX
868 SaveReg
<DS,SI,ES,DI>
870 MOV DI,OFFSET DOSGroup
:Name1
872 INC SI ; Skip past drive byte to name in FCB
877 invoke testkanj
;AN000;
881 JCXZ DoneNam2
;AN000; ; Ignore split kanji char error
883 jmp short StuffChar2
;AN000;
894 MOV [ATTRIB
],attr_hidden
+ attr_system
+ attr_directory
895 ; Must set this to something interesting
897 Invoke DevName
; check for device
898 ASSUME
DS:NOTHING
,ES:NOTHING
899 RestoreReg
<DI,ES,SI,DS>
900 JC RegenFileNoSharing
; not found on device list => file
902 ; Device found. We can ignore disk-specific info
904 MOV BYTE PTR ES:[DI].sf_flags
,BH ; device parms
905 MOV ES:[DI].sf_attr
,0 ; attribute
906 LDS SI,DEVPT
; get device driver
907 MOV WORD PTR ES:[DI].sf_devptr
,SI
908 MOV WORD PTR ES:[DI].sf_devptr
+2,DS
909 return
; carry is clear
914 ; File found. Just copy in the remaining pieces.
917 MOV AX,ES:[DI].sf_flags
921 MOV WORD PTR ES:[DI].sf_devptr
,SI
922 MOV WORD PTR ES:[DI].sf_devptr
+2,DS
924 jc RegenDeadJ
; if find DPB fails, then drive
925 ; indicator was bogus
926 MOV AX,[SI].FCB_nsl_dirsec
927 MOV WORD PTR ES:[DI].sf_dirsec
,AX
928 MOV WORD PTR ES:[DI].sf_dirsec
+2,0 ;AN000;>32mb
929 MOV AX,[SI].FCB_nsl_firclus
930 MOV ES:[DI].sf_firclus
,AX
931 MOV ES:[DI].sf_lstclus
,AX
932 MOV AL,[SI].FCB_nsl_dirpos
933 MOV ES:[DI].sf_dirpos
,AL
934 INC ES:[DI].sf_ref_count
; Increment reference count.
935 ; Existing FCB entries would be
936 ; flushed unnecessarily because of
937 ; check in CheckFCB of the ref_count.
941 MOV CX,fcb_extent
-fcb_name
950 JCXZ DoneNam
; Ignore split kanji char error
967 ; BlastSFT - fill SFT with garbage
969 ; Inputs: ES:DI point to SFT
971 ; Outputs: SFT is filled with nonsense
973 ; Registers modified: CX
975 Procedure BlastSFT
,NEAR
980 MOV ES:[DI].sf_ref_count
,0 ; set ref count
981 MOV ES:[DI].sf_LRU
,0 ; set lru
982 MOV ES:[DI].sf_OpenAge
,-1 ; Set open age
986 Break <CheckFCB
- see
if the SFT pointed to by the FCB is still OK
>
988 ; CheckFCB - examine an FCB and its contents to see if it needs to be
991 ; Inputs: DS:SI point to FCB (not extended)
993 ; Outputs: Carry Set - FCB needs to be regened
994 ; Carry clear - FCB is OK. ES:DI point to SFT
995 ; Registers modified: AX and BX
997 Procedure CheckFCB
,NEAR
998 ASSUME
DS:NOTHING
,ES:NOTHING
1000 CMP BYTE PTR ES:[DI].SFCount
,AL
1002 MOV BL,SIZE sf_entry
1007 CMP ES:[DI].sf_PID
,AX
1008 JNZ BadSFT
; must match process
1009 CMP ES:[DI].sf_ref_count
,0
1010 JZ BadSFT
; must also be in use
1011 MOV AL,[SI].FCB_l_Drive
1012 TEST AL,FCBSPECIAL
; a special FCB?
1013 JZ CheckNoShare
; No. try local or device
1015 ; Since we are a special FCB, try NOT to use a bogus test instruction.
1016 ; FCBSHARE is a superset of FCBNETWORK.
1020 CMP AL,FCBSHARE
; net FCB?
1024 ;----- In share support -----
1027 Call JShare
+ 11 * 4
1034 ;----- End in share support -----
1037 CMP BX,ES:[DI].sf_firclus
1040 MOV AH,BYTE PTR ES:[DI].sf_flags
1043 retz
; carry is clear
1045 return
; carry is clear
1048 ;----- In net support -----
1050 ; MOV AX,[SI].FCB_net_handle
1051 ; CMP AX,WORD PTR ES:[DI].sf_NETID+4
1053 ; MOV AX,WORD PTR [SI].FCB_netID
1054 ; CMP AX,WORD PTR ES:[DI].sf_netid
1056 MOV AX,WORD PTR [SI].FCB_netID
;AN000;IFS.DOS 4.00
1057 CMP AX,WORD PTR ES:[DI].sf_serial_ID
;AN000;IFS.DOS 4.00
1060 ;----- END In net support -----
1065 TEST AL,FCBDEVICE
; Device?
1066 JNZ CheckNoShareDev
; Yes
1068 ; Check no sharing local file
1070 MOV BX,[SI].FCB_nsl_Dirsec
1071 CMP WORD PTR ES:[DI].sf_dirsec
+2,0 ;AN000;F.C. >32mb
1072 JNZ BadSFt
;AN000;F.C. >32mb
1074 CMP BX,WORD PTR ES:[DI].sf_dirsec
;AN000;F.C. >32mb
1076 MOV BL,[SI].FCB_nsl_Dirpos
1077 CMP BL,ES:[DI].sf_dirpos
1080 ; Since the bits field comes from two different spots, compare them separately.
1082 MOV BL,[SI].FCB_nsl_bits
1083 MOV BH,BYTE PTR ES:[DI].sf_flags
1086 JNZ BadSFT
; dirty/device bits are different
1087 XOR BL,BYTE PTR ES:[DI].sf_mode
1089 JNZ BadSFT
; access modes are different
1090 ; Make sure that the names are the same in the FCB and the SFT
1091 ; This case can appear under the following scenario:
1095 ; The SFT will still contain the name for the old file name.
1100 LEA SI,[SI].fcb_name
1106 MOV BX,[SI].FCB_nsl_firclus
1110 MOV BX,WORD PTR [SI].FCB_nsld_drvptr
1111 CMP BX,WORD PTR ES:[DI].sf_devptr
1113 MOV BX,WORD PTR [SI].FCB_nsld_drvptr
+ 2
1114 CMP BX,WORD PTR ES:[DI].sf_devptr
+ 2
1120 Break <SFTFromFCB
- take a FCB
and obtain a SFT
from it
>
1123 ; SFTFromFCB - the workhorse of this compatability crap. Check to see if
1124 ; the SFT for the FCB is Good. If so, make ThisSFT point to it. If not
1125 ; good, get one from the cache and regenerate it. Overlay the LRU field
1128 ; Inputs: DS:SI point to FCB
1129 ; Outputs: ThisSFT point to appropriate SFT
1130 ; Carry clear -> OK ES:DI -> SFT
1131 ; Carry set -> error in ax
1132 ; Registers modified: ES,DI, AX
1134 Procedure SFTFromFCB
,NEAR
1135 ASSUME
DS:NOTHING
,ES:NOTHING
1137 MOV AL,[SI].fcb_sfn
; set SFN for check
1140 MOV WORD PTR ThisSFT
,DI ; set thissft
1141 MOV WORD PTR ThisSFT
+2,ES
1142 JNC SetSFT
; no problems, just set thissft
1144 fmt typFCB
,LevCheck
,<"FCB $x:$x does not match SFT $x:$x\n">,<DS,SI,ES,DI>
1148 Invoke Restore_World
; restore world
1152 ; Message 1,<"FCBRegen Succeeded",13,10>
1154 SetSFT: LES DI,ThisSFT
1155 PUSH Proc_ID
; set process id
1157 return
; carry is clear
1160 Break <FCBHardErr
- generate
INT 24 for hard errors
on FCBS
>
1163 ; FCBHardErr - signal to a user app that he is trying to use an
1168 ; Registers modified: all
1171 Procedure FCBHardErr
,NEAR
1172 ASSUME
DS:NOTHING
,ES:NOTHING
1173 MOV AX,error_FCB_Unavailable
1174 MOV [ALLOWED
],allowed_FAIL
1176 MOV DI,1 ; Fake some registers
1178 MOV DX,ES:[BP.dpb_first_sector
]