summaryrefslogtreecommitdiff
path: root/v4.0/src/DOS/FCBIO.ASM
diff options
context:
space:
mode:
Diffstat (limited to 'v4.0/src/DOS/FCBIO.ASM')
-rw-r--r--v4.0/src/DOS/FCBIO.ASM1185
1 files changed, 1185 insertions, 0 deletions
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 @@
1; SCCSID = @(#)fcbio.asm 1.5 85/07/30
2; SCCSID = @(#)fcbio.asm 1.5 85/07/30
3TITLE FCBIO - FCB system calls
4NAME 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.xlist
38;
39; get the appropriate segment definitions
40;
41include dosseg.asm
42
43CODE SEGMENT BYTE PUBLIC 'CODE'
44 ASSUME SS:DOSGROUP,CS:DOSGROUP
45
46.xcref
47INCLUDE DOSSYM.INC
48INCLUDE DEVSYM.INC
49INCLUDE FASTOPEN.INC
50.cref
51.list
52
53 AsmVars <Kanji>
54
55 I_need OpenBuf,128 ; buffer for translating paths
56 I_need RenBuf,128 ; buffer for rename paths
57 i_need THISDPB,DWORD
58 i_need EXTERR,WORD
59 i_need ALLOWED,BYTE
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
74if debug
75 I_need BugLev,WORD
76 I_need BugTyp,WORD
77 include bugtyp.asm
78endif
79
80
81Break <$Get_FCB_Position - set random record fields to current pos>
82
83;
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
86; to that record
87;
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
91
92Procedure $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
99 JAE GetFCBBye
100 MOV [SI+fcb_RR+2+1],DH ; Set 4th byte only if record size < 64
101GetFCBBye:
102 transfer FCB_Ret_OK
103EndProc $GET_FCB_POSITION
104
105Break <$FCB_Delete - remove several files that match the input FCB>
106
107;
108; $FCB_delete - given an FCB, remove all directory entries in the current
109; directory that have names that match the FCB's ? marks.
110;
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
115
116Procedure $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
121 Context DS
122 invoke DOS_Delete ; wham
123 JC BadPath
124GoodPath:
125 transfer FCB_Ret_OK ; do a good return
126BadPath:
127;
128
129; Error code is in AX
130;
131 transfer FCB_Ret_Err ; let someone else signal the error
132EndProc $FCB_DELETE
133
134Break <$Get_FCB_File_Length - return the length of a file>
135
136;
137; $Get_FCB_File_Length - set the random record field to the length of the
138; file in records (rounded up if partial).
139;
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
143
144Procedure $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
151 RestoreReg <SI,DS>
152 JC BadPath
153 SaveReg <DS,SI> ; save pointer
154 Context DS
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
163 MOV BX,128
164GetSize:
165 MOV DI,AX ; save low order word
166 MOV AX,DX ; move high order for divide
167 XOR DX,DX ; clear out high
168 DIV BX ; wham
169 PUSH AX ; save dividend
170 MOV AX,DI ; get low order piece
171 DIV BX ; wham
172 MOV CX,DX ; save remainder
173 POP DX ; get high order dividend
174 JCXZ LengthStore ; no roundup
175 ADD AX,1
176 ADC DX,0 ; 32-bit increment
177LengthStore:
178 MOV WORD PTR [SI.FCB_RR],AX ; store low order
179 MOV [SI.FCB_RR+2],DL ; store high order
180 OR DH,DH
181 JZ GoodPath ; not storing insignificant zero
182 MOV [SI.FCB_RR+3],DH ; save that high piece
183GoodRet:
184 transfer FCB_Ret_OK
185EndProc $GET_FCB_FILE_LENGTH
186
187Break <$FCB_Close - close a file>
188
189;
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
192;
193; Inputs: DS:DX point to FCB
194; Outputs: AL = FF if file was not found on disk
195; Registers modified: all
196
197Procedure $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
203NoAttr:
204 MOV [Attrib],AL ; stash away found attributes
205 invoke SFTFromFCB
206 JC GoodRet ; MZ 16 Jan Assume death
207;
208; If the sharer is present, then the SFT is not regenable. Thus, there is
209; no need to set the SFT's attribute.
210;
211;;; 9/8/86 F.C. save SFT attribute and restore it back when close is done
212 MOV AL,ES:[DI].sf_attr
213 XOR AH,AH
214 PUSH AX
215;;; 9/8/86 F.C. save SFT attribute and restore it back when close is done
216 invoke CheckShare
217 JNZ NoStash
218 MOV AL,Attrib
219 MOV ES:[DI].sf_attr,AL ; attempted attribute for close
220NoStash:
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
232 LES DI,ThisSFT
233;;; 9/8/86 F.C. restore SFT attribute
234 POP CX
235 MOV ES:[DI].sf_attr,CL
236;;; 9/8/86 F.C. restore SFT attribute
237 PUSHF
238 TEST ES:[DI.sf_ref_count],-1 ; zero ref count gets blasted
239 JNZ CloseOK
240 PUSH AX
241 MOV AL,'M'
242 invoke BlastSFT
243 POP AX
244CloseOK:
245 POPF
246 JNC GoodRet
247 CMP AL,error_invalid_handle
248 JZ GoodRet
249 MOV AL,error_file_not_found
250 transfer FCB_Ret_Err
251EndProc $FCB_CLOSE
252
253Break <$FCB_Rename - change names in place>
254
255;
256; $FCB_Rename - rename a file in place within a directory. Renames multiple
257; files copying from the meta characters.
258;
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
266
267Procedure $FCB_Rename,NEAR
268 ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:DOSGroup
269 invoke GetExtended ; get pointer to real FCB
270 SaveReg <DX>
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
288 JC BadRen ; error
289 invoke DOS_Rename
290 JC BadRen
291 transfer FCB_Ret_OK
292BadRen:
293;
294; AL has error code
295;
296 transfer FCB_Ret_Err
297
298EndProc $FCB_RENAME
299
300Break <Misbehavior fixers>
301
302;
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
307; usage.
308;
309; This results in the following misbehavior:
310;
311; infinite opens of the same file:
312;
313; While (TRUE) { While (TRUE) {
314; FCBOpen (FCB); FCBOpen (FCB);
315; Read (FCB); Write (FCB);
316; } }
317;
318; infinite opens of different files:
319;
320; While (TRUE) { While (TRUE) {
321; FCBOpen (FCB[i++]); FCBOpen (FCB[i++]);
322; Read (FCB); Write (FCB);
323; } }
324;
325; multiple closes of the same file:
326;
327; FCBOpen (FCB);
328; while (TRUE)
329; FCBClose (FCB);
330;
331; I/O after closing file:
332;
333; FCBOpen (FCB);
334; while (TRUE) {
335; FCBWrite (FCB);
336; FCBClose (FCB);
337; }
338;
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
343; the local machine.
344;
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.
351;
352; No regeneration of SFTs is attempted for network FCBs.
353;
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
356; regenerated.
357;
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
360; information:
361;
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.
366; The last used SFT.
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
370;
371;
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.
374;
375; Some key items need to be remembered:
376;
377; Even though we are caching SFTs, they may contain useful sharing
378; information. We enforce good behavior on the FCBs.
379;
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.
382;
383; If this is not an installed version of the DOS, file sharing will
384; always be present.
385;
386; We MUST always initialize lstclus to = firclus when regenerating a
387; file. Otherwise we start allocating clusters up the wazoo.
388;
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
391; proper OI record.
392;
393; The test bits are:
394;
395; 00 -> local file
396; 40 -> sharing local
397; 80 -> network
398; C0 -> local device
399
400Break <SaveFCBInfo - store pertinent information from an SFT into the FCB>
401
402;
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.
406;
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.
410; DS:SI preserved
411; ES:DI point to sft
412; Registers modified: All
413;
414
415Procedure SaveFCBInfo,NEAR
416 ASSUME CS:DOSGroup,DS:NOTHING,ES:NOTHING,SS:DOSGroup
417 LES DI,ThisSFT
418 Assert ISSFT,<ES,DI>,"SaveFCBInfo"
419 invoke IsSFTNet
420 JZ SaveLocal ; if not network then save local info
421;
422;----- In net support -----
423;
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.
426; SaveReg <ES,DI>
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
430; RestoreReg <DI,ES>
431 MOV BL,FCBNETWORK
432;
433;----- END In net support -----
434;
435IF debug
436 JMP SaveSFN
437ELSE
438 JMP SHORT SaveSFN
439ENDIF
440SaveLocal:
441 IF Installed
442 Invoke CheckShare
443 JZ SaveNoShare ; no sharer
444 JMP SaveShare ; sharer present
445
446SaveNoShare:
447 TEST ES:[DI].sf_flags,devid_device
448 JNZ SaveNoShareDev ; Device
449;
450; Save no sharing local file information
451;
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
458 MOV BL,00
459;
460; Create the bits field from the dirty/device bits of the flags word and the
461; mode byte
462;
463SetFCBBits:
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
469
470;
471; Save no sharing local device information
472;
473SaveNoShareDev:
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
478 MOV BL,FCBDEVICE
479 JMP SetFCBBits ; go and save SFN
480
481SaveShare:
482 ENDIF
483;
484;----- In share support -----
485;
486if installed
487 Call JShare + 10 * 4
488else
489 Call ShSave
490endif
491;
492;----- end in share support -----
493;
494SaveSFN:
495 MOV AX,ES:[DI].sf_flags
496 AND AL,3Fh ; get real drive
497 OR AL,BL
498 MOV [SI].fcb_l_drive,AL
499 LEA AX,[DI-SFTable]
500;
501; Adjust for offset to table.
502;
503 SUB AX,WORD PTR SftFCB
504 MOV BL,SIZE sf_entry
505 DIV BL
506 MOV [SI].FCB_sfn,AL ; last used SFN
507 MOV AX,FCBLRU ; get lru count
508 INC AX
509 MOV WORD PTR ES:[DI].sf_LRU,AX
510 JNZ SimpleStuff
511;
512; lru flag overflowed. Run through all FCB sfts and adjust: LRU < 8000h
513; get set to 0. Others -= 8000h. This LRU = 8000h
514;
515 MOV BX,sf_position
516 invoke ResetLRU
517;
518; Set new LRU to AX
519;
520SimpleStuff:
521 MOV FCBLRU,AX
522 return
523EndProc SaveFCBInfo
524
525Break <ResetLRU - reset overflowed lru counts>
526
527;
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
530; at 0.
531;
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
535; AX has 8000h
536; Registers modified: none
537
538Procedure ResetLRU,NEAR
539 ASSUME CS:DOSGroup,DS:NOTHING,ES:NOTHING,SS:NOTHING
540 Assert ISSFT,<ES,DI>,"ResetLRU"
541 MOV AX,8000h
542 SaveReg <ES,DI>
543 LES DI,sftFCB ; get pointer to head
544 MOV CX,ES:[DI].sfCount
545 LEA DI,[DI].sfTable ; point at table
546ovScan:
547 SUB WORD PTR ES:[DI+BX],AX ; decrement lru count
548 JA ovLoop
549 MOV WORD PTR ES:[DI.BX],AX ; truncate at 0
550ovLoop:
551 ADD DI,SIZE SF_Entry ; advance to next
552 LOOP ovScan
553 RestoreReg <DI,ES>
554 MOV ES:[DI+BX],AX
555 return
556EndProc ResetLRU
557
558Break <SetOpenAge - update the open age of a SFT>
559
560;
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.
564;
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
570;
571
572Procedure SetOpenAge,NEAR
573 ASSUME CS:DOSGroup,DS:NOTHING,ES:NOTHING,SS:NOTHING
574 Assert ISSFT,<ES,DI>,"SetOpenAge"
575 MOV AX,OpenLRU
576 INC AX
577 MOV ES:[DI].sf_OpenAge,AX
578 JNZ SetDone
579 MOV BX,sf_Position+2
580 invoke ResetLRU
581SetDone:
582 MOV OpenLRU,AX
583 return
584EndProc SetOpenAge
585
586Break <LRUFCB - perform LRU on FCB sfts>
587
588;
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.
592;
593; Inputs: none
594; Outputs: ES:DI point to SFT
595; ThisSFT points to SFT
596; SFT is zeroed
597; Carry set of closes failed
598; Registers modified: none
599;
600
601Procedure LRUFCB,NEAR
602 ASSUME CS:DOSGroup,DS:NOTHING,ES:NOTHING,SS:NOTHING
603 Invoke Save_World
604;
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.
609;
610; BP is the count of times we need to go through this loop.
611; AX is the current acceptable minimum age to consider
612;
613 mov bp,KeepCount ; k = keepcount;
614 XOR AX,AX ; low = 0;
615;
616; If we've scanned the table n times, then we are done.
617;
618lru1:
619 CMP bp,0 ; while (k--) {
620 JZ lru75
621 DEC bp
622;
623; Set up for scan.
624;
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
628;
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
633 LEA DI,[DI].sfTable
634;
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.
638;
639lru2:
640 cmp es:[di].sf_ref_count,0
641 jz lru25
642 cmp es:[di].sf_ref_count,sf_busy
643 jnz lru3
644;
645; The entry is usable without further scan. Go and use it.
646;
647lru25:
648 MOV si,DI ; pos = i;
649 JMP lru11 ; goto got;
650;
651; See if the entry is for the network or for the sharer.
652;
653; If for the sharer or network then
654; if the age < current minimum AND >= allowed minimum then
655; this entry becomes current minimum
656;
657lru3:
658 TEST ES:[DI].sf_flags,sf_isnet ; if (!net[i]
659 JNZ lru35
660if installed
661 Invoke CheckShare ; && !sharing)
662 JZ lru5 ; else
663ENDIF
664;
665; This SFT is for the net or is for the sharer. See if it less than the
666; current minimum.
667;
668lru35:
669 MOV DX,ES:[DI].sf_OpenAge
670 CMP DX,AX ; if (age[i] >= low &&
671 JB lru5
672 CMP DX,BX
673 JAE lru5 ; age[i] < min) {
674;
675; entry is new minimum. Remember his age.
676;
677 mov bx,DX ; min = age[i];
678 mov si,di ; pos = i;
679;
680; End of loop. gp back for more
681;
682lru5:
683add di,size sf_entry
684 loop lru2 ; }
685;
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.
689;
690lru6: 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
694lru65: stc
695 jmp short lruDead ; return -1;
696;
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
700;
701lru75:
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
706 LEA DI,[DI].sfTable
707;
708; If this is is local-no-share then go check for LRU else if age >= threshold
709; then check for lru.
710;
711lru8:
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
716;
717; Network or sharer. Check age
718;
719lru85:
720 cmp es:[di].sf_OpenAge,ax
721 jb lru9 ; age is before threshold, skip it
722;
723; Check LRU
724;
725lru86:
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
730;
731; Done with this entry, go back for more.
732;
733lru9:
734 add di,size sf_entry
735 loop lru8
736;
737; Scan is complete. If we found NOTHING that satisfied us then we bomb
738; out. The conditions here are:
739;
740; No local-no-shares AND all net/share entries are older than threshold
741;
742lru10:
743 cmp si,-1 ; if no one f
744 jz lru65 ; return -1;
745lru11:
746 mov di,si
747 MOV WORD PTR ThisSFT,DI ; set thissft
748 MOV WORD PTR ThisSFT+2,ES
749;
750; If we have sharing or thisSFT is a net sft, then close it until ref count
751; is 0.
752;
753 TEST ES:[DI].sf_flags,sf_isNet
754 JNZ LRUClose
755IF INSTALLED
756 Invoke CheckShare
757 JZ LRUDone
758ENDIF
759;
760; Repeat close until ref count is 0
761;
762LRUClose:
763 Context DS
764 LES DI,ThisSFT
765 CMP ES:[DI].sf_ref_count,0 ; is ref count still <> 0?
766 JZ LRUDone ; nope, all done
767
768; Message 1,"LRUFCB: closing "
769; MessageNum <WORD PTR THISSFT+2>
770; Message 1,":"
771; MessageNum <WORD PTR THISSFT>
772
773 Invoke DOS_Close
774 jnc LRUClose ; no error => clean up
775 cmp al,error_invalid_handle
776 jz LRUClose
777 stc
778 JMP short LRUDead
779LRUDone:
780 XOR AL,AL
781 invoke BlastSFT ; fill SFT with 0 (AL)
782LRUDead:
783 Invoke Restore_World
784 ASSUME DS:NOTHING
785 LES DI,ThisSFT
786 Assert ISSFT,<ES,DI>,"LRUFCB return"
787 retnc
788 MOV AL,error_FCB_unavailable
789 return
790EndProc LRUFCB
791
792Break <FCBRegen - regenerate a sft from the info in the FCB>
793
794;
795; FCBRegen - examine reserved field of FCB and attempt to generate the SFT
796; from it.
797;
798; Inputs: DS:SI point to FCB
799; Outputs: carry clear Filled in SFT
800; Carry set unrecoverable error
801; Registers modified: all
802
803Procedure FCBRegen,NEAR
804 ASSUME DS:NOTHING,ES:NOTHING
805;
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
809;
810 MOV AL,[SI].fcb_l_drive
811;
812; We discriminate based on the first two bits in the reserved field.
813;
814 TEST AL,FCBSPECIAL ; check for no sharing test
815 JZ RegenNoSharing ; yes, go regen from no sharing
816;
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.
819;
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.
824;
825 invoke CheckShare ; test for sharer
826 JNZ RegenFail ; yep, fail this.
827 MOV AX,multNet SHL 8 ; install check on multnet
828 INT 2FH
829 OR AL,AL ; is it there?
830 JZ RegenDead ; no, just fail the operation
831RegenFail:
832 MOV AX,User_In_AX
833 cmp AH,fcb_close
834 jz RegenDead
835 invoke FCBHardErr ; massive hard error.
836RegenDead:
837 STC
838 return ; carry set
839;
840; Local FCB without sharing. Check to see if sharing is loaded. If so
841; fail the operation.
842;
843RegenNoSharing:
844 invoke CheckShare ; Sharing around?
845 JNZ RegenFail
846;
847; Find an SFT for this guy.
848;
849 invoke LRUFcb
850 retc
851 MOV ES:[DI].sf_mode,SF_IsFCB + open_for_both + sharing_compat
852 AND AL,3Fh ; get drive number for flags
853 CBW
854 OR AX,sf_close_noDate ; normal FCB operation
855;
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.
858;
859 MOV CL,[SI].FCB_nsl_bits ; stick in dirty bits.
860 MOV CH,CL
861 AND CH,0C0h ; mask off the dirty/device bits
862 OR AL,CH
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
866 MOV AX,Proc_ID
867 MOV ES:[DI].sf_PID,AX
868 SaveReg <DS,SI,ES,DI>
869 Context ES
870 MOV DI,OFFSET DOSGroup:Name1
871 MOV CX,8
872 INC SI ; Skip past drive byte to name in FCB
873RegenCopyName2:
874 LODSB
875
876 IF DBCS ;AN000;
877 invoke testkanj ;AN000;
878 jz notkanj9 ;AN000;
879 STOSB ;AN000;
880 DEC CX ;AN000;
881 JCXZ DoneNam2 ;AN000; ; Ignore split kanji char error
882 LODSB ;AN000;
883 jmp short StuffChar2 ;AN000;
884 ;AN000;
885notkanj9: ;AN000;
886 ENDIF ;AN000;
887
888 Invoke UCase
889StuffChar2:
890 STOSB
891 LOOP RegenCopyName2
892DoneNam2:
893 Context DS
894 MOV [ATTRIB],attr_hidden + attr_system + attr_directory
895 ; Must set this to something interesting
896 ; to call DEVNAME.
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
901;
902; Device found. We can ignore disk-specific info
903;
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
910
911RegenDeadJ:
912 JMP RegenDead
913;
914; File found. Just copy in the remaining pieces.
915;
916RegenFileNoSharing:
917 MOV AX,ES:[DI].sf_flags
918 AND AX,03Fh
919 SaveReg <DS,SI>
920 Invoke Find_DPB
921 MOV WORD PTR ES:[DI].sf_devptr,SI
922 MOV WORD PTR ES:[DI].sf_devptr+2,DS
923 RestoreReg <SI,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.
938 ; July 22/85 - BAS
939 LEA SI,[SI].FCB_name
940 LEA DI,[DI].sf_name
941 MOV CX,fcb_extent-fcb_name
942RegenCopyName:
943 LODSB
944
945 IF DBCS ;AN000;
946 invoke testkanj
947 jz notkanj1
948 STOSB
949 DEC CX
950 JCXZ DoneNam ; Ignore split kanji char error
951 LODSB
952 jmp short StuffChar
953
954notkanj1:
955 ENDIF ;AN000;
956
957 Invoke UCase
958StuffChar:
959 STOSB
960 LOOP RegenCopyName
961DoneNam:
962 clc
963 return
964EndProc FCBRegen
965
966;
967; BlastSFT - fill SFT with garbage
968;
969; Inputs: ES:DI point to SFT
970; AL has fill
971; Outputs: SFT is filled with nonsense
972; *FLAGS PRESERVED*
973; Registers modified: CX
974
975Procedure BlastSFT,NEAR
976 SaveReg <DI>
977 MOV CX,SIZE sf_entry
978 REP STOSB
979 RestoreReg <DI>
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
983 return
984EndProc BlastSFT
985
986Break <CheckFCB - see if the SFT pointed to by the FCB is still OK>
987
988; CheckFCB - examine an FCB and its contents to see if it needs to be
989; regenerated.
990;
991; Inputs: DS:SI point to FCB (not extended)
992; AL is SFT index
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
996
997Procedure CheckFCB,NEAR
998 ASSUME DS:NOTHING,ES:NOTHING
999 LES DI,sftFCB
1000 CMP BYTE PTR ES:[DI].SFCount,AL
1001 JC BadSFT
1002 MOV BL,SIZE sf_entry
1003 MUL BL
1004 LEA DI,[DI].sftable
1005 ADD DI,AX
1006 MOV AX,Proc_ID
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
1014;
1015; Since we are a special FCB, try NOT to use a bogus test instruction.
1016; FCBSHARE is a superset of FCBNETWORK.
1017;
1018 PUSH AX
1019 AND AL,FCBMASK
1020 CMP AL,FCBSHARE ; net FCB?
1021 POP AX
1022 JNZ CheckNet ; yes
1023;
1024;----- In share support -----
1025;
1026if installed
1027 Call JShare + 11 * 4
1028else
1029 Call ShChk
1030endif
1031 JC BadSFT
1032 JMP SHORT CheckD
1033;
1034;----- End in share support -----
1035;
1036CheckFirClus:
1037 CMP BX,ES:[DI].sf_firclus
1038 JNZ BadSFT
1039CheckD: AND AL,3Fh
1040 MOV AH,BYTE PTR ES:[DI].sf_flags
1041 AND AH,3Fh
1042 CMP AH,AL
1043 retz ; carry is clear
1044BadSFT: STC
1045 return ; carry is clear
1046CheckNet:
1047;
1048;----- In net support -----
1049;
1050; MOV AX,[SI].FCB_net_handle
1051; CMP AX,WORD PTR ES:[DI].sf_NETID+4
1052; JNZ BadSFT
1053; MOV AX,WORD PTR [SI].FCB_netID
1054; CMP AX,WORD PTR ES:[DI].sf_netid
1055; JNZ BadSFT
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
1058 JNZ BadSFT
1059;
1060;----- END In net support -----
1061;
1062 return
1063
1064CheckNoShare:
1065 TEST AL,FCBDEVICE ; Device?
1066 JNZ CheckNoShareDev ; Yes
1067;
1068; Check no sharing local file
1069;
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
1073
1074 CMP BX,WORD PTR ES:[DI].sf_dirsec ;AN000;F.C. >32mb
1075 JNZ BadSFT
1076 MOV BL,[SI].FCB_nsl_Dirpos
1077 CMP BL,ES:[DI].sf_dirpos
1078 JNZ BadSFt
1079;
1080; Since the bits field comes from two different spots, compare them separately.
1081;
1082 MOV BL,[SI].FCB_nsl_bits
1083 MOV BH,BYTE PTR ES:[DI].sf_flags
1084 XOR BH,BL
1085 AND BH,0C0h
1086 JNZ BadSFT ; dirty/device bits are different
1087 XOR BL,BYTE PTR ES:[DI].sf_mode
1088 AND BL,access_mask
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:
1092; Create FOO
1093; Rename FOO -> BAR
1094; Open BAR
1095; The SFT will still contain the name for the old file name.
1096; July 30/85 - BAS
1097 PUSH DI
1098 PUSH SI
1099 LEA DI,[DI].sf_name
1100 LEA SI,[SI].fcb_name
1101 MOV CX,11
1102 REPE CMPSB
1103 POP SI
1104 POP DI
1105 JNZ BadSFT
1106 MOV BX,[SI].FCB_nsl_firclus
1107 JMP CheckFirClus
1108
1109CheckNoShareDev:
1110 MOV BX,WORD PTR [SI].FCB_nsld_drvptr
1111 CMP BX,WORD PTR ES:[DI].sf_devptr
1112 JNZ BadSFT
1113 MOV BX,WORD PTR [SI].FCB_nsld_drvptr + 2
1114 CMP BX,WORD PTR ES:[DI].sf_devptr + 2
1115 JNZ BadSFT
1116 JMP CheckD
1117
1118EndProc CheckFCB
1119
1120Break <SFTFromFCB - take a FCB and obtain a SFT from it>
1121
1122;
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
1126; with PID
1127;
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
1133
1134Procedure SFTFromFCB,NEAR
1135 ASSUME DS:NOTHING,ES:NOTHING
1136 SaveReg <AX,BX>
1137 MOV AL,[SI].fcb_sfn ; set SFN for check
1138 invoke CheckFCB
1139 RestoreReg <BX,AX>
1140 MOV WORD PTR ThisSFT,DI ; set thissft
1141 MOV WORD PTR ThisSFT+2,ES
1142 JNC SetSFT ; no problems, just set thissft
1143
1144 fmt typFCB,LevCheck,<"FCB $x:$x does not match SFT $x:$x\n">,<DS,SI,ES,DI>
1145
1146 Invoke Save_World
1147 invoke FCBRegen
1148 Invoke Restore_World ; restore world
1149 MOV AX,EXTERR
1150 retc
1151
1152; Message 1,<"FCBRegen Succeeded",13,10>
1153
1154SetSFT: LES DI,ThisSFT
1155 PUSH Proc_ID ; set process id
1156 POP ES:[DI].sf_PID
1157 return ; carry is clear
1158EndProc SFTFromFCB
1159
1160Break <FCBHardErr - generate INT 24 for hard errors on FCBS>
1161
1162;
1163; FCBHardErr - signal to a user app that he is trying to use an
1164; unavailable FCB.
1165;
1166; Inputs: none.
1167; Outputs: none.
1168; Registers modified: all
1169;
1170
1171Procedure FCBHardErr,NEAR
1172 ASSUME DS:NOTHING,ES:NOTHING
1173 MOV AX,error_FCB_Unavailable
1174 MOV [ALLOWED],allowed_FAIL
1175 LES BP,[THISDPB]
1176 MOV DI,1 ; Fake some registers
1177 MOV CX,DI
1178 MOV DX,ES:[BP.dpb_first_sector]
1179 invoke HARDERR
1180 STC
1181 return
1182EndProc FCBHardErr
1183
1184CODE ENDS
1185END