1 ; SCCSID = @(#)fcbio2.asm 1.2 85/07/23
2 ; SCCSID = @(#)fcbio2.asm 1.2 85/07/23
3 TITLE FCBIO2
- FCB system calls
7 ; Ancient 1.0 1.1 FCB system calls
15 ; $FCB_OPEN written ACC ACC
16 ; $FCB_CREATE written ACC ACC
17 ; $FCB_RANDOM_WRITE_BLOCK written fcbio fcbio
18 ; $FCB_RANDOM_READ_BLOCK written fcbio fcbio
19 ; $FCB_SEQ_READ written fcbio fcbio
20 ; $FCB_SEQ_WRITE written fcbio fcbio
21 ; $FCB_RANDOM_READ written fcbio fcbio
22 ; $FCB_RANDOM_WRITE written fcbio fcbio
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
53 EXTRN DOS_Read
:NEAR, DOS_Write
:NEAR
54 EXTRN DOS_Open
:NEAR, DOS_Create
:NEAR
56 I_need DMAAdd
,DWORD ; current user's DMA address
57 I_need OpenBuf
,128 ; buffer for translating paths
58 I_need ThisSFT
,DWORD ; SFT in use
59 I_need sftFCB
,DWORD ; pointer to SFTs for FCB cache
60 I_need FCBLRU
,WORD ; least recently used count
61 I_need DISK_FULL
,BYTE ; flag for disk full
70 I_need BUF_EMS_MODE
,BYTE
71 I_need BUF_EMS_LAST_PAGE
,DWORD
72 I_need BUF_EMS_FIRST_PAGE
,DWORD
73 I_need BUF_EMS_SAFE_FLAG
,BYTE
74 I_need BUF_EMS_NPA640
,WORD
75 I_need BUF_EMS_PAGE_FRAME
,WORD
76 I_need BUF_EMS_PFRAME
,WORD
77 I_need LASTBUFFER
,DWORD
79 extrn restore_user_map
:near
80 extrn Setup_EMS_Buffers
:near
85 ; Defintions for FCBOp flags
87 Random
= 2 ; random operation
88 FCBRead
= 4 ; doing a read
89 Block
= 8 ; doing a block I/O
91 Break <GetRR
- return the random record field
in DX:AX>
94 ; GetRR - correctly load DX:AX with the random record field (3 or 4 bytes)
95 ; from the FCB pointed to by DS:SI
97 ; Inputs: DS:SI point to an FCB
99 ; Outputs: DX:AX contain the contents of the random record field
100 ; Registers modified: none
103 ASSUME
CS:DOSGROUP
,DS:NOTHING
,ES:NOTHING
,SS:DOSGROUP
104 MOV AX,WORD PTR [SI.FCB_RR
] ; get low order part
105 MOV DX,WORD PTR [SI.FCB_RR
+2] ; get high order part
106 CMP BX,64 ; ignore MSB of RR if recsiz > 64
113 Break <GetExtent
- retrieve next location for sequential IO
>
116 ; GetExtent - Construct the next record to perform I/O from the EXTENT and
117 ; NR fields in the FCB.
119 ; Inputs: DS:SI - point to FCB
120 ; Outputs: DX:AX contain the contents of the random record field
121 ; Registers modified: none
123 Procedure GetExtent
,NEAR
124 ASSUME
CS:DOSGROUP
,DS:NOTHING
,ES:NOTHING
,SS:DOSGROUP
125 MOV AL,[SI.fcb_NR
] ; get low order piece
126 MOV DX,[SI.fcb_EXTENT
] ; get high order piece
129 RCR AL,1 ; move low order bit of DL to high order of AH
136 Break <SetExtent
- update the extent
/NR field
>
139 ; SetExtent - change the position of an FCB by filling in the extent/NR
142 ; Inputs: DS:SI point to FCB
143 ; DX:AX is a record location in file
144 ; Outputs: Extent/NR fields are filled in
145 ; Registers modified: CX
147 Procedure SetExtent
,NEAR
148 ASSUME
CS:DOSGROUP
,DS:NOTHING
,ES:NOTHING
,SS:DOSGroup
151 AND AL,7FH
; next rec field
153 AND CL,80H
; save upper bit
155 RCL DX,1 ; move high bit of CX to low bit of DX
158 MOV [SI.fcb_EXTENT
],AX ; all done
163 Break <GetExtended
- find FCB
in potential extended fcb
>
166 ; GetExtended - Make DS:SI point to FCB from DS:DX
168 ; Inputs: DS:DX point to a possible extended FCB
169 ; Outputs: DS:SI point to the FCB part
170 ; zeroflag set if not extended fcb
171 ; Registers modified: SI
173 Procedure GetExtended
,NEAR
174 ASSUME
CS:DOSGROUP
,DS:NOTHING
,ES:NOTHING
,SS:DOSGROUP
175 MOV SI,DX ; point to Something
176 CMP BYTE PTR DS:[SI],-1 ; look for extention
177 JNZ GetBye
; not there
178 ADD SI,7 ; point to FCB
180 CMP SI,DX ; set condition codes
184 Break <GetRecSize
- return
in BX the FCB record size
>
187 ; GetRecSize - return in BX the record size from the FCB at DS:SI
189 ; Inputs: DS:SI point to a non-extended FCB
190 ; Outputs: BX contains the record size
191 ; Registers modified: None
193 Procedure GetRecSize
,NEAR
194 ASSUME
CS:DOSGROUP
,DS:NOTHING
,ES:NOTHING
,SS:DOSGroup
195 MOV BX,[SI.fcb_RECSIZ
] ; get his record size
196 OR BX,BX ; is it nul?
198 MOV BX,128 ; use default size
199 MOV [SI.fcb_RECSIZ
],BX ; stuff it back
203 BREAK <FCBIO
- do internal FCB I
/O
>
206 ; FCBIO - look at FCBOP and merge all FCB operations into a single routine.
208 ; Inputs: FCBOP flags which operations need to be performed
210 ; CX may have count of number of records to xfer
211 ; Outputs: AL has error code
212 ; Registers modified: all
215 ASSUME
CS:DOSGROUP
,DS:NOTHING
,ES:NOTHING
,SS:DOSGroup
216 PUBLIC FCBIO001S
,FCBIO001E
220 LocalVar RecPos
,DWORD
221 LocalVar RecSize
,WORD
224 LocalVar cResult
,WORD
225 LocalVar cRecRes
,WORD
233 MOV FCBErr
,0 ; FCBErr = 0;
234 invoke GetExtended
; FCB = GetExtended ();
235 TEST FCBOp
,BLOCK
; if ((OP&BLOCK) == 0)
239 MOV cRec
,CX ;*Tail coalesce
240 invoke GetExtent
; RecPos = GetExtent ();
241 invoke GetRecSize
; RecSize = GetRecSize ();
243 TEST FCBOp
,RANDOM
; if ((OP&RANDOM) <> 0)
245 invoke GetRR
; RecPos = GetRR ();
247 MOV RecPosL
,AX ;*Tail coalesce
249 invoke SetExtent
; SetExtent (RecPos);
250 MOV AX,RecPosH
; bPos = RecPos * RecSize;
258 MOV AX,cRec
; cByte = cRec * RecSize;
261 ADD AX,WORD PTR DMAAdd
; if (cByte+DMA > 64K) {
264 MOV FCBErr
,FTRIM
; FCBErr = FTRIM;
265 MOV AX,WORD PTR DMAAdd
; cRec = (64K-DMA)/RecSize;
273 MUL BX ; cByte = cRec * RecSize;
277 MOV cResult
,BX ; cResult = 0;
278 CMP cByte
,BX ; if (cByte <> 0 ||
280 TEST FCBErr
,FTRIM
; (FCBErr&FTRIM) == 0) {
290 invoke SFTFromFCB
; if (!SFTFromFCB (SFT,FCB))
293 invoke FCB_Ret_Err
; signal error, map for extended
294 MOV cRecRes
,0 ; no bytes transferred
295 MOV FCBErr
,FEOF
; return FTRIM;
298 Assert ISSFT
,<ES,DI>,"ContinueOP"
299 MOV AX,WORD PTR [SI].fcb_filsiz
300 MOV WORD PTR ES:[DI].sf_size
,AX
301 MOV AX,WORD PTR [SI].fcb_filsiz
+2
302 MOV WORD PTR ES:[DI].sf_size
+2,AX
305 MOV WORD PTR ES:[DI.sf_position
],AX
306 XCHG WORD PTR ES:[DI.sf_position
+2],DX
307 PUSH DX ; save away Open age.
308 MOV CX,cByte
; cResult =
312 MOV DI,OFFSET DOSGroup
:DOS_Read
; *(OP&FCBRead ? DOS_Read
313 TEST FCBOp
,FCBRead
; : DOS_Write)(cRec);
315 MOV DI,OFFSET DOSGroup
:DOS_Write
321 RestoreReg
<SI,DS,BP>
329 cmp cs:[BUF_EMS_MODE
], -1
331 call restore_user_map
332 mov ax, word ptr cs:[BUF_EMS_LAST_PAGE
]
333 cmp cs:[BUF_EMS_PFRAME
], ax
335 mov word ptr cs:[LASTBUFFER
], -1
336 mov cs:[BUF_EMS_PFRAME
], ax
337 mov ax, word ptr cs:[BUF_EMS_LAST_PAGE
+2]
338 mov cs:[BUF_EMS_PAGE_FRAME
], ax
339 mov cs:[BUF_EMS_SAFE_FLAG
], 1
340 call Setup_EMS_Buffers
350 CMP BYTE PTR [DISK_FULL
],0 ; treat disk full as error
352 MOV BYTE PTR [DISK_FULL
],0 ; clear the flag
353 MOV FCBerr
,FEOF
; set disk full flag
357 invoke SaveFCBInfo
; SaveFCBInfo (FCB);
358 Assert ISSFT
,<ES,DI>,"FCBIO/SaveFCBInfo"
359 %
out WARNING!!! Make sure sf_position
+2 is OpenAGE
360 POP WORD PTR ES:[DI].sf_Position
+2 ; restore open age
361 MOV AX,WORD PTR ES:[DI].sf_size
362 MOV WORD PTR [SI].fcb_filsiz
,AX
363 MOV AX,WORD PTR ES:[DI].sf_size
+2
364 MOV WORD PTR [SI].fcb_filsiz
+2,AX
367 MOV AX,cResult
; cRecRes = cResult / RecSize;
371 ADD RecPosL
,AX ; RecPos += cRecResult;
374 ; If we have not gotten the expected number of records, we signal an EOF
375 ; condition. On input, this is EOF. On output this is usually disk full.
376 ; BUT... Under 2.0 and before, all device output IGNORED this condition. So
379 CMP AX,cRec
; if (cRecRes <> cRec)
381 TEST FCBOp
,FCBRead
; if (OP&FCBRead || !DEVICE)
383 TEST ES:[DI].sf_flags
,devid_device
386 MOV FCBErr
,FEOF
; FCBErr = FEOF;
388 OR DX,DX ; if (cResult%RecSize <> 0) {
390 ADD RecPosL
,1 ; RecPos++;
392 TEST FCBOp
,FCBRead
; if(OP&FCBRead) <> 0) {
394 INC cRecRes
; cRecRes++;
395 MOV FCBErr
,FTRIM
+ FEOF
; FCBErr = FTRIM | FEOF;
396 MOV CX,RecSize
; Blank (RecSize-cResult%RecSize,
397 SUB CX,DX ; DMA+cResult);
405 TEST FCBOp
,RANDOM
; if ((OP&Random) == 0 ||
407 TEST FCBOp
,BLOCK
; (OP&BLOCK) <> 0)
410 invoke SetExtent
; SetExtent (RecPos, FCB);
412 TEST FCBOp
,BLOCK
; if ((op&BLOCK) <> 0)
414 MOV WORD PTR [SI.FCB_RR
],AX ; FCB->RR = RecPos;
415 MOV BYTE PTR [SI.FCB_RR
+2],DL
416 CMP [SI.fcb_RECSIZ
],64
418 MOV [SI+fcb_RR
+2+1],DH ; Set 4th byte only if record size < 64
420 TEST FCBOP
,FCBRead
; if (!(FCBOP & FCBREAD)) {
422 SaveReg
<DS> ; FCB->FDate = date;
423 Invoke Date16
; FCB->FTime = time;
425 MOV [SI].FCB_FDate
,AX
426 MOV [SI].FCB_FTime
,DX ; }
428 TEST FCBOp
,BLOCK
; if ((op&BLOCK) <> 0)
430 MOV CX,cRecRes
; user_CX = cRecRes;
431 invoke Get_User_Stack
434 MOV AL,FCBErr
; return (FCBERR);
439 Break <$FCB_Open
- open an old
-style FCB
>
442 ; $FCB_Open - CPM compatability file open. The user has formatted an FCB
443 ; for us and asked to have the rest filled in.
445 ; Inputs: DS:DX point to an unopenned FCB
446 ; Outputs: AL indicates status 0 is ok FF is error
447 ; FCB has the following fields filled in:
448 ; Time/Date Extent/NR Size
450 Procedure $FCB_Open
,NEAR
451 ASSUME
CS:DOSGROUP
,DS:NOTHING
,ES:NOTHING
,SS:DOSGROUP
452 MOV AX,sharing_Compat
+Open_For_Both
453 MOV CX,OFFSET DOSGroup
:DOS_Open
455 ; The following is common code for Creation and openning of FCBs. AX is
456 ; either attributes (for create) or open mode (for open)... DS:DX points to
460 SaveReg
<DS,DX,CX,AX> ; save FCB pointer away
461 MOV DI,OFFSET DOSGroup
:OpenBuf
462 invoke TransFCB
; crunch the fcb
463 RestoreReg
<AX,CX,DX,DS> ; get fcb
464 JNC FindFCB
; everything seems ok
471 invoke GetExtended
; DS:SI will point to FCB
472 invoke LRUFCB
; get a sft entry (no error)
476 ; Message 1,"Entering "
482 MOV ES:[DI].sf_mode
,sf_ISFCB
483 SaveReg
<DS,SI,BX> ; save fcb pointer
485 Context
DS ; let DOS_Open see variables
486 CALL SI ; go open the file
487 RestoreReg
<BX,SI,DS> ; get fcb
489 LES DI,ThisSFT
; get sf pointer
490 JNC FCBOK
; operation succeeded
491 Assert ISSFT
,<ES,DI>,"DeadFCB"
494 MOV AL,"R" ; clear out field (free sft)
497 CMP AX,error_too_many_open_files
499 CMP AX,error_sharing_buffer_exceeded
508 invoke IsSFTNet
;AN007;F.C. >32mb Non Fat file?
509 JNZ FCBOK2
;AN007;F.C. >32mb yes
510 invoke CheckShare
;AN000;F.C. >32mb share around?
511 JNZ FCBOK2
;AN000;F.C. >32mb yes
512 CMP WORD PTR ES:[DI].sf_dirsec
+2,0 ;AN000;F.C. >32mb if dirsec >32mb
513 JZ FCBOK2
;AN000;F.C. >32mb then error
514 MOV AX,error_sys_comp_not_loaded
;AN000;F.C. >32mb
515 JMP failopen
;AN000;F.C. >32mb
518 INC ES:[DI].sf_ref_count
; increment reference count
520 Assert ISSFT
,<ES,DI>,"FCBOK"
522 Assert ISSFT
,<ES,DI>,"FCBOK/SetOpenAge"
523 TEST ES:[DI].sf_flags
,devid_device
524 JNZ FCBNoDrive
; do not munge drive on devices
525 MOV AL,DS:[SI] ; get drive byte
526 invoke GetThisDrv
; convert
528 MOV DS:[SI],AL ; stash in good drive letter
530 MOV [SI].FCB_RecSiz
,80h
; stuff in default record size
531 MOV AX,ES:[DI].SF_Time
; set time
532 MOV [SI].FCB_FTime
,AX
533 MOV AX,ES:[DI].SF_Date
; set date
534 MOV [SI].FCB_FDate
,AX
535 MOV AX,WORD PTR ES:[DI].SF_Size
; set sizes
536 MOV [SI].FCB_FILSIZ
,AX
537 MOV AX,WORD PTR ES:[DI].SF_Size
+2
538 MOV [SI].FCB_FILSIZ
+2,AX
539 XOR AX,AX ; convenient zero
540 MOV [SI].FCB_Extent
,AX ; point to beginning of file
542 ; We must scan the set of FCB SFTs for one that appears to match the current
543 ; one. We cheat and use CheckFCB to match the FCBs.
545 LES DI,SFTFCB
; get the pointer to head of the list
546 MOV AH,BYTE PTR ES:[DI].sfCount
; get number of SFTs to scan
548 CMP AL,[SI].fcb_sfn
; don't compare ourselves
550 SaveReg
<AX> ; preserve count
551 invoke CheckFCB
; do they match
552 RestoreReg
<AX> ; get count back
553 JNC OpenFound
; found a match!
555 INC AL ; advance to next FCB
556 CMP AL,AH ; table full?
557 JNZ OpenScan
; no, go for more
559 xor al,al ; return success
562 ; The SFT at ES:DI is the one that is already in use for this FCB. We set the
563 ; FCB to use this one. We increment its ref count. We do NOT close it at all.
566 ; open (foo) delete (foo) open (bar)
568 ; This causes us to recycle (potentially) bar through the same local SFT as
569 ; foo even though foo is no longer needed; this is due to the server closing
570 ; foo for us when we delete it. Unfortunately, we cannot see this closure.
571 ; If we were to CLOSE bar, the server would then close the only reference to
572 ; bar and subsequent I/O would be lost to the redirector.
574 ; This gets solved by NOT closing the sft, but zeroing the ref count
575 ; (effectively freeing the SFT) and informing the sharer (if relevant) that
576 ; the SFT is no longer in use. Note that the SHARER MUST keep its ref counts
577 ; around. This will allow us to access the same file through multiple network
578 ; connections and NOT prematurely terminate when the ref count on one
579 ; connection goes to zero.
582 MOV [SI].fcb_SFN
,AL ; assign with this
583 INC ES:[DI].sf_ref_count
; remember this new invocation
584 MOV AX,FCBLRU
; update LRU counts
585 MOV ES:[DI].sf_LRU
,AX
587 ; We have an FCB sft that is now of no use. We release sharing info and then
588 ; blast it to prevent other reuse.
592 DEC ES:[DI].sf_ref_count
; free the newly allocated SFT
594 Assert ISSFT
,<ES,DI>,"Open blasting"
600 BREAK <$FCB_Create
- create a new directory
entry>
603 ; $FCB_Create - CPM compatability file create. The user has formatted an
604 ; FCB for us and asked to have the rest filled in.
606 ; Inputs: DS:DX point to an unopenned FCB
607 ; Outputs: AL indicates status 0 is ok FF is error
608 ; FCB has the following fields filled in:
609 ; Time/Date Extent/NR Size
611 Procedure $FCB_Create
,NEAR
612 ASSUME
CS:DOSGROUP
,DS:NOTHING
,ES:NOTHING
,SS:DOSGroup
613 MOV CX,OFFSET DOSGroup
:DOS_Create
; routine to call
614 XOR AX,AX ; attributes to create
615 invoke GetExtended
; get extended FCB
616 JZ DoAccessJ
; not an extended FCB
617 MOV AL,[SI-1] ; get attributes
619 JMP DoAccess
; do dirty work
622 BREAK <$FCB_Random_write_Block
- write a block of records to a
file >
625 ; $FCB_Random_Write_Block - retrieve a location from the FCB, seek to it
626 ; and write a number of blocks from it.
628 ; Inputs: DS:DX point to an FCB
629 ; Outputs: AL = 0 write was successful and the FCB position is updated
630 ; AL <> 0 Not enough room on disk for the output
633 Procedure $FCB_Random_Write_Block
,NEAR
634 ASSUME
CS:DOSGROUP
,DS:NOTHING
,ES:NOTHING
,SS:DOSGroup
637 EndProc $FCB_Random_Write_Block
639 BREAK <$FCB_Random_Read_Block
- read a block of records to a
file >
642 ; $FCB_Random_Read_Block - retrieve a location from the FCB, seek to it
643 ; and read a number of blocks from it.
645 ; Inputs: DS:DX point to an FCB
646 ; Outputs: AL = error codes defined above
649 Procedure $FCB_Random_Read_Block
,NEAR
650 ASSUME
CS:DOSGROUP
,DS:NOTHING
,ES:NOTHING
,SS:DOSGroup
651 MOV AL,Random
+FCBRead
+Block
653 EndProc $FCB_Random_Read_Block
655 BREAK <$FCB_Seq_Read
- read the next record
from a
file >
658 ; $FCB_Seq_Read - retrieve the next record from an FCB and read it into
661 ; Inputs: DS:DX point to an FCB
662 ; Outputs: AL = error codes defined above
665 Procedure $FCB_Seq_Read
,NEAR
666 ASSUME
CS:DOSGROUP
,DS:NOTHING
,ES:NOTHING
,SS:DOSGroup
669 EndProc $FCB_Seq_Read
671 BREAK <$FCB_Seq_Write
- write the next record to a
file >
674 ; $FCB_Seq_Write - retrieve the next record from an FCB and write it to the
677 ; Inputs: DS:DX point to an FCB
678 ; Outputs: AL = error codes defined above
681 Procedure $FCB_Seq_Write
,NEAR
682 ASSUME
CS:DOSGROUP
,DS:NOTHING
,ES:NOTHING
,SS:DOSGroup
685 EndProc $FCB_SEQ_WRITE
687 BREAK <$FCB_Random_Read
- Read a single record
from a
file >
690 ; $FCB_Random_Read - retrieve a location from the FCB, seek to it and read a
693 ; Inputs: DS:DX point to an FCB
694 ; Outputs: AL = error codes defined above
697 Procedure $FCB_Random_Read
,NEAR
698 ASSUME
CS:DOSGROUP
,DS:NOTHING
,ES:NOTHING
,SS:DOSGroup
699 MOV AL,Random
+FCBRead
700 jmp FCBIO
; single block
701 EndProc $FCB_RANDOM_READ
703 BREAK <$FCB_Random_Write
- write a single record to a
file >
706 ; $FCB_Random_Write - retrieve a location from the FCB, seek to it and write
709 ; Inputs: DS:DX point to an FCB
710 ; Outputs: AL = error codes defined above
713 Procedure $FCB_Random_Write
,NEAR
714 ASSUME
CS:DOSGROUP
,DS:NOTHING
,ES:NOTHING
,SS:DOSGroup
717 EndProc $FCB_RANDOM_WRITE