1 ; SCCSID = @(#)mknode.asm 1.5 85/08/29
2 TITLE MKNODE
- Node maker
4 ; Low level routines for making a new local file system node
5 ; and filling in an SFT from a directory entry
19 ; AN000 version 4.0 Jan. 1988
20 ; A004 PTM 3680 --- Make SFT NAME field offset same as 3.30
23 ; get the appropriate segment definitions
29 CODE SEGMENT BYTE PUBLIC 'CODE'
30 ASSUME
SS:DOSGROUP
,CS:DOSGROUP
49 i_need SecClusPos
,BYTE
51 i_need NxtClusNum
,WORD
59 I_need FastOpen_Ext_info
,BYTE ; DOS 3.3
60 I_need FastOpenFlg
,BYTE ; DOS 3.3
61 I_need CPSWFLAG
,BYTE ;FT. DOS 3.4 ;AN000;
62 I_need EXTOPEN_ON
,BYTE ;FT. DOS 3.4 ;AN000;
63 I_need EXTOPEN_FLAG
,WORD ;FT. DOS 3.4 ;AN000;
64 I_need EXTOPEN_IO_MODE
,WORD ;FT. DOS 3.4 ;AN000;
65 I_need HIGH_SECTOR
,WORD ;>32mb ;AN000;
66 I_need ACT_PAGE
,WORD ;>32mb ;AN000;
68 Break <BUILDDIR
,NEWDIR
-- ALLOCATE DIRECTORIES
>
72 ; [THISSFT] Set if using NEWDIR entry point
74 ; [LASTENT] current last valid entry number in directory if no free
76 ; [DIRSTART] Points to first cluster of dir (0 means root)
78 ; Grow directory if no free entries and not root
80 ; CARRY SET IF FAILURE
82 ; AX entry number of new entry
83 ; If a new dir [DIRSTART],[CLUSFAC],[CLUSNUM],[DIRSEC] set
84 ; AX = first entry of new dir
85 ; GETENT should be called to set [LASTENT]
87 procedure BUILDDIR
,NEAR
88 DOSAssume
CS,<DS>,"BuildDir"
101 return
; Can't grow root
126 ;;;; 10/17/86 update CLUSNUM in the fastopen cache
131 MOV AH,1 ; CLUSNUM update
132 MOV DL,ES:[BP.dpb_drive
] ; drive #
133 MOV CX,[DIRSTART
] ; first cluster #
135 invoke FastOpen_Update
140 ;;;; 10/17/86 update CLUSNUM in the fastopen cache
146 MOV CL,ES:[BP.dpb_cluster_mask
]
151 MOV [ALLOWED
],allowed_FAIL
+ allowed_RETRY
159 MOV CX,ES:[BP.dpb_sector_size
]
162 OR ES:[DI.buf_flags
],buf_isDIR
173 TEST ES:[DI.buf_flags
],buf_dirty
;LB. if already dirty ;AN000;
174 JNZ yesdirty
;LB. don't increment dirty count ;AN000;
175 invoke INC_DIRTY_COUNT
;LB. ;AN000;
176 OR ES:[DI.buf_flags
],buf_dirty
190 ; set up a . or .. directory entry for a directory.
192 ; Inputs: ES:DI point to the beginning of a directory entry.
193 ; AX contains ". " or ".."
194 ; DX contains first cluster of entry
196 procedure SETDOTENT
,NEAR
197 DOSAssume
CS,<DS>,"SetDotEnt"
209 MOV AL,attr_directory
210 errnz dir_attr
-(dir_name
+11)
213 ; Initialize time and date of creation
216 MOV SI,WORD PTR [THISSFT
]
218 errnz dir_time
-(dir_attr
+1+10)
221 errnz dir_date
-(dir_time
+2)
224 ; Set up first cluster field
227 errnz dir_first
-(dir_date
+2)
233 errnz dir_size_l
-(dir_first
+2)
236 errnz
<(size dir_entry
)-(dir_size_l
+4)>
240 Break <MAKENODE
-- CREATE A NEW NODE
>
243 ; AL - attribute to create
244 ; AH = 0 if it is ok to truncate a file already by this name
245 ; AH = Non 0 if this is an error
246 ; (AH ignored on dirs and devices)
247 ; NOTE: When making a DIR or volume ID, AH need not be set since
248 ; a name already existant is ALWAYS an error in these cases.
249 ; [WFP_START] Points to WFP string ("d:/" must be first 3 chars, NUL
251 ; [CURR_DIR_END] Points to end of Current dir part of string
252 ; ( = -1 if current dir not involved, else
253 ; Points to first char after last "/" of current dir part)
254 ; [THISCDS] Points to CDS being used
255 ; [THISSFT] Points to an empty SFT. EXCEPT sf_mode filled in.
259 ; Sets EXTERR_LOCUS = errLOC_Disk or errLOC_Unk via GetPathNoset
261 ; AX = 1 A node by this name exists and is a directory
262 ; AX = 2 A new node could not be created
263 ; AX = 3 A node by this name exists and is a disk file
264 ; (AH was NZ on input)
266 ; SI return from GetPath maintained
267 ; AX = 5 Attribute mismatch
268 ; AX = 6 Sharing Violation
269 ; (INT 24 generated ALWAYS since create is always compat mode
270 ; AX = 7 file not found for Extended Open (not exists and fails)
273 ; AX = 3 Device Node (error in some cases)
274 ; [DIRSTART],[DIRSEC],[CLUSFAC],[CLUSNUM] set to directory
275 ; containing new node.
276 ; [CURBUF+2]:BX Points to entry
277 ; [CURBUF+2]:SI Points to entry.dir_first
278 ; [THISSFT] is filled in
279 ; sf_mode = unchanged.
280 ; Attribute byte in entry is input AL
281 ; DS preserved, others destroyed
283 procedure MakeNode
,NEAR
284 DOSAssume
CS,<DS>,"MakeNode"
287 MOV WORD PTR [CREATING
],0E5FFH ; Creating, not DEL *.*
288 PUSH AX ; Save AH value
292 MOV DL,CL ; Save CL info
293 MOV CX,AX ; Device ID to CH
295 JNC make_exists
; File existed
296 JNZ make_err_4
; Path bad
297 CMP DL,80H
; Check "CL" return from GETPATH
298 JZ make_type
; Name simply not found, and no metas
300 MOV AL,4 ; case 1 bad path
306 entry RENAME_MAKE
; Used by DOS_RENAME to "copy" a node
310 TEST [EXTOPEN_ON
],ext_open_on
;FT. from extended open ;AN000;
311 JZ make_type2
;FT. no ;AN000;
312 OR [EXTOPEN_ON
],ext_file_not_exists
;FT. set for extended open ;AN000;
313 TEST [EXTOPEN_FLAG
],0F0H ;FT. not exists and fails ;AN000;
314 JNZ make_type2
;FT. no ;AN000;
315 STC ;FT. set carry ;AN000;
316 MOV AX,7 ;FT. file not found ;AN000;
321 ; MOV ES:[DI.sf_mode],sharing_compat + open_for_both
322 XOR AX,AX ; nothing exists Disk Node
327 ; The node exists. It may be either a device, directory or file:
328 ; Zero set => directory
329 ; High bit of CH on => device
333 MOV AL,3 ; file exists type 3 (error or device node)
334 TEST BYTE PTR [ATTRIB
],(attr_volume_id
+attr_directory
)
335 JNZ make_err_ret_5
; Cannot already exist as Disk or Device Node
336 ; if making DIR or Volume ID
338 JS make_share
; No further checks on attributes if device
340 JNZ make_err_ret
; truncating NOT OK (AL = 3)
341 PUSH CX ; Save device ID
342 MOV ES,WORD PTR [CURBUF
+2]
343 MOV CH,ES:[BX+dir_attr
] ; Get file attributes
344 TEST CH,attr_read_only
345 JNZ make_err_ret_5P
; Cannot create on read only files
346 invoke MatchAttributes
347 POP CX ; Devid back in CH
348 JNZ make_err_ret_5
; Attributes not ok
349 XOR AL,AL ; AL = 0, Disk Node
352 PUSH AX ; Save Disk or Device node
353 PUSH CX ; Save Device ID
354 MOV AH,CH ; Device ID to AH
355 CALL DOOPEN
; Fill in SFT for share check
357 ; MOV ES:[DI.sf_mode],sharing_compat + open_for_both
358 SaveReg
<SI,BX> ; Save CURBUF pointers
362 ; User failed request.
364 RestoreReg
<BX,SI,CX,AX>
370 POP CX ; Get back device ID
372 MOV AL,5 ; Attribute mismatch
376 MOV AL,1 ; exists as directory, always an error
380 PUSH AX ; Save whether Disk or File
381 MOV AX,CX ; Device ID to AH
383 POP AX ; 0 if Disk, 3 if File
385 MOV AL,2 ; create failed case 2
391 TEST BYTE PTR [ATTRIB
],attr_directory
392 retnz
; Don't "open" directories, so don't
393 ; tell the sharer about them
394 SaveReg
<AX,BX,SI> ; Save AL code
396 RestoreReg
<SI,BX,AX>
399 ; We get here by having the user FAIL a share problem. Typically a failure of
400 ; this nature is an out-of-space or an internal error. We clean up as best as
401 ; possible: delete the newly created directory entry and return share_error.
405 MOV BYTE PTR ES:[BX],0E5H ; nuke newly created entry.
407 TEST ES:[DI.buf_flags
],buf_dirty
;LB. if already dirty ;AN000;
408 JNZ yesdirty2
;LB. don't increment dirty count ;AN000;
409 invoke INC_DIRTY_COUNT
;LB. ;AN000;
410 OR ES:[DI].buf_flags
,buf_dirty
; flag buffer as dirty
413 MOV AL,ES:[BP].DPB_Drive
; get drive for flush
414 Invoke FlushBuf
; write out buffer.
418 ; We have found an existing file. We have also entered it into the share set.
419 ; At this point we need to call newentry to correctly address the problem of
420 ; getting rid of old data (create an existing file) or creating a new
421 ; directory entry (create a new file). Unfortunately, this operation may
422 ; result in an INT 24 that the user doesn't return from, thus locking the file
423 ; irretrievably into the share set. The correct solution is for us to LEAVE
424 ; the share set now, do the operation and then reassert the share access.
426 ; We are allowed to do this! There is no window! After all, we are in
427 ; critDisk here and for someone else to get in, they must enter critDisk also.
430 LES DI,ThisSFT
; grab SFT
433 XCHG AX,ES:[DI].sf_ref_count
436 invoke ShareEnd
; remove sharing
438 RestoreReg
<ES,DI,ES:[DI].sf_ref_count
>
440 RestoreReg
<BX,SI,CX,AX>
443 ; If the user failed, we do not reenter into the sharing set.
450 RestoreReg
<SI,BX,AX>
452 ; If Share_check fails, then we have an internal ERROR!!!!!
460 ; [LASTENT] current last valid entry number in directory if no free
462 ; [VOLID] set if a volume ID was found during search
463 ; [ATTRIB] Contains attributes for new file
464 ; [DIRSTART] Points to first cluster of dir (0 means root)
465 ; CARRY FLAG INDICATES STATUS OF SEARCH FOR FILE
466 ; NC means file existed (device)
467 ; C means file did not exist
468 ; AH = Device ID byte
470 ; [CURBUF+2]:BX points to start of directory entry
471 ; [CURBUF+2]:SI points to dir_first of directory entry
473 ; DS:BX points to start of "fake" directory entry
474 ; DS:SI points to dir_first of "fake" directory entry
475 ; (has DWORD pointer to device header)
477 ; Make a new directory entry
478 ; If an old one existed it is truncated first
481 ; Can't grow dir, atts didn't match, attempt to make 2nd
482 ; vol ID, user FAILed to I 24
485 ; DS, BX, SI preserved (meaning on SI BX, not value), others destroyed
487 procedure NEWENTRY
,NEAR
488 DOSAssume
CS,<DS>,"NewEntry"
496 retnz
; User FAILed, node might exist
497 CALL BUILDDIR
; Try to build dir
499 invoke GETENT
; Point at that free entry
508 DOSAssume
CS,<DS>,"MKNODE/ExistEnt"
509 OR AH,AH ; Check if file is I/O device
511 JMP DOOPEN
; If so, proceed with open
514 invoke FREEENT
; Free cluster chain
517 TEST BYTE PTR [ATTRIB
],attr_volume_id
519 CMP BYTE PTR [VOLID
],0
520 JNZ ERRRET3
; Can't create a second volume ID
522 MOV ES,WORD PTR [CURBUF
+2]
524 MOV SI,OFFSET DOSGROUP
:NAME1
527 MOVSB ; Move name into dir entry
529 errnz dir_attr
-(dir_name
+11)
531 ;; File Tagging for Create DOS 4.00
532 MOV CL,5 ;FT. assume normal ;AN000;
533 ; CMP [CPSWFLAG],0 ;FT. code page matching on ;AN000;
534 ; JZ NORMFT ;FT. no, make null code page ;AN000;
535 ; invoke Get_Global_CdPg ;FT. get global code page ;AN000;
536 ; STOSW ;FT. tag this file with global code page ;AN000;
537 ; DEC CL ;FT. only 4 ;AN000;
538 ;NORMFT: ;FT. ;AN000;
540 ;; File Tagging for Create DOS 4.00
545 errnz dir_time
-(dir_attr
+1+2*5)
548 errnz dir_date
-(dir_time
+2)
551 PUSH DI ; Correct SI input value (recomputed for new buffer)
553 errnz dir_first
-(dir_date
+2)
554 STOSW ; Zero dir_first and size
555 errnz dir_size_l
-(dir_first
+2)
559 errnz
<(size dir_entry
)-(dir_size_l
+4)>
560 MOV SI,WORD PTR [CURBUF
]
562 TEST ES:[SI.buf_flags
],buf_dirty
;LB. if already dirty ;AN000;
563 JNZ yesdirty3
;LB. don't increment dirty count ;AN000;
564 invoke INC_DIRTY_COUNT
;LB. ;AN000;
565 OR ES:[SI.buf_flags
],buf_dirty
568 MOV AL,ES:[BP.dpb_drive
] ; Sets AH value again (in AL)
571 ; If we have a file, we need to increment the open ref. count so that
572 ; we have some protection against invalid media changes if an Int 24
574 ; Do nothing for a device.
577 test es:[di.sf_flags
],devid_device
581 MOV word ptr ES:[DI.sf_devptr
],BX
583 MOV word ptr ES:[DI.sf_devptr
+2],BX
584 RestoreReg
<BX,DS> ; need to use DS for segment later on
585 invoke Dev_Open_SFT
; increment ref. count
586 mov [VIRTUAL_OPEN
],1; set flag
590 PUSH [ACT_PAGE
] ;LB. save EMS page for curbuf ;AN000;
592 POP BX ;LB. restore EMS page for curbuf ;AN000;
593 PUSHF ;LB. save flushbuf falg ;AN000;
594 CMP BX,-1 ;BL-NETWORK PTM #-?
595 JE Page_ok
;BL-NETWORK PTM #-?
596 invoke SET_MAP_PAGE
;LB. remap curbuf ;AN000;
597 Page_ok: ;BL-NETWORK PTM #-?
598 POPF ;LB. restore flush flag ;AN000;
599 Call CHECK_VIRT_OPEN
; decrement ref. count ;AN000;
602 POP SI ; Get SI input back
603 MOV AH,AL ; Get I/O driver number back
610 ; [THISDPB] points to DPB if file
611 ; [THISSFT] points to SFT being used
612 ; AH = Device ID byte
614 ; [CURBUF+2]:BX points to start of directory entry
615 ; [CURBUF+2]:SI points to dir_first of directory entry
617 ; DS:BX points to start of "fake" directory entry
618 ; DS:SI points to dir_first of "fake" directory entry
619 ; (has DWORD pointer to device header)
621 ; Fill in SFT from dir entry
624 ; sf_ref_count and sf_mode fields not altered
625 ; sf_flags high byte = 0
626 ; sf_flags low byte = AH except
627 ; sf_flags Bit 6 set (not dirty or not EOF)
628 ; sf_attr sf_date sf_time sf_name set from entry
631 ; sf_devptr = dword at dir_first (pointer to device header)
634 ; sf_firclus sf_size set from entry
635 ; sf_devptr = [THISDPB]
637 ; sf_lstclus = sf_firclus
638 ; sf_dirsec sf_dirpos set
639 ; DS,SI,BX preserved, others destroyed
642 DOSAssume
CS,<DS>,"DoOpen"
646 ; Generate and store attribute
648 MOV DH,AH ; AH to different place
650 ADD DI,sf_attr
; Skip ref_count and mode fields
651 XOR AL,AL ; Assume it's a device, devices have an
652 ; attribute of 0 (for R/O testing etc).
653 OR DH,DH ; See if our assumption good.
654 JS DEV_SFT1
; If device DS=DOSGROUP
655 MOV DS,WORD PTR [CURBUF
+2]
657 MOV AL,[BX.dir_attr
] ; If file, get attrib from dir entry
659 STOSB ; sf_attr, ES:DI -> sf_flags
661 ; Generate and store flags word
665 OR AL,devid_file_clean
666 STOSW ; sf_flags, ES:DI -> sf_devptr
668 ; Generate and store device pointer
671 LDS AX,DWORD PTR [BX.dir_first
] ; Assume device
674 LDS AX,[THISDPB
] ; Was file
679 STOSW ; store segment
680 ; ES:DI -> sf_firclus
682 ; Generate pointer to, generate and store first cluster (irrelevant for
685 PUSH SI ; Save pointer to dir_first
686 MOVSW ; dir_first -> sf_firclus
687 ; DS:SI -> dir_size_l, ES:DI -> sf_time
689 ; Copy time/date of last modification
691 SUB SI,dir_size_l
- dir_time
; DS:SI->dir_time
692 MOVSW ; dir_time -> sf_time
693 ; DS:SI -> dir_date, ES:DI -> sf_date
694 MOVSW ; dir_date -> sf_date
695 ; DS:SI -> dir_first, ES:DI -> sf_size
697 ; Generate and store file size (0 for devices)
699 LODSW ; skip dir_first, DS:SI -> dir_size_l
700 LODSW ; dir_size_l in AX , DS:SI -> dir_size_h
701 MOV CX,AX ; dir_size_l in CX
702 LODSW ; dir_size_h (size AX:CX), DS:SI -> ????
706 MOV CX,AX ; Devices are open ended
709 STOSW ; Low word of sf_size
711 STOSW ; High word of sf_size
712 ; ES:DI -> sf_position
714 ; Initialize position to 0
719 ; ES:DI -> sf_cluspos
721 ; Generate cluster optimizations for files
726 MOV AX,[BX.dir_first
]
727 ;;;; STOSW ; sf_lstclus
728 PUSH DI ;AN004; save dirsec offset
729 SUB DI,sf_dirsec
;AN004; es:di -> SFT
730 MOV ES:[DI.sf_lstclus
],AX ;AN004; save it
731 POP DI ;AN004; restore dirsec offset
735 ; DOS 3.3 FastOpen 6/13/86
739 TEST [FastOpenFlg
],Special_Fill_Set
741 MOV SI,OFFSET DOSGROUP
:FastOpen_Ext_Info
742 MOV AX,WORD PTR [SI.FEI_dirsec
]
744 MOV AX,WORD PTR [SI.FEI_dirsec
+2] ;;; changed for >32mb
746 MOV AL,[SI.FEI_dirpos
]
751 ; DOS 3.3 FastOpen 6/13/86
756 MOV SI,WORD PTR [CURBUF
] ; DS:SI->buffer header
757 MOV AX,WORD PTR [SI.buf_sector
] ;F.C. >32mb ;AN000;
758 STOSW ; sf_dirsec ;F.C. >32mb ;AN000;
759 MOV AX,WORD PTR [SI.buf_sector
+2] ;F.C. >32mb ;AN000;
760 STOSW ; sf_dirsec ;F.C. >32mb ;AN000;
762 ADD SI,BUFINSIZ
; DS:SI-> start of data in buffer
763 SUB AX,SI ; AX = BX relative to start of sector
764 MOV CL,SIZE dir_entry
769 errnz sf_name
-(sf_dirpos
+1)
773 ADD DI,sf_name
- sf_cluspos
776 ; Copy in the object's name
778 MOV SI,BX ; DS:SI points to dir_name
781 POP SI ; recover DS:SI -> dir_first
782 ;; File tagging , code page and XA cluster must be after name
783 ; MOV AX,[BX.dir_CODEPG] ;FT. set file's code page ;AN000;
785 ; MOV AX,[BX.dir_EXTCLUSTER] ;FT. set XA cluster ;AN000;
787 ; MOV AX,[EXTOPEN_IO_MODE] ;FT. extended open ;AN000;
789 ; MOV AL,[BX.dir_attr2] ;FT. high attribute ;AN000;
792 ;; File tagging , code page and XA cluster must be after name
803 ; [CURBUF+2]:BX points to directory entry
804 ; [CURBUF+2]:SI points to above dir_first
806 ; Free the cluster chain for the entry if present
808 ; Carry set if error (currently user FAILed to I 24)
809 ; (NOTE dir_firclus and dir_size_l/h are wrong)
810 ; DS BX SI ES BP preserved (BX,SI in meaning, not value) others destroyed
812 procedure FREEENT
,NEAR
813 DOSAssume
CS,<DS>,"FreeEnt"
819 MOV CX,[SI] ; Get pointer to clusters
820 MOV DX,WORD PTR [DI.buf_sector
+2] ;F.C. >32mb ;AN000;
821 MOV [HIGH_SECTOR
],DX ;F.C. >32mb ;AN000;
822 MOV DX,WORD PTR [DI.buf_sector
]
824 DOSAssume
CS,<DS>,"MKNODE/FreeEnt"
826 JB RET1
; Was 0 length file (or mucked Firclus if CX=1)
827 CMP CX,ES:[BP.dpb_max_cluster
]
828 JA RET1
; Treat like zero length file (firclus mucked)
830 PUSH BX ; Save offset
831 PUSH [HIGH_SECTOR
] ;F.C. >32mb ;AN000;
832 PUSH DX ; Save sector number
835 invoke Delete_FSeek
; FS. delete Fastseek Clusters ;AN000;
836 invoke RELEASE
; Free any data allocated
838 POP [HIGH_SECTOR
] ;F.C. >32mb ;AN000;
845 MOV [ALLOWED
],allowed_RETRY
+ allowed_FAIL
847 invoke GETBUFFR
; Get sector back
848 POP BX ; Get offset back
850 invoke SET_BUF_AS_DIR
851 ADD BX,WORD PTR [CURBUF
] ; Correct it for new buffer
853 ADD SI,dir_first
; Get corrected SI
860 ; CHECK_VIRT_OPEN checks to see if we had performed a "virtual open" (by
861 ; examining the flag [VIRTUAL_OPEN] to see if it is 1). If we did, then
862 ; it calls Dev_Close_SFT to decrement the ref. count. It also resets the
863 ; flag [VIRTUAL_OPEN].
864 ; No registers affected (including flags).
865 ; On input, [THISSFT] points to current SFT.
867 Procedure CHECK_VIRT_OPEN
,NEAR
868 DOSAssume
CS,<DS>,"Check_Virt_Open"
871 lahf ; preserve flags
874 mov [VIRTUAL_OPEN
],0 ; reset flag
885 EndProc CHECK_VIRT_OPEN