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
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
|
; SCCSID = @(#)mknode.asm 1.5 85/08/29
TITLE MKNODE - Node maker
NAME MKNODE
; Low level routines for making a new local file system node
; and filling in an SFT from a directory entry
;
; BUILDDIR
; SETDOTENT
; MakeNode
; NEWENTRY
; FREEENT
; NEWDIR
; DOOPEN
; RENAME_MAKE
; CHECK_VIRT_OPEN
;
; Revision history:
;
; AN000 version 4.0 Jan. 1988
; A004 PTM 3680 --- Make SFT NAME field offset same as 3.30
;
; get the appropriate segment definitions
;
.xlist
include dosseg.asm
include fastopen.inc
CODE SEGMENT BYTE PUBLIC 'CODE'
ASSUME SS:DOSGROUP,CS:DOSGROUP
.xcref
include dossym.inc
include devsym.inc
.cref
.list
i_need EntFree,WORD
i_need DirStart,WORD
i_need LastEnt,WORD
i_need ClusNum,WORD
i_need CurBuf,DWORD
i_need Attrib,BYTE
i_need VolID,BYTE
i_need Name1,BYTE
i_need ThisDPB,DWORD
i_need EntLast,WORD
i_need Creating,BYTE
i_need SecClusPos,BYTE
i_need ClusFac,BYTE
i_need NxtClusNum,WORD
i_need DirSec,WORD
i_need NoSetDir,BYTE
i_need THISSFT,DWORD
i_need SATTRIB,BYTE
i_need ALLOWED,BYTE
i_need FAILERR,BYTE
i_need VIRTUAL_OPEN
I_need FastOpen_Ext_info,BYTE ; DOS 3.3
I_need FastOpenFlg,BYTE ; DOS 3.3
I_need CPSWFLAG,BYTE ;FT. DOS 3.4 ;AN000;
I_need EXTOPEN_ON,BYTE ;FT. DOS 3.4 ;AN000;
I_need EXTOPEN_FLAG,WORD ;FT. DOS 3.4 ;AN000;
I_need EXTOPEN_IO_MODE,WORD ;FT. DOS 3.4 ;AN000;
I_need HIGH_SECTOR,WORD ;>32mb ;AN000;
I_need ACT_PAGE,WORD ;>32mb ;AN000;
Break <BUILDDIR,NEWDIR -- ALLOCATE DIRECTORIES>
; Inputs:
; ES:BP Points to DPB
; [THISSFT] Set if using NEWDIR entry point
; (used by ALLOCATE)
; [LASTENT] current last valid entry number in directory if no free
; entries
; [DIRSTART] Points to first cluster of dir (0 means root)
; Function:
; Grow directory if no free entries and not root
; Outputs:
; CARRY SET IF FAILURE
; ELSE
; AX entry number of new entry
; If a new dir [DIRSTART],[CLUSFAC],[CLUSNUM],[DIRSEC] set
; AX = first entry of new dir
; GETENT should be called to set [LASTENT]
procedure BUILDDIR,NEAR
DOSAssume CS,<DS>,"BuildDir"
ASSUME ES:NOTHING
MOV AX,[ENTFREE]
CMP AX,-1
JZ CHECK_IF_ROOT
CLC
return
CHECK_IF_ROOT:
CMP [DIRSTART],0
JNZ NEWDIR
STC
return ; Can't grow root
entry NEWDIR
MOV BX,[DIRSTART]
OR BX,BX
JZ NULLDIR
invoke GETEOF
retc ; Screw up
NULLDIR:
MOV CX,1
invoke ALLOCATE
retc
MOV DX,[DIRSTART]
OR DX,DX
JNZ ADDINGDIR
invoke SETDIRSRCH
retc
MOV [LASTENT],-1
JMP SHORT GOTDIRREC
ADDINGDIR:
PUSH BX
MOV BX,[ClusNum]
Invoke IsEof
POP BX
JB NOTFIRSTGROW
;;;; 10/17/86 update CLUSNUM in the fastopen cache
MOV [CLUSNUM],BX
PUSH CX
PUSH AX
PUSH BP
MOV AH,1 ; CLUSNUM update
MOV DL,ES:[BP.dpb_drive] ; drive #
MOV CX,[DIRSTART] ; first cluster #
MOV BP,BX ; CLUSNUM
invoke FastOpen_Update
POP BP
POP AX
POP CX
;;;; 10/17/86 update CLUSNUM in the fastopen cache
NOTFIRSTGROW:
MOV DX,BX
XOR BL,BL
invoke FIGREC
GOTDIRREC:
MOV CL,ES:[BP.dpb_cluster_mask]
INC CL
XOR CH,CH
ZERODIR:
PUSH CX
MOV [ALLOWED],allowed_FAIL + allowed_RETRY
MOV AL,0FFH
invoke GETBUFFR
JNC GET_SSIZE
POP CX
return
GET_SSIZE:
MOV CX,ES:[BP.dpb_sector_size]
PUSH ES
LES DI,[CURBUF]
OR ES:[DI.buf_flags],buf_isDIR
PUSH DI
ADD DI,BUFINSIZ
XOR AX,AX
SHR CX,1
REP STOSW
JNC EVENZ
STOSB
EVENZ:
POP DI
TEST ES:[DI.buf_flags],buf_dirty ;LB. if already dirty ;AN000;
JNZ yesdirty ;LB. don't increment dirty count ;AN000;
invoke INC_DIRTY_COUNT ;LB. ;AN000;
OR ES:[DI.buf_flags],buf_dirty
yesdirty:
POP ES
POP CX
INC DX
LOOP ZERODIR
MOV AX,[LASTENT]
INC AX
CLC
return
EndProc BUILDDIR
;
; set up a . or .. directory entry for a directory.
;
; Inputs: ES:DI point to the beginning of a directory entry.
; AX contains ". " or ".."
; DX contains first cluster of entry
;
procedure SETDOTENT,NEAR
DOSAssume CS,<DS>,"SetDotEnt"
;
; Fill in name field
;
STOSW
MOV CX,4
MOV AX," "
REP STOSW
STOSB
;
; Set up attribute
;
MOV AL,attr_directory
errnz dir_attr-(dir_name+11)
STOSB
;
; Initialize time and date of creation
;
ADD DI,10
MOV SI,WORD PTR [THISSFT]
MOV AX,[SI.sf_time]
errnz dir_time-(dir_attr+1+10)
STOSW
MOV AX,[SI.sf_date]
errnz dir_date-(dir_time+2)
STOSW
;
; Set up first cluster field
;
MOV AX,DX
errnz dir_first-(dir_date+2)
STOSW
;
; 0 file size
;
XOR AX,AX
errnz dir_size_l-(dir_first+2)
STOSW
STOSW
errnz <(size dir_entry)-(dir_size_l+4)>
return
EndProc SETDOTENT
Break <MAKENODE -- CREATE A NEW NODE>
; Inputs:
; AL - attribute to create
; AH = 0 if it is ok to truncate a file already by this name
; AH = Non 0 if this is an error
; (AH ignored on dirs and devices)
; NOTE: When making a DIR or volume ID, AH need not be set since
; a name already existant is ALWAYS an error in these cases.
; [WFP_START] Points to WFP string ("d:/" must be first 3 chars, NUL
; terminated)
; [CURR_DIR_END] Points to end of Current dir part of string
; ( = -1 if current dir not involved, else
; Points to first char after last "/" of current dir part)
; [THISCDS] Points to CDS being used
; [THISSFT] Points to an empty SFT. EXCEPT sf_mode filled in.
; Function:
; Make a new node
; Outputs:
; Sets EXTERR_LOCUS = errLOC_Disk or errLOC_Unk via GetPathNoset
; CARRY SET IF ERROR
; AX = 1 A node by this name exists and is a directory
; AX = 2 A new node could not be created
; AX = 3 A node by this name exists and is a disk file
; (AH was NZ on input)
; AX = 4 Bad Path
; SI return from GetPath maintained
; AX = 5 Attribute mismatch
; AX = 6 Sharing Violation
; (INT 24 generated ALWAYS since create is always compat mode
; AX = 7 file not found for Extended Open (not exists and fails)
; ELSE
; AX = 0 Disk Node
; AX = 3 Device Node (error in some cases)
; [DIRSTART],[DIRSEC],[CLUSFAC],[CLUSNUM] set to directory
; containing new node.
; [CURBUF+2]:BX Points to entry
; [CURBUF+2]:SI Points to entry.dir_first
; [THISSFT] is filled in
; sf_mode = unchanged.
; Attribute byte in entry is input AL
; DS preserved, others destroyed
procedure MakeNode,NEAR
DOSAssume CS,<DS>,"MakeNode"
ASSUME ES:NOTHING
MOV WORD PTR [CREATING],0E5FFH ; Creating, not DEL *.*
PUSH AX ; Save AH value
MOV [NoSetDir],0
MOV [SATTRIB],AL
invoke GetPathNoSet
MOV DL,CL ; Save CL info
MOV CX,AX ; Device ID to CH
POP AX ; Get back AH
JNC make_exists ; File existed
JNZ make_err_4 ; Path bad
CMP DL,80H ; Check "CL" return from GETPATH
JZ make_type ; Name simply not found, and no metas
make_err_4:
MOV AL,4 ; case 1 bad path
make_err_ret:
XOR AH,AH
STC
return
entry RENAME_MAKE ; Used by DOS_RENAME to "copy" a node
make_type:
;Extended Open hooks
TEST [EXTOPEN_ON],ext_open_on ;FT. from extended open ;AN000;
JZ make_type2 ;FT. no ;AN000;
OR [EXTOPEN_ON],ext_file_not_exists ;FT. set for extended open ;AN000;
TEST [EXTOPEN_FLAG],0F0H ;FT. not exists and fails ;AN000;
JNZ make_type2 ;FT. no ;AN000;
STC ;FT. set carry ;AN000;
MOV AX,7 ;FT. file not found ;AN000;
return ;FT. ;AN000;
make_type2:
;Extended Open hooks
LES DI,[THISSFT]
; MOV ES:[DI.sf_mode],sharing_compat + open_for_both
XOR AX,AX ; nothing exists Disk Node
STC ; Not found
JMP make_new
;
; The node exists. It may be either a device, directory or file:
; Zero set => directory
; High bit of CH on => device
; else => file
make_exists:
JZ make_exists_dir
MOV AL,3 ; file exists type 3 (error or device node)
TEST BYTE PTR [ATTRIB],(attr_volume_id+attr_directory)
JNZ make_err_ret_5 ; Cannot already exist as Disk or Device Node
; if making DIR or Volume ID
OR CH,CH
JS make_share ; No further checks on attributes if device
OR AH,AH
JNZ make_err_ret ; truncating NOT OK (AL = 3)
PUSH CX ; Save device ID
MOV ES,WORD PTR [CURBUF+2]
MOV CH,ES:[BX+dir_attr] ; Get file attributes
TEST CH,attr_read_only
JNZ make_err_ret_5P ; Cannot create on read only files
invoke MatchAttributes
POP CX ; Devid back in CH
JNZ make_err_ret_5 ; Attributes not ok
XOR AL,AL ; AL = 0, Disk Node
make_share:
XOR AH,AH
PUSH AX ; Save Disk or Device node
PUSH CX ; Save Device ID
MOV AH,CH ; Device ID to AH
CALL DOOPEN ; Fill in SFT for share check
LES DI,[THISSFT]
; MOV ES:[DI.sf_mode],sharing_compat + open_for_both
SaveReg <SI,BX> ; Save CURBUF pointers
invoke ShareEnter
jnc MakeEndShare
;
; User failed request.
;
RestoreReg <BX,SI,CX,AX>
Make_Share_ret:
MOV AL,6
JMP make_err_ret
make_err_ret_5P:
POP CX ; Get back device ID
make_err_ret_5:
MOV AL,5 ; Attribute mismatch
JMP make_err_ret
make_exists_dir:
MOV AL,1 ; exists as directory, always an error
JMP make_err_ret
make_save:
PUSH AX ; Save whether Disk or File
MOV AX,CX ; Device ID to AH
CALL NewEntry
POP AX ; 0 if Disk, 3 if File
retnc
MOV AL,2 ; create failed case 2
return
make_new:
call make_save
retc ; case 2 fail
TEST BYTE PTR [ATTRIB],attr_directory
retnz ; Don't "open" directories, so don't
; tell the sharer about them
SaveReg <AX,BX,SI> ; Save AL code
invoke ShareEnter
RestoreReg <SI,BX,AX>
retnc
;
; We get here by having the user FAIL a share problem. Typically a failure of
; this nature is an out-of-space or an internal error. We clean up as best as
; possible: delete the newly created directory entry and return share_error.
;
PUSH AX
LES DI,CurBuf
MOV BYTE PTR ES:[BX],0E5H ; nuke newly created entry.
TEST ES:[DI.buf_flags],buf_dirty ;LB. if already dirty ;AN000;
JNZ yesdirty2 ;LB. don't increment dirty count ;AN000;
invoke INC_DIRTY_COUNT ;LB. ;AN000;
OR ES:[DI].buf_flags,buf_dirty ; flag buffer as dirty
yesdirty2:
LES BP,ThisDPB
MOV AL,ES:[BP].DPB_Drive ; get drive for flush
Invoke FlushBuf ; write out buffer.
POP AX
jmp make_Share_ret
;
; We have found an existing file. We have also entered it into the share set.
; At this point we need to call newentry to correctly address the problem of
; getting rid of old data (create an existing file) or creating a new
; directory entry (create a new file). Unfortunately, this operation may
; result in an INT 24 that the user doesn't return from, thus locking the file
; irretrievably into the share set. The correct solution is for us to LEAVE
; the share set now, do the operation and then reassert the share access.
;
; We are allowed to do this! There is no window! After all, we are in
; critDisk here and for someone else to get in, they must enter critDisk also.
;
MakeEndShare:
LES DI,ThisSFT ; grab SFT
XOR AX,AX
EnterCrit critSFT
XCHG AX,ES:[DI].sf_ref_count
SaveReg <AX,DI,ES>
PUSHF
invoke ShareEnd ; remove sharing
POPF
RestoreReg <ES,DI,ES:[DI].sf_ref_count>
LeaveCrit critSFT
RestoreReg <BX,SI,CX,AX>
CALL make_save
;
; If the user failed, we do not reenter into the sharing set.
;
retc ; bye if error
SaveReg <AX,BX,SI>
PUSHF
invoke ShareEnter
POPF
RestoreReg <SI,BX,AX>
;
; If Share_check fails, then we have an internal ERROR!!!!!
;
return
EndProc MakeNode
; Inputs:
; [THISSFT] set
; [THISDPB] set
; [LASTENT] current last valid entry number in directory if no free
; entries
; [VOLID] set if a volume ID was found during search
; [ATTRIB] Contains attributes for new file
; [DIRSTART] Points to first cluster of dir (0 means root)
; CARRY FLAG INDICATES STATUS OF SEARCH FOR FILE
; NC means file existed (device)
; C means file did not exist
; AH = Device ID byte
; If FILE
; [CURBUF+2]:BX points to start of directory entry
; [CURBUF+2]:SI points to dir_first of directory entry
; If device
; DS:BX points to start of "fake" directory entry
; DS:SI points to dir_first of "fake" directory entry
; (has DWORD pointer to device header)
; Function:
; Make a new directory entry
; If an old one existed it is truncated first
; Outputs:
; Carry set if error
; Can't grow dir, atts didn't match, attempt to make 2nd
; vol ID, user FAILed to I 24
; else
; outputs of DOOPEN
; DS, BX, SI preserved (meaning on SI BX, not value), others destroyed
procedure NEWENTRY,NEAR
DOSAssume CS,<DS>,"NewEntry"
ASSUME ES:NOTHING
LES BP,[THISDPB]
ASSUME ES:NOTHING
JNC EXISTENT
CMP [FAILERR],0
STC
retnz ; User FAILed, node might exist
CALL BUILDDIR ; Try to build dir
retc ; Failed
invoke GETENT ; Point at that free entry
retc ; Failed
JMP SHORT FREESPOT
ERRRET3:
STC
return
EXISTENT:
DOSAssume CS,<DS>,"MKNODE/ExistEnt"
OR AH,AH ; Check if file is I/O device
JNS NOT_DEV1
JMP DOOPEN ; If so, proceed with open
NOT_DEV1:
invoke FREEENT ; Free cluster chain
retc ; Failed
FREESPOT:
TEST BYTE PTR [ATTRIB],attr_volume_id
JZ NOTVOLID
CMP BYTE PTR [VOLID],0
JNZ ERRRET3 ; Can't create a second volume ID
NOTVOLID:
MOV ES,WORD PTR [CURBUF+2]
MOV DI,BX
MOV SI,OFFSET DOSGROUP:NAME1
MOV CX,5
REP MOVSW
MOVSB ; Move name into dir entry
MOV AL,[ATTRIB]
errnz dir_attr-(dir_name+11)
STOSB ; Attributes
;; File Tagging for Create DOS 4.00
MOV CL,5 ;FT. assume normal ;AN000;
; CMP [CPSWFLAG],0 ;FT. code page matching on ;AN000;
; JZ NORMFT ;FT. no, make null code page ;AN000;
; invoke Get_Global_CdPg ;FT. get global code page ;AN000;
; STOSW ;FT. tag this file with global code page ;AN000;
; DEC CL ;FT. only 4 ;AN000;
;NORMFT: ;FT. ;AN000;
;; File Tagging for Create DOS 4.00
XOR AX,AX
REP STOSW ; Zero pad
invoke DATE16
XCHG AX,DX
errnz dir_time-(dir_attr+1+2*5)
STOSW ; dir_time
XCHG AX,DX
errnz dir_date-(dir_time+2)
STOSW ; dir_date
XOR AX,AX
PUSH DI ; Correct SI input value (recomputed for new buffer)
errnz dir_first-(dir_date+2)
STOSW ; Zero dir_first and size
errnz dir_size_l-(dir_first+2)
STOSW
STOSW
updnxt:
errnz <(size dir_entry)-(dir_size_l+4)>
MOV SI,WORD PTR [CURBUF]
TEST ES:[SI.buf_flags],buf_dirty ;LB. if already dirty ;AN000;
JNZ yesdirty3 ;LB. don't increment dirty count ;AN000;
invoke INC_DIRTY_COUNT ;LB. ;AN000;
OR ES:[SI.buf_flags],buf_dirty
yesdirty3:
LES BP,[THISDPB]
MOV AL,ES:[BP.dpb_drive] ; Sets AH value again (in AL)
PUSH AX
PUSH BX
; If we have a file, we need to increment the open ref. count so that
; we have some protection against invalid media changes if an Int 24
; error occurs.
; Do nothing for a device.
SaveReg <ES,DI>
LES DI,[THISSFT]
test es:[di.sf_flags],devid_device
jnz GotADevice
SaveReg <DS,BX>
LDS BX,[THISDPB]
MOV word ptr ES:[DI.sf_devptr],BX
MOV BX,DS
MOV word ptr ES:[DI.sf_devptr+2],BX
RestoreReg <BX,DS> ; need to use DS for segment later on
invoke Dev_Open_SFT ; increment ref. count
mov [VIRTUAL_OPEN],1; set flag
GotADevice:
RestoreReg <DI,ES>
PUSH [ACT_PAGE] ;LB. save EMS page for curbuf ;AN000;
invoke FLUSHBUF
POP BX ;LB. restore EMS page for curbuf ;AN000;
PUSHF ;LB. save flushbuf falg ;AN000;
CMP BX,-1 ;BL-NETWORK PTM #-?
JE Page_ok ;BL-NETWORK PTM #-?
invoke SET_MAP_PAGE ;LB. remap curbuf ;AN000;
Page_ok: ;BL-NETWORK PTM #-?
POPF ;LB. restore flush flag ;AN000;
Call CHECK_VIRT_OPEN ; decrement ref. count ;AN000;
POP BX
POP AX
POP SI ; Get SI input back
MOV AH,AL ; Get I/O driver number back
retc ; Failed
;NOTE FALL THROUGH
; Inputs:
; [THISDPB] points to DPB if file
; [THISSFT] points to SFT being used
; AH = Device ID byte
; If FILE
; [CURBUF+2]:BX points to start of directory entry
; [CURBUF+2]:SI points to dir_first of directory entry
; If device
; DS:BX points to start of "fake" directory entry
; DS:SI points to dir_first of "fake" directory entry
; (has DWORD pointer to device header)
; Function:
; Fill in SFT from dir entry
; Outputs:
; CARRY CLEAR
; sf_ref_count and sf_mode fields not altered
; sf_flags high byte = 0
; sf_flags low byte = AH except
; sf_flags Bit 6 set (not dirty or not EOF)
; sf_attr sf_date sf_time sf_name set from entry
; sf_position = 0
; If device
; sf_devptr = dword at dir_first (pointer to device header)
; sf_size = 0
; If file
; sf_firclus sf_size set from entry
; sf_devptr = [THISDPB]
; sf_cluspos = 0
; sf_lstclus = sf_firclus
; sf_dirsec sf_dirpos set
; DS,SI,BX preserved, others destroyed
entry DOOPEN
DOSAssume CS,<DS>,"DoOpen"
ASSUME ES:NOTHING
;
; Generate and store attribute
;
MOV DH,AH ; AH to different place
LES DI,[THISSFT]
ADD DI,sf_attr ; Skip ref_count and mode fields
XOR AL,AL ; Assume it's a device, devices have an
; attribute of 0 (for R/O testing etc).
OR DH,DH ; See if our assumption good.
JS DEV_SFT1 ; If device DS=DOSGROUP
MOV DS,WORD PTR [CURBUF+2]
ASSUME DS:NOTHING
MOV AL,[BX.dir_attr] ; If file, get attrib from dir entry
DEV_SFT1:
STOSB ; sf_attr, ES:DI -> sf_flags
;
; Generate and store flags word
;
XOR AX,AX
MOV AL,DH
OR AL,devid_file_clean
STOSW ; sf_flags, ES:DI -> sf_devptr
;
; Generate and store device pointer
;
PUSH DS
LDS AX,DWORD PTR [BX.dir_first] ; Assume device
OR DH,DH
JS DEV_SFT2
LDS AX,[THISDPB] ; Was file
DEV_SFT2:
STOSW ; store offset
MOV AX,DS
POP DS
STOSW ; store segment
; ES:DI -> sf_firclus
;
; Generate pointer to, generate and store first cluster (irrelevant for
; devices)
;
PUSH SI ; Save pointer to dir_first
MOVSW ; dir_first -> sf_firclus
; DS:SI -> dir_size_l, ES:DI -> sf_time
;
; Copy time/date of last modification
;
SUB SI,dir_size_l - dir_time ; DS:SI->dir_time
MOVSW ; dir_time -> sf_time
; DS:SI -> dir_date, ES:DI -> sf_date
MOVSW ; dir_date -> sf_date
; DS:SI -> dir_first, ES:DI -> sf_size
;
; Generate and store file size (0 for devices)
;
LODSW ; skip dir_first, DS:SI -> dir_size_l
LODSW ; dir_size_l in AX , DS:SI -> dir_size_h
MOV CX,AX ; dir_size_l in CX
LODSW ; dir_size_h (size AX:CX), DS:SI -> ????
OR DH,DH
JNS FILE_SFT1
XOR AX,AX
MOV CX,AX ; Devices are open ended
FILE_SFT1:
XCHG AX,CX
STOSW ; Low word of sf_size
XCHG AX,CX
STOSW ; High word of sf_size
; ES:DI -> sf_position
;
; Initialize position to 0
;
XOR AX,AX
STOSW
STOSW ; sf_position
; ES:DI -> sf_cluspos
;
; Generate cluster optimizations for files
;
OR DH,DH
JS DEV_SFT3
STOSW ; sf_cluspos
MOV AX,[BX.dir_first]
;;;; STOSW ; sf_lstclus
PUSH DI ;AN004; save dirsec offset
SUB DI,sf_dirsec ;AN004; es:di -> SFT
MOV ES:[DI.sf_lstclus],AX ;AN004; save it
POP DI ;AN004; restore dirsec offset
; DOS 3.3 FastOpen 6/13/86
PUSH DS
context DS
TEST [FastOpenFlg],Special_Fill_Set
JZ Not_FastOpen
MOV SI,OFFSET DOSGROUP:FastOpen_Ext_Info
MOV AX,WORD PTR [SI.FEI_dirsec]
STOSW ; sf_dirsec
MOV AX,WORD PTR [SI.FEI_dirsec+2] ;;; changed for >32mb
STOSW ; sf_dirsec
MOV AL,[SI.FEI_dirpos]
STOSB ; sf_dirpos
POP DS
JMP Next_Name
; DOS 3.3 FastOpen 6/13/86
Not_FastOpen:
POP DS ; normal path
ASSUME DS:NOTHING
MOV SI,WORD PTR [CURBUF] ; DS:SI->buffer header
MOV AX,WORD PTR [SI.buf_sector] ;F.C. >32mb ;AN000;
STOSW ; sf_dirsec ;F.C. >32mb ;AN000;
MOV AX,WORD PTR [SI.buf_sector+2] ;F.C. >32mb ;AN000;
STOSW ; sf_dirsec ;F.C. >32mb ;AN000;
MOV AX,BX
ADD SI,BUFINSIZ ; DS:SI-> start of data in buffer
SUB AX,SI ; AX = BX relative to start of sector
MOV CL,SIZE dir_entry
DIV CL
STOSB ; sf_dirpos
Next_Name:
errnz sf_name-(sf_dirpos+1)
JMP SHORT FILE_SFT2
DEV_SFT3:
ADD DI,sf_name - sf_cluspos
FILE_SFT2:
;
; Copy in the object's name
;
MOV SI,BX ; DS:SI points to dir_name
MOV CX,11
REP MOVSB ; sf_name
POP SI ; recover DS:SI -> dir_first
;; File tagging , code page and XA cluster must be after name
; MOV AX,[BX.dir_CODEPG] ;FT. set file's code page ;AN000;
; STOSW ;FT. ;AN000;
; MOV AX,[BX.dir_EXTCLUSTER] ;FT. set XA cluster ;AN000;
; STOSW ;FT. ;AN000;
; MOV AX,[EXTOPEN_IO_MODE] ;FT. extended open ;AN000;
; STOSW ;FT. ;AN000;
; MOV AL,[BX.dir_attr2] ;FT. high attribute ;AN000;
; STOSB ;FT. ;AN000;
;; File tagging , code page and XA cluster must be after name
context DS
CLC
return
EndProc NEWENTRY
; Inputs:
; ES:BP -> DPB
; [CURBUF] Set
; [CURBUF+2]:BX points to directory entry
; [CURBUF+2]:SI points to above dir_first
; Function:
; Free the cluster chain for the entry if present
; Outputs:
; Carry set if error (currently user FAILed to I 24)
; (NOTE dir_firclus and dir_size_l/h are wrong)
; DS BX SI ES BP preserved (BX,SI in meaning, not value) others destroyed
procedure FREEENT,NEAR
DOSAssume CS,<DS>,"FreeEnt"
ASSUME ES:NOTHING
PUSH DS
LDS DI,[CURBUF]
ASSUME DS:NOTHING
MOV CX,[SI] ; Get pointer to clusters
MOV DX,WORD PTR [DI.buf_sector+2] ;F.C. >32mb ;AN000;
MOV [HIGH_SECTOR],DX ;F.C. >32mb ;AN000;
MOV DX,WORD PTR [DI.buf_sector]
POP DS
DOSAssume CS,<DS>,"MKNODE/FreeEnt"
CMP CX,2
JB RET1 ; Was 0 length file (or mucked Firclus if CX=1)
CMP CX,ES:[BP.dpb_max_cluster]
JA RET1 ; Treat like zero length file (firclus mucked)
SUB BX,DI
PUSH BX ; Save offset
PUSH [HIGH_SECTOR] ;F.C. >32mb ;AN000;
PUSH DX ; Save sector number
MOV BX,CX
invoke Delete_FSeek ; FS. delete Fastseek Clusters ;AN000;
invoke RELEASE ; Free any data allocated
POP DX
POP [HIGH_SECTOR] ;F.C. >32mb ;AN000;
JNC GET_BUF_BACK
POP BX
return ; Screw up
GET_BUF_BACK:
MOV [ALLOWED],allowed_RETRY + allowed_FAIL
XOR AL,AL
invoke GETBUFFR ; Get sector back
POP BX ; Get offset back
retc
invoke SET_BUF_AS_DIR
ADD BX,WORD PTR [CURBUF] ; Correct it for new buffer
MOV SI,BX
ADD SI,dir_first ; Get corrected SI
RET1:
CLC
return
EndProc FREEENT
;
; CHECK_VIRT_OPEN checks to see if we had performed a "virtual open" (by
; examining the flag [VIRTUAL_OPEN] to see if it is 1). If we did, then
; it calls Dev_Close_SFT to decrement the ref. count. It also resets the
; flag [VIRTUAL_OPEN].
; No registers affected (including flags).
; On input, [THISSFT] points to current SFT.
;
Procedure CHECK_VIRT_OPEN,NEAR
DOSAssume CS,<DS>,"Check_Virt_Open"
PUSH AX
lahf ; preserve flags
CMP [VIRTUAL_OPEN],0
JZ ALL_CLOSED
mov [VIRTUAL_OPEN],0 ; reset flag
SaveReg <ES,DI>
LES DI,[THISSFT]
INVOKE DEV_CLOSE_SFT
RestoreReg <DI,ES>
ALL_CLOSED:
sahf ; restore flags
POP AX
return
EndProc CHECK_VIRT_OPEN
CODE ENDS
END
|