summaryrefslogtreecommitdiff
path: root/v4.0/src/DOS/FCBIO2.ASM
blob: ec0ee3e45a4de27c441d9e46f916bb9bb7a68441 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
;	SCCSID = @(#)fcbio2.asm 1.2 85/07/23
;	SCCSID = @(#)fcbio2.asm 1.2 85/07/23
TITLE	FCBIO2 - FCB system calls
NAME	FCBIO2

;
; Ancient 1.0 1.1 FCB system calls
;				    regen   save
;   GetRR
;   GetExtent
;   SetExtent
;   GetExtended
;   GetRecSize
;   FCBIO
;   $FCB_OPEN		    written ACC     ACC
;   $FCB_CREATE 	    written ACC     ACC
;   $FCB_RANDOM_WRITE_BLOCK written fcbio   fcbio
;   $FCB_RANDOM_READ_BLOCK  written fcbio   fcbio
;   $FCB_SEQ_READ	    written fcbio   fcbio
;   $FCB_SEQ_WRITE	    written fcbio   fcbio
;   $FCB_RANDOM_READ	    written fcbio   fcbio
;   $FCB_RANDOM_WRITE	    written fcbio   fcbio
;
;   Revision history:
;
;	Created: ARR 4 April 1983
;		 MZ  6 June  1983 completion of functions
;		 MZ 15 Dec   1983 Brain damaged programs close FCBs multiple
;				  times.  Change so successive closes work by
;				  always returning OK.	Also, detect I/O to
;				  already closed FCB and return EOF.
;		 MZ 16 Jan   1984 More braindamage.  Need to separate info
;				  out of sft into FCB for reconnection
;
;	A000	version 4.00  Jan. 1988
;
.xlist
;
; get the appropriate segment definitions
;
include dosseg.asm

CODE	SEGMENT BYTE PUBLIC  'CODE'
	ASSUME	SS:DOSGROUP,CS:DOSGROUP

.xcref
INCLUDE DOSSYM.INC
INCLUDE DEVSYM.INC
include version.inc
.cref
.list

	EXTRN	DOS_Read:NEAR, DOS_Write:NEAR
	EXTRN	DOS_Open:NEAR, DOS_Create:NEAR

	I_need	DMAAdd,DWORD		; current user's DMA address
	I_need	OpenBuf,128		; buffer for translating paths
	I_need	ThisSFT,DWORD		; SFT in use
	I_need	sftFCB,DWORD		; pointer to SFTs for FCB cache
	I_need	FCBLRU,WORD		; least recently used count
	I_need	DISK_FULL,BYTE		; flag for disk full
if debug
	I_need	BugLev,WORD
	I_need	BugTyp,WORD
	include bugtyp.asm
endif

IF	BUFFERFLAG

	I_need	BUF_EMS_MODE,BYTE
	I_need	BUF_EMS_LAST_PAGE,DWORD
	I_need	BUF_EMS_FIRST_PAGE,DWORD
	I_need	BUF_EMS_SAFE_FLAG,BYTE
	I_need	BUF_EMS_NPA640,WORD
	I_need	BUF_EMS_PAGE_FRAME,WORD
	I_need	BUF_EMS_PFRAME,WORD
	I_need	LASTBUFFER,DWORD

	extrn	restore_user_map:near
	extrn	Setup_EMS_Buffers:near

ENDIF


; Defintions for FCBOp flags

Random	=   2				; random operation
FCBRead =   4				; doing a read
Block	=   8				; doing a block I/O

Break <GetRR - return the random record field in DX:AX>

;
;   GetRR - correctly load DX:AX with the random record field (3 or 4 bytes)
;	from the FCB pointed to by DS:SI
;
;   Inputs:	DS:SI point to an FCB
;		BX has record size
;   Outputs:	DX:AX contain the contents of the random record field
;   Registers modified: none

Procedure   GetRR,NEAR
	ASSUME	CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:DOSGROUP
	MOV	AX,WORD PTR [SI.FCB_RR] ; get low order part
	MOV	DX,WORD PTR [SI.FCB_RR+2]   ; get high order part
	CMP	BX,64			; ignore MSB of RR if recsiz > 64
	JB	GetRRBye
	XOR	DH,DH
GetRRBye:
	return
EndProc GetRR

Break <GetExtent - retrieve next location for sequential IO>

;
;   GetExtent - Construct the next record to perform I/O from the EXTENT and
;	NR fields in the FCB.
;
;   Inputs:	DS:SI - point to FCB
;   Outputs:	DX:AX contain the contents of the random record field
;   Registers modified: none

Procedure   GetExtent,NEAR
	ASSUME	CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:DOSGROUP
	MOV	AL,[SI.fcb_NR]		; get low order piece
	MOV	DX,[SI.fcb_EXTENT]	; get high order piece
	SHL	AL,1
	SHR	DX,1
	RCR	AL,1			; move low order bit of DL to high order of AH
	MOV	AH,DL
	MOV	DL,DH
	XOR	DH,DH
	return
EndProc GetExtent

Break <SetExtent - update the extent/NR field>

;
;   SetExtent - change the position of an FCB by filling in the extent/NR
;	fields
;
;   Inputs:	DS:SI point to FCB
;		DX:AX is a record location in file
;   Outputs:	Extent/NR fields are filled in
;   Registers modified: CX

Procedure SetExtent,NEAR
	ASSUME	CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:DOSGroup
	SaveReg <AX,DX>
	MOV	CX,AX
	AND	AL,7FH			; next rec field
	MOV	[SI.fcb_NR],AL
	AND	CL,80H			; save upper bit
	SHL	CX,1
	RCL	DX,1			; move high bit of CX to low bit of DX
	MOV	AL,CH
	MOV	AH,DL
	MOV	[SI.fcb_EXTENT],AX	; all done
	RestoreReg  <DX,AX>
	return
EndProc SetExtent

Break <GetExtended - find FCB in potential extended fcb>

;
;   GetExtended - Make DS:SI point to FCB from DS:DX
;
;   Inputs:	DS:DX point to a possible extended FCB
;   Outputs:	DS:SI point to the FCB part
;		zeroflag set if not extended fcb
;   Registers modified: SI

Procedure   GetExtended,NEAR
	ASSUME	CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:DOSGROUP
	MOV	SI,DX			; point to Something
	CMP	BYTE PTR DS:[SI],-1	; look for extention
	JNZ	GetBye			; not there
	ADD	SI,7			; point to FCB
GetBye:
	CMP	SI,DX			; set condition codes
	return
EndProc GetExtended

Break <GetRecSize - return in BX the FCB record size>

;
;   GetRecSize - return in BX the record size from the FCB at DS:SI
;
;   Inputs:	DS:SI point to a non-extended FCB
;   Outputs:	BX contains the record size
;   Registers modified: None

Procedure   GetRecSize,NEAR
	ASSUME	CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:DOSGroup
	MOV	BX,[SI.fcb_RECSIZ]	; get his record size
	OR	BX,BX			; is it nul?
	retnz
	MOV	BX,128			; use default size
	MOV	[SI.fcb_RECSIZ],BX	; stuff it back
	return
EndProc GetRecSize

BREAK <FCBIO - do internal FCB I/O>

;
;   FCBIO - look at FCBOP and merge all FCB operations into a single routine.
;
;   Inputs:	FCBOP flags which operations need to be performed
;		DS:DX point to FCB
;		CX may have count of number of records to xfer
;   Outputs:	AL has error code
;   Registers modified: all

Procedure   FCBIO,NEAR
	ASSUME	CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:DOSGroup
PUBLIC FCBIO001S,FCBIO001E
FCBIO001S:
	LocalVar    FCBErr,BYTE
	LocalVar    cRec,WORD
	LocalVar    RecPos,DWORD
	LocalVar    RecSize,WORD
	LocalVar    bPos,DWORD
	LocalVar    cByte,WORD
	LocalVar    cResult,WORD
	LocalVar    cRecRes,WORD
	LocalVar    FCBOp,BYTE
FCBIO001E:
	Enter

FEOF	EQU	1
FTRIM	EQU	2
	MOV	FCBOp,AL
	MOV	FCBErr,0		;   FCBErr = 0;
	invoke	GetExtended		;   FCB = GetExtended ();
	TEST	FCBOp,BLOCK		;   if ((OP&BLOCK) == 0)
	JNZ	GetPos
	MOV	CX,1			;	cRec = 1;
GetPos:
	MOV	cRec,CX 		;*Tail coalesce
	invoke	GetExtent		;   RecPos = GetExtent ();
	invoke	GetRecSize		;   RecSize = GetRecSize ();
	MOV	RecSize,BX
	TEST	FCBOp,RANDOM		;   if ((OP&RANDOM) <> 0)
	JZ	GetRec
	invoke	GetRR			;	RecPos = GetRR ();
GetRec:
	MOV	RecPosL,AX		;*Tail coalesce
	MOV	RecPosH,DX
	invoke	SetExtent		;   SetExtent (RecPos);
	MOV	AX,RecPosH		;   bPos = RecPos * RecSize;
	MUL	BX
	MOV	DI,AX
	MOV	AX,RecPosL
	MUL	BX
	ADD	DX,DI
	MOV	bPosL,AX
	MOV	bPosH,DX
	MOV	AX,cRec 		;   cByte = cRec * RecSize;
	MUL	BX
	MOV	cByte,AX
	ADD	AX,WORD PTR DMAAdd	;   if (cByte+DMA > 64K) {
	ADC	DX,0
	JZ	DoOper
	MOV	FCBErr,FTRIM		;	FCBErr = FTRIM;
	MOV	AX,WORD PTR DMAAdd	;	cRec = (64K-DMA)/RecSize;
	NEG	AX
	JNZ	DoDiv
	DEC	AX
DoDiv:
	XOR	DX,DX
	DIV	BX
	MOV	cRec,AX
	MUL	BX			;	cByte = cRec * RecSize;
	MOV	cByte,AX		;	}
DoOper:
	XOR	BX,BX
	MOV	cResult,BX		;   cResult = 0;
	CMP	cByte,BX		;   if (cByte <> 0 ||
	JNZ	DoGetExt
	TEST	FCBErr,FTRIM		;	(FCBErr&FTRIM) == 0) {
IF debug
	JZ	DoGetExt
	JMP	SkipOp
ELSE
	JZ	SKP_SkipOp
	JMP	SkipOp
SKP_SkipOp:
ENDIF
DoGetExt:
	invoke	SFTFromFCB		;	if (!SFTFromFCB (SFT,FCB))
	JNC	ContinueOp
FCBDeath:
	invoke	FCB_Ret_Err		; signal error, map for extended
	MOV	cRecRes,0		; no bytes transferred
	MOV	FCBErr,FEOF		;	    return FTRIM;
	JMP	FCBSave 		; bam!
ContinueOp:
	Assert	ISSFT,<ES,DI>,"ContinueOP"
	MOV	AX,WORD PTR [SI].fcb_filsiz
	MOV	WORD PTR ES:[DI].sf_size,AX
	MOV	AX,WORD PTR [SI].fcb_filsiz+2
	MOV	WORD PTR ES:[DI].sf_size+2,AX
	MOV	AX,bPosL
	MOV	DX,bPosH
	MOV	WORD PTR ES:[DI.sf_position],AX
	XCHG	WORD PTR ES:[DI.sf_position+2],DX
	PUSH	DX			; save away Open age.
	MOV	CX,cByte		;	cResult =

;	int	3

	MOV	DI,OFFSET DOSGroup:DOS_Read ;	    *(OP&FCBRead ? DOS_Read
	TEST	FCBOp,FCBRead		;			 : DOS_Write)(cRec);
	JNZ	DoContext
	MOV	DI,OFFSET DOSGroup:DOS_Write
DoContext:
	SaveReg <BP,DS,SI>
	Context DS
;; Fix for disk full
	CALL	DI
	RestoreReg  <SI,DS,BP>
	ASSUME	DS:NOTHING

IF	BUFFERFLAG
	pushf
	push	ax
	push	bx

	cmp	cs:[BUF_EMS_MODE], -1
	jz	dos_fcb_call_done
	call	restore_user_map
	mov	ax, word ptr cs:[BUF_EMS_LAST_PAGE]
	cmp	cs:[BUF_EMS_PFRAME], ax
	je	dos_fcb_call_done
	mov	word ptr cs:[LASTBUFFER], -1
	mov	cs:[BUF_EMS_PFRAME], ax
	mov	ax, word ptr cs:[BUF_EMS_LAST_PAGE+2]
	mov	cs:[BUF_EMS_PAGE_FRAME], ax
	mov	cs:[BUF_EMS_SAFE_FLAG], 1
	call	Setup_EMS_Buffers

dos_fcb_call_done:
	pop	bx
	pop	ax
	popf
ENDIF

	JC	FCBDeath

	CMP	BYTE PTR [DISK_FULL],0	; treat disk full as error
	JZ	NODSKFULL
	MOV	BYTE PTR [DISK_FULL],0	; clear the flag
	MOV	FCBerr,FEOF		; set disk full flag
NODSKFULL:
;; Fix for disk full
	MOV	cResult,CX
	invoke	SaveFCBInfo		;	SaveFCBInfo (FCB);
	Assert	ISSFT,<ES,DI>,"FCBIO/SaveFCBInfo"
%out WARNING!!! Make sure sf_position+2 is OpenAGE
	POP	WORD PTR ES:[DI].sf_Position+2	; restore open age
	MOV	AX,WORD PTR ES:[DI].sf_size
	MOV	WORD PTR [SI].fcb_filsiz,AX
	MOV	AX,WORD PTR ES:[DI].sf_size+2
	MOV	WORD PTR [SI].fcb_filsiz+2,AX
					;	}
SkipOp:
	MOV	AX,cResult		;   cRecRes = cResult / RecSize;
	XOR	DX,DX
	DIV	RecSize
	MOV	cRecRes,AX
	ADD	RecPosL,AX		;   RecPos += cRecResult;
	ADC	RecPosH,0
;
; If we have not gotten the expected number of records, we signal an EOF
; condition.  On input, this is EOF.  On output this is usually disk full.
; BUT...  Under 2.0 and before, all device output IGNORED this condition.  So
; do we.
;
	CMP	AX,cRec 		;   if (cRecRes <> cRec)
	JZ	TryBlank
	TEST	FCBOp,FCBRead		;	if (OP&FCBRead || !DEVICE)
	JNZ	SetEOF
	TEST	ES:[DI].sf_flags,devid_device
	JNZ	TryBlank
SetEOF:
	MOV	FCBErr,FEOF		;	FCBErr = FEOF;
TryBlank:				;
	OR	DX,DX			;   if (cResult%RecSize <> 0) {
	JZ	SetExt
	ADD	RecPosL,1		;	RecPos++;
	ADC	RecPosH,0
	TEST	FCBOp,FCBRead		;	if(OP&FCBRead) <> 0) {
	JZ	SetExt
	INC	cRecRes 		;	cRecRes++;
	MOV	FCBErr,FTRIM + FEOF	;	FCBErr = FTRIM | FEOF;
	MOV	CX,RecSize		;	Blank (RecSize-cResult%RecSize,
	SUB	CX,DX			;	       DMA+cResult);
	XOR	AL,AL
	LES	DI,DMAAdd
	ADD	DI,cResult
	REP	STOSB			;   }	}
SetExt:
	MOV	DX,RecPosH
	MOV	AX,RecPosL
	TEST	FCBOp,RANDOM		;   if ((OP&Random) == 0 ||
	JZ	DoSetExt
	TEST	FCBOp,BLOCK		;	(OP&BLOCK) <> 0)
	JZ	TrySetRR
DoSetExt:
	invoke	SetExtent		;	SetExtent (RecPos, FCB);
TrySetRR:
	TEST	FCBOp,BLOCK		;   if ((op&BLOCK) <> 0)
	JZ	TryReturn
	MOV	WORD PTR [SI.FCB_RR],AX ;	FCB->RR = RecPos;
	MOV	BYTE PTR [SI.FCB_RR+2],DL
	CMP	[SI.fcb_RECSIZ],64
	JAE	TryReturn
	MOV	[SI+fcb_RR+2+1],DH	; Set 4th byte only if record size < 64
TryReturn:
	TEST	FCBOP,FCBRead		;   if (!(FCBOP & FCBREAD)) {
	JNZ	FCBSave
	SaveReg <DS>			;	FCB->FDate = date;
	Invoke	Date16			;	FCB->FTime = time;
	RestoreReg  <DS>
	MOV	[SI].FCB_FDate,AX
	MOV	[SI].FCB_FTime,DX	;	}
FCBSave:
	TEST	FCBOp,BLOCK		;   if ((op&BLOCK) <> 0)
	JZ	DoReturn
	MOV	CX,cRecRes		;	user_CX = cRecRes;
	invoke	Get_User_Stack
	MOV	[SI.User_CX],CX
DoReturn:
	MOV	AL,FCBErr		;   return (FCBERR);
	Leave
	return
EndProc FCBIO

Break <$FCB_Open - open an old-style FCB>

;
;   $FCB_Open - CPM compatability file open.  The user has formatted an FCB
;	for us and asked to have the rest filled in.
;
;   Inputs:	DS:DX point to an unopenned FCB
;   Outputs:	AL indicates status 0 is ok FF is error
;		FCB has the following fields filled in:
;		    Time/Date Extent/NR Size

Procedure $FCB_Open,NEAR
	ASSUME	CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:DOSGROUP
	MOV	AX,sharing_Compat+Open_For_Both
	MOV	CX,OFFSET DOSGroup:DOS_Open
;
; The following is common code for Creation and openning of FCBs.  AX is
; either attributes (for create) or open mode (for open)...  DS:DX points to
; the FCB
;
DoAccess:
	SaveReg <DS,DX,CX,AX>		; save FCB pointer away
	MOV	DI,OFFSET DOSGroup:OpenBuf
	invoke	TransFCB		; crunch the fcb
	RestoreReg  <AX,CX,DX,DS>	; get fcb
	JNC	FindFCB 		; everything seems ok
FCBOpenErr:
;
; AL has error code
;
	transfer    FCB_Ret_Err
FindFCB:
	invoke	GetExtended		; DS:SI will point to FCB
	invoke	LRUFCB			; get a sft entry (no error)
	JC	HardMessage
	ASSUME	ES:NOTHING

;	Message 1,"Entering "
;	MessageNum  ES
;	Message 1,":"
;	MessageNum  DI
;	Message 1,<13,10>

	MOV	ES:[DI].sf_mode,sf_ISFCB
	SaveReg <DS,SI,BX>		; save fcb pointer
	MOV	SI,CX
	Context DS			; let DOS_Open see variables
	CALL	SI			; go open the file
	RestoreReg  <BX,SI,DS>		; get fcb
	ASSUME	DS:NOTHING
	LES	DI,ThisSFT		; get sf pointer
	JNC	FCBOK			; operation succeeded
	Assert	ISSFT,<ES,DI>,"DeadFCB"
failopen:
	PUSH	AX
	MOV	AL,"R"                  ; clear out field (free sft)
	invoke	BlastSFT
	POP	AX
	CMP	AX,error_too_many_open_files
	JZ	HardMessage
	CMP	AX,error_sharing_buffer_exceeded
	jnz	DeadFCB
HardMessage:
	PUSH	AX
	invoke	FCBHardErr
	POP	AX
DeadFCB:
	transfer    FCB_Ret_Err
FCBOK:
	invoke	IsSFTNet		       ;AN007;F.C. >32mb  Non Fat file?
	JNZ	FCBOK2			       ;AN007;F.C. >32mb  yes
	invoke	CheckShare		       ;AN000;F.C. >32mb  share around?
	JNZ	FCBOK2			       ;AN000;F.C. >32mb  yes
	CMP	WORD PTR ES:[DI].sf_dirsec+2,0 ;AN000;F.C. >32mb  if dirsec >32mb
	JZ	FCBOK2			       ;AN000;F.C. >32mb    then error
	MOV	AX,error_sys_comp_not_loaded   ;AN000;F.C. >32mb
	JMP	failopen		       ;AN000;F.C. >32mb
FCBOK2:

	INC	ES:[DI].sf_ref_count	; increment reference count
	invoke	SaveFCBInfo
	Assert	ISSFT,<ES,DI>,"FCBOK"
	invoke	SetOpenAge
	Assert	ISSFT,<ES,DI>,"FCBOK/SetOpenAge"
	TEST	ES:[DI].sf_flags,devid_device
	JNZ	FCBNoDrive		; do not munge drive on devices
	MOV	AL,DS:[SI]		; get drive byte
	invoke	GetThisDrv		; convert
	INC	AL
	MOV	DS:[SI],AL		; stash in good drive letter
FCBNoDrive:
	MOV	[SI].FCB_RecSiz,80h	; stuff in default record size
	MOV	AX,ES:[DI].SF_Time	; set time
	MOV	[SI].FCB_FTime,AX
	MOV	AX,ES:[DI].SF_Date	; set date
	MOV	[SI].FCB_FDate,AX
	MOV	AX,WORD PTR ES:[DI].SF_Size ; set sizes
	MOV	[SI].FCB_FILSIZ,AX
	MOV	AX,WORD PTR ES:[DI].SF_Size+2
	MOV	[SI].FCB_FILSIZ+2,AX
	XOR	AX,AX			; convenient zero
	MOV	[SI].FCB_Extent,AX	; point to beginning of file
;
; We must scan the set of FCB SFTs for one that appears to match the current
; one.	We cheat and use CheckFCB to match the FCBs.
;
	LES	DI,SFTFCB		; get the pointer to head of the list
	MOV	AH,BYTE PTR ES:[DI].sfCount ; get number of SFTs to scan
OpenScan:
	CMP	AL,[SI].fcb_sfn 	; don't compare ourselves
	JZ	SkipCheck
	SaveReg <AX>			; preserve count
	invoke	CheckFCB		; do they match
	RestoreReg  <AX>		; get count back
	JNC	OpenFound		; found a match!
SkipCheck:
	INC	AL			; advance to next FCB
	CMP	AL,AH			; table full?
	JNZ	OpenScan		; no, go for more
OpenDone:
	xor	al,al			; return success
	return
;
; The SFT at ES:DI is the one that is already in use for this FCB.  We set the
; FCB to use this one.	We increment its ref count.  We do NOT close it at all.
; Consider:
;
;   open (foo)	delete (foo) open (bar)
;
; This causes us to recycle (potentially) bar through the same local SFT as
; foo even though foo is no longer needed; this is due to the server closing
; foo for us when we delete it.  Unfortunately, we cannot see this closure.
; If we were to CLOSE bar, the server would then close the only reference to
; bar and subsequent I/O would be lost to the redirector.
;
; This gets solved by NOT closing the sft, but zeroing the ref count
; (effectively freeing the SFT) and informing the sharer (if relevant) that
; the SFT is no longer in use.	Note that the SHARER MUST keep its ref counts
; around.  This will allow us to access the same file through multiple network
; connections and NOT prematurely terminate when the ref count on one
; connection goes to zero.
;
OpenFound:
	MOV	[SI].fcb_SFN,AL 	; assign with this
	INC	ES:[DI].sf_ref_count	; remember this new invocation
	MOV	AX,FCBLRU		; update LRU counts
	MOV	ES:[DI].sf_LRU,AX
;
; We have an FCB sft that is now of no use.  We release sharing info and then
; blast it to prevent other reuse.
;
	context DS
	LES	DI,ThisSFT
	DEC	ES:[DI].sf_ref_count	; free the newly allocated SFT
	invoke	ShareEnd
	Assert	ISSFT,<ES,DI>,"Open blasting"
	MOV	AL,'C'
	invoke	BlastSFT
	JMP	OpenDone
EndProc $FCB_Open

BREAK	<$FCB_Create - create a new directory entry>

;
;   $FCB_Create - CPM compatability file create.  The user has formatted an
;	FCB for us and asked to have the rest filled in.
;
;   Inputs:	DS:DX point to an unopenned FCB
;   Outputs:	AL indicates status 0 is ok FF is error
;		FCB has the following fields filled in:
;		    Time/Date Extent/NR Size

Procedure $FCB_Create,NEAR
	ASSUME	CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:DOSGroup
	MOV	CX,OFFSET DOSGroup:DOS_Create	; routine to call
	XOR	AX,AX			; attributes to create
	invoke	GetExtended		; get extended FCB
	JZ	DoAccessJ		; not an extended FCB
	MOV	AL,[SI-1]		; get attributes
DoAccessJ:
	JMP	DoAccess		; do dirty work
EndProc $FCB_Create

BREAK <$FCB_Random_write_Block - write a block of records to a file >

;
;   $FCB_Random_Write_Block - retrieve a location from the FCB, seek to it
;	and write a number of blocks from it.
;
;   Inputs:	DS:DX point to an FCB
;   Outputs:	AL = 0 write was successful and the FCB position is updated
;		AL <> 0 Not enough room on disk for the output
;

Procedure $FCB_Random_Write_Block,NEAR
	ASSUME	CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:DOSGroup
	MOV	AL,Random+Block
	JMP	FCBIO
EndProc $FCB_Random_Write_Block

BREAK <$FCB_Random_Read_Block - read a block of records to a file >

;
;   $FCB_Random_Read_Block - retrieve a location from the FCB, seek to it
;	and read a number of blocks from it.
;
;   Inputs:	DS:DX point to an FCB
;   Outputs:	AL = error codes defined above
;

Procedure $FCB_Random_Read_Block,NEAR
	ASSUME	CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:DOSGroup
	MOV	AL,Random+FCBRead+Block
	JMP	FCBIO
EndProc $FCB_Random_Read_Block

BREAK <$FCB_Seq_Read - read the next record from a file >

;
;   $FCB_Seq_Read - retrieve the next record from an FCB and read it into
;	memory
;
;   Inputs:	DS:DX point to an FCB
;   Outputs:	AL = error codes defined above
;

Procedure $FCB_Seq_Read,NEAR
	ASSUME	CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:DOSGroup
	MOV	AL,FCBRead
	JMP	FCBIO
EndProc $FCB_Seq_Read

BREAK <$FCB_Seq_Write - write the next record to a file >

;
;   $FCB_Seq_Write - retrieve the next record from an FCB and write it to the
;	file
;
;   Inputs:	DS:DX point to an FCB
;   Outputs:	AL = error codes defined above
;

Procedure $FCB_Seq_Write,NEAR
	ASSUME	CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:DOSGroup
	MOV	AL,0
	jmp	FCBIO
EndProc $FCB_SEQ_WRITE

BREAK <$FCB_Random_Read - Read a single record from a file >

;
;   $FCB_Random_Read - retrieve a location from the FCB, seek to it and read a
;	record from it.
;
;   Inputs:	DS:DX point to an FCB
;   Outputs:	AL = error codes defined above
;

Procedure $FCB_Random_Read,NEAR
	ASSUME	CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:DOSGroup
	MOV	AL,Random+FCBRead
	jmp	FCBIO			; single block
EndProc $FCB_RANDOM_READ

BREAK <$FCB_Random_Write - write a single record to a file >

;
;   $FCB_Random_Write - retrieve a location from the FCB, seek to it and write
;	a record to it.
;
;   Inputs:	DS:DX point to an FCB
;   Outputs:	AL = error codes defined above
;

Procedure $FCB_Random_Write,NEAR
	ASSUME	CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:DOSGroup
	MOV	AL,Random
	jmp	FCBIO
EndProc $FCB_RANDOM_WRITE

CODE ENDS
END