]> wirehaze git hosting - MS-DOS.git/blob - v4.0/src/DOS/FCBIO.ASM

wirehaze git hosting

MZ is back!
[MS-DOS.git] / v4.0 / src / DOS / FCBIO.ASM
1 ; SCCSID = @(#)fcbio.asm 1.5 85/07/30
2 ; SCCSID = @(#)fcbio.asm 1.5 85/07/30
3 TITLE FCBIO - FCB system calls
4 NAME FCBIO
5
6 ;
7 ; Ancient 1.0 1.1 FCB system calls
8 ; regen save
9 ; $GET_FCB_POSITION written none none
10 ; $FCB_DELETE written none none
11 ; $GET_FCB_FILE_LENGTH written none none
12 ; $FCB_CLOSE written close none
13 ; $FCB_RENAME written none none
14 ; SaveFCBInfo
15 ; ResetLRU
16 ; SetOpenAge
17 ; LRUFCB
18 ; FCBRegen
19 ; BlastSFT
20 ; CheckFCB
21 ; SFTFromFCB
22 ; FCBHardErr
23 ;
24 ; Revision history:
25 ;
26 ; Created: ARR 4 April 1983
27 ; MZ 6 June 1983 completion of functions
28 ; MZ 15 Dec 1983 Brain damaged programs close FCBs multiple
29 ; times. Change so successive closes work by
30 ; always returning OK. Also, detect I/O to
31 ; already closed FCB and return EOF.
32 ; MZ 16 Jan 1984 More braindamage. Need to separate info
33 ; out of sft into FCB for reconnection
34 ;
35 ; A000 version 4.00 Jan. 1988
36 ;
37 .xlist
38 ;
39 ; get the appropriate segment definitions
40 ;
41 include dosseg.asm
42
43 CODE SEGMENT BYTE PUBLIC 'CODE'
44 ASSUME SS:DOSGROUP,CS:DOSGROUP
45
46 .xcref
47 INCLUDE DOSSYM.INC
48 INCLUDE DEVSYM.INC
49 INCLUDE 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
74 if debug
75 I_need BugLev,WORD
76 I_need BugTyp,WORD
77 include bugtyp.asm
78 endif
79
80
81 Break <$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
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
99 JAE GetFCBBye
100 MOV [SI+fcb_RR+2+1],DH ; Set 4th byte only if record size < 64
101 GetFCBBye:
102 transfer FCB_Ret_OK
103 EndProc $GET_FCB_POSITION
104
105 Break <$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
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
121 Context DS
122 invoke DOS_Delete ; wham
123 JC BadPath
124 GoodPath:
125 transfer FCB_Ret_OK ; do a good return
126 BadPath:
127 ;
128
129 ; Error code is in AX
130 ;
131 transfer FCB_Ret_Err ; let someone else signal the error
132 EndProc $FCB_DELETE
133
134 Break <$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
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
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
164 GetSize:
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
177 LengthStore:
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
183 GoodRet:
184 transfer FCB_Ret_OK
185 EndProc $GET_FCB_FILE_LENGTH
186
187 Break <$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
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
203 NoAttr:
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
220 NoStash:
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
244 CloseOK:
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
251 EndProc $FCB_CLOSE
252
253 Break <$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
267 Procedure $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
292 BadRen:
293 ;
294 ; AL has error code
295 ;
296 transfer FCB_Ret_Err
297
298 EndProc $FCB_RENAME
299
300 Break <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
400 Break <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
415 Procedure 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 ;
435 IF debug
436 JMP SaveSFN
437 ELSE
438 JMP SHORT SaveSFN
439 ENDIF
440 SaveLocal:
441 IF Installed
442 Invoke CheckShare
443 JZ SaveNoShare ; no sharer
444 JMP SaveShare ; sharer present
445
446 SaveNoShare:
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 ;
463 SetFCBBits:
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 ;
473 SaveNoShareDev:
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
481 SaveShare:
482 ENDIF
483 ;
484 ;----- In share support -----
485 ;
486 if installed
487 Call JShare + 10 * 4
488 else
489 Call ShSave
490 endif
491 ;
492 ;----- end in share support -----
493 ;
494 SaveSFN:
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 ;
520 SimpleStuff:
521 MOV FCBLRU,AX
522 return
523 EndProc SaveFCBInfo
524
525 Break <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
538 Procedure 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
546 ovScan:
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
550 ovLoop:
551 ADD DI,SIZE SF_Entry ; advance to next
552 LOOP ovScan
553 RestoreReg <DI,ES>
554 MOV ES:[DI+BX],AX
555 return
556 EndProc ResetLRU
557
558 Break <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
572 Procedure 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
581 SetDone:
582 MOV OpenLRU,AX
583 return
584 EndProc SetOpenAge
585
586 Break <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
601 Procedure 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 ;
618 lru1:
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 ;
639 lru2:
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 ;
647 lru25:
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 ;
657 lru3:
658 TEST ES:[DI].sf_flags,sf_isnet ; if (!net[i]
659 JNZ lru35
660 if installed
661 Invoke CheckShare ; && !sharing)
662 JZ lru5 ; else
663 ENDIF
664 ;
665 ; This SFT is for the net or is for the sharer. See if it less than the
666 ; current minimum.
667 ;
668 lru35:
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 ;
682 lru5:
683 add 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 ;
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
694 lru65: 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 ;
701 lru75:
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 ;
711 lru8:
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 ;
719 lru85:
720 cmp es:[di].sf_OpenAge,ax
721 jb lru9 ; age is before threshold, skip it
722 ;
723 ; Check LRU
724 ;
725 lru86:
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 ;
733 lru9:
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 ;
742 lru10:
743 cmp si,-1 ; if no one f
744 jz lru65 ; return -1;
745 lru11:
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
755 IF INSTALLED
756 Invoke CheckShare
757 JZ LRUDone
758 ENDIF
759 ;
760 ; Repeat close until ref count is 0
761 ;
762 LRUClose:
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
779 LRUDone:
780 XOR AL,AL
781 invoke BlastSFT ; fill SFT with 0 (AL)
782 LRUDead:
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
790 EndProc LRUFCB
791
792 Break <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
803 Procedure 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
831 RegenFail:
832 MOV AX,User_In_AX
833 cmp AH,fcb_close
834 jz RegenDead
835 invoke FCBHardErr ; massive hard error.
836 RegenDead:
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 ;
843 RegenNoSharing:
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
873 RegenCopyName2:
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;
885 notkanj9: ;AN000;
886 ENDIF ;AN000;
887
888 Invoke UCase
889 StuffChar2:
890 STOSB
891 LOOP RegenCopyName2
892 DoneNam2:
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
911 RegenDeadJ:
912 JMP RegenDead
913 ;
914 ; File found. Just copy in the remaining pieces.
915 ;
916 RegenFileNoSharing:
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
942 RegenCopyName:
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
954 notkanj1:
955 ENDIF ;AN000;
956
957 Invoke UCase
958 StuffChar:
959 STOSB
960 LOOP RegenCopyName
961 DoneNam:
962 clc
963 return
964 EndProc 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
975 Procedure 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
984 EndProc BlastSFT
985
986 Break <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
997 Procedure 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 ;
1026 if installed
1027 Call JShare + 11 * 4
1028 else
1029 Call ShChk
1030 endif
1031 JC BadSFT
1032 JMP SHORT CheckD
1033 ;
1034 ;----- End in share support -----
1035 ;
1036 CheckFirClus:
1037 CMP BX,ES:[DI].sf_firclus
1038 JNZ BadSFT
1039 CheckD: 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
1044 BadSFT: STC
1045 return ; carry is clear
1046 CheckNet:
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
1064 CheckNoShare:
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
1109 CheckNoShareDev:
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
1118 EndProc CheckFCB
1119
1120 Break <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
1134 Procedure 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
1154 SetSFT: LES DI,ThisSFT
1155 PUSH Proc_ID ; set process id
1156 POP ES:[DI].sf_PID
1157 return ; carry is clear
1158 EndProc SFTFromFCB
1159
1160 Break <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
1171 Procedure 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
1182 EndProc FCBHardErr
1183
1184 CODE ENDS
1185 END