; ; Directory routines for MSDOS ; INCLUDE DOSSEG.ASM CODE SEGMENT BYTE PUBLIC 'CODE' ASSUME SS:DOSGROUP,CS:DOSGROUP .xlist .xcref INCLUDE DOSSYM.ASM INCLUDE DEVSYM.ASM .cref .list TITLE DIR - Directory and path cracking NAME Dir i_need NoSetDir,BYTE i_need EntFree,WORD i_need DirStart,WORD i_need LastEnt,WORD i_need ClusNum,WORD i_need CurBuf,DWORD i_need ThisFCB,DWORD i_need Attrib,BYTE i_need DelAll,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 DriveSpec,BYTE i_need Device_availability,BYTE i_need RootStart,BYTE i_need DevString,BYTE i_need DevStrLen,BYTE SUBTTL BUILDDIR,NEWDIR -- ALLOCATE DIRECTORIES PAGE procedure BUILDDIR,NEAR ASSUME DS:DOSGROUP,ES:NOTHING ; Inputs: ; ES:BP Points to DPB ; [THISFCB] Set if using NEWDIR entry point ; [LASTENT] current last valid entry number in directory if no free ; entries ; 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] MOV AX,[ENTFREE] CMP AX,-1 JNZ GOTRET CMP [DIRSTART],0 JNZ NEWDIR STC return ; Can't grow root entry NEWDIR MOV BX,[DIRSTART] OR BX,BX JZ NULLDIR invoke GETEOF NULLDIR: MOV CX,1 invoke ALLOCATE retc MOV DX,[DIRSTART] OR DX,DX JNZ ADDINGDIR call SETDIRSRCH MOV [LASTENT],-1 JMP SHORT GOTDIRREC ADDINGDIR: CMP [CLUSNUM],0FF8H JB NOTFIRSTGROW MOV [CLUSNUM],BX 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 AL,0FFH invoke GETBUFFR MOV CX,ES:[BP.dpb_sector_size] PUSH ES LES DI,[CURBUF] PUSH DI ADD DI,BUFINSIZ XOR AX,AX SHR CX,1 REP STOSW JNC EVENZ STOSB EVENZ: POP DI INC AL MOV ES:[DI.BUFDIRTY],AL POP ES POP CX INC DX LOOP ZERODIR MOV AX,[LASTENT] INC AX GOTRET: CLC return BUILDDIR ENDP ; ; set up a . and .. directory entry for a directory ; procedure SETDOTENT,NEAR ASSUME DS:DOSGROUP MOV CX,4 MOV AX,2020H REP STOSW STOSB MOV SI,WORD PTR [THISFCB] MOV AL,attr_directory STOSB ADD DI,10 MOV AX,[SI.fcb_FTIME] STOSW MOV AX,[SI.fcb_FDATE] STOSW MOV AX,DX STOSW XOR AX,AX STOSW STOSW return SETDOTENT ENDP SUBTTL GETFILE, GETNAME, FINDNAME -- LOOK FOR A FILE PAGE procedure SEARCH,near entry GETFILE ASSUME DS:NOTHING,ES:NOTHING ; Same as GETNAME except ES:DI points to FCB on successful return invoke MOVNAME retc PUSH DX PUSH DS CALL FINDNAME POP ES POP DI return entry GETNAME ASSUME DS:NOTHING,ES:NOTHING ; Inputs: ; DS,DX point to FCB ; Function: ; Find file name in disk directory. First byte is ; drive number (0=current disk). "?" matches any ; character. ; Outputs: ; Carry set if file not found ; ELSE ; Zero set if attributes match (always except when creating) ; AH = Device ID (bit 7 set if not disk) ; [THISDPB] = Base of drive parameters ; DS = DOSGROUP ; ES = DOSGROUP ; [CURBUF+2]:BX = Pointer into directory buffer ; [CURBUF+2]:SI = Pointer to First Cluster field in directory entry ; [CURBUF] has directory record with match ; [NAME1] has file name ; All other registers destroyed. invoke MOVNAME ASSUME ES:DOSGROUP retc ; Bad file name? entry FINDNAME PUSH SS POP DS ASSUME DS:DOSGROUP invoke DEVNAME JC FindEntry invoke BUILDFCB return ASSUME ES:NOTHING ; NOTE THE FALL THROUGH SUBTTL FINDENTRY -- LOOK FOR AN ENTRY PAGE entry FindEntry ASSUME DS:DOSGROUP,ES:NOTHING ; Inputs: ; [THISDPB] set ; [SECCLUSPOS] = 0 ; [DIRSEC] = Starting directory sector number ; [CLUSNUM] = Next cluster of directory ; [CLUSFAC] = Sectors/Cluster ; [NAME1] = Name to look for ; Function: ; Find file name in disk directory. ; "?" matches any character. ; Outputs: ; Carry set if name not found ; ELSE ; Zero set if attributes match (always except when creating) ; AH = Device ID (bit 7 set if not disk) ; [THISDPB] = Base of drive parameters ; DS = DOSGROUP ; ES = DOSGROUP ; [CURBUF+2]:BX = Pointer into directory buffer ; [CURBUF+2]:SI = Pointer to First Cluster field in directory entry ; [CURBUF] has directory record with match ; [NAME1] has file name ; [LASTENT] is entry number of the entry ; All other registers destroyed. CALL STARTSRCH CMP BYTE PTR [ATTRIB],attr_volume_id ; Looking for vol ID only ? JNZ NOTVOLSRCH ; No CALL SETROOTSRCH ; Yes force search of root NOTVOLSRCH: CALL GETENTRY entry Srch PUSH DS MOV DS,WORD PTR [CURBUF+2] ASSUME DS:NOTHING MOV AH,BYTE PTR [BX] OR AH,AH ; End of directory? JZ FREE CMP AH,BYTE PTR [DELALL] ; Free entry? JZ FREE TEST BYTE PTR [BX+11],attr_volume_id ; Volume ID file? JZ CHKFNAM ; NO INC BYTE PTR [VOLID] CHKFNAM: MOV SI,BX PUSH SS POP ES ASSUME ES:DOSGROUP MOV DI,OFFSET DOSGROUP:NAME1 MOV CX,11 WILDCRD: REPE CMPSB JZ FOUND CMP BYTE PTR ES:[DI-1],"?" JZ WILDCRD POP DS ASSUME DS:DOSGROUP entry NEXTENT LES BP,[THISDPB] ASSUME ES:NOTHING CALL NEXTENTRY JNC SRCH JMP SHORT SETESRET FREE: POP DS ASSUME DS:DOSGROUP MOV CX,[LASTENT] CMP CX,[ENTFREE] JAE TSTALL MOV [ENTFREE],CX TSTALL: CMP AH,BYTE PTR [DELALL] ; At end of directory? JZ NEXTENT ; No - continue search MOV [ENTLAST],CX STC JMP SHORT SETESRET FOUND: ; ; We have a file with a matching name. We must now consider ; the attributes: ; ATTRIB Action ; ------ ------ ; Volume_ID Is Volume_ID in test? ; Otherwise If no create then Is ATTRIB+extra superset of test? ; If create then Is ATTRIB equal to test? ; MOV CH,[SI] ; Attributes of file POP DS ASSUME DS:DOSGROUP MOV AH,BYTE PTR [ATTRIB] ; Attributes of search TEST CH,attr_volume_id ; Volume ID file? JZ check_one_volume_id ; Nope check other attributes TEST AH,attr_volume_id ; Can we find Volume ID? JZ NEXTENT ; Nope, (not even $FCB_CREATE) XOR AH,AH ; Set zero flag for $FCB_CREATE JMP SHORT RETF ; Found Volume ID check_one_volume_id: CMP AH,attr_volume_id ; Looking only for Volume ID? JZ NEXTENT ; Yes, continue search ADD SI,15 CALL MatchAttributes JZ RETF TEST BYTE PTR [CREATING],-1 ; Pass back mismatch if creating JZ NEXTENT ; Otherwise continue searching RETF: LES BP,[THISDPB] MOV AH,ES:[BP.dpb_drive] SETESRET: PUSH SS POP ES return SUBTTL GETENTRY, NEXTENTRY, GETENT -- STEP THROUGH DIRECTORY PAGE entry GETENTRY ASSUME DS:DOSGROUP,ES:NOTHING ; Inputs: ; [LASTENT] has directory entry ; ES:BP points to drive parameters ; Function: ; Locates directory entry in preparation for search ; GETENT provides entry for passing desired entry in AX ; A valid search environment MUST exist ; ENDENT,ENTLAST,ENTFREE ; Outputs: ; [CURBUF+2]:BX = Pointer to next directory entry in CURBUF ; [CURBUF+2]:DX = Pointer to first byte after end of CURBUF ; [LASTENT] = New directory entry number MOV AX,[LASTENT] entry GETENT MOV [LASTENT],AX MOV CL,4 SHL AX,CL XOR DX,DX SHL AX,1 RCL DX,1 ; Account for overflow in last shift MOV BX,ES:[BP.dpb_sector_size] AND BL,255-31 ; Must be multiple of 32 DIV BX MOV BX,DX ; Position within sector PUSH BX invoke DIRREAD POP BX SETENTRY: MOV DX,WORD PTR [CURBUF] ADD DX,BUFINSIZ ADD BX,DX ADD DX,ES:[BP.dpb_sector_size] ; Always clears carry return entry NEXTENTRY ASSUME DS:DOSGROUP,ES:NOTHING ; Inputs: ; Same as outputs of GETENTRY, above ; Function: ; Update BX, and [LASTENT] for next directory entry. ; Carry set if no more. MOV AX,[LASTENT] CMP AX,[ENTLAST] JZ NONE INC AX ADD BX,32 CMP BX,DX JB HAVIT MOV BL,BYTE PTR [SECCLUSPOS] INC BL CMP BL,BYTE PTR [CLUSFAC] JB SAMECLUS MOV BX,[NXTCLUSNUM] CMP BX,0FF8H JAE NONE CMP BX,2 JB NONE JMP GETENT NONE: STC return HAVIT: MOV [LASTENT],AX CLC return SAMECLUS: MOV BYTE PTR [SECCLUSPOS],BL MOV [LASTENT],AX PUSH DS LDS DI,[CURBUF] ASSUME DS:NOTHING MOV DX,[DI.BUFSECNO] INC DX POP DS ASSUME DS:DOSGROUP invoke FIRSTCLUSTER XOR BX,BX JMP SETENTRY Search ENDP SUBTTL GETCURRDIR -- GET CURRENT DIRECTORY PAGE procedure Dir_search,NEAR entry GETCURRDIR ASSUME DS:NOTHING,ES:NOTHING ; Inputs: ; ES:BP Points to DPB ; FATREAD should be called before this routine ; Function: ; Find current directory for drive ; If path is bad set current directory to the root ; Outputs: ; DS = DOSGROUP ; [SECCLUSPOS] = 0 ; [DIRSTART] = Cluster # of first cluster of directory ( 0 if root) ; [DIRSEC] Set to phys sec # of first sector first cluster of directory ; [CLUSNUM] Set to next cluster ; [CLUSFAC] Sectors/cluster ; Destroys all registers MOV BX,ES:[BP.dpb_current_dir] OR BX,BX JZ SETROOTSRCH CMP BX,0FF8H JB SETDIRSRCH PUSH ES POP DS LEA SI,[BP.dpb_dir_text] CALL ROOTPATH ASSUME DS:DOSGROUP JNC SETCURR MOV ES:[BP.dpb_current_dir],0 SETROOTSRCH: ASSUME DS:NOTHING,ES:NOTHING PUSH SS POP DS ASSUME DS:DOSGROUP XOR AX,AX MOV [DIRSTART],AX MOV BYTE PTR [SECCLUSPOS],AL DEC AX MOV [CLUSNUM],AX MOV AX,ES:[BP.dpb_first_sector] MOV DX,ES:[BP.dpb_dir_sector] SUB AX,DX MOV BYTE PTR [CLUSFAC],AL MOV [DIRSEC],DX return SETCURR: ASSUME DS:DOSGROUP MOV AX,[DIRSTART] MOV ES:[BP.dpb_current_dir],AX return entry SETDIRSRCH ASSUME DS:NOTHING,ES:NOTHING ; Inputs: ; BX cluster number of start of directory ; ES:BP Points to DPB ; Function: ; Set up a directory search ; Outputs: ; DS = DOSGROUP ; [DIRSTART] = BX ; [CLUSFAC],[CLUSNUM],[SECCLUSPOS],[DIRSEC] set ; destroys AX,DX OR BX,BX JZ SETROOTSRCH PUSH SS POP DS ASSUME DS:DOSGROUP MOV [DIRSTART],BX MOV AL,ES:[BP.dpb_cluster_mask] INC AL MOV BYTE PTR [CLUSFAC],AL invoke UNPACK MOV [CLUSNUM],DI MOV DX,BX XOR BL,BL MOV BYTE PTR [SECCLUSPOS],BL invoke FIGREC MOV [DIRSEC],DX return Dir_search ENDP SUBTTL MAKENODE -- CREATE A NEW NODE PAGE procedure MakeNode,NEAR ASSUME DS:NOTHING,ES:NOTHING ; Inputs: ; AL - attribute to create ; DS:SI Points to asciz path ; [THISFCB] Points to an empty FCB ; Function: ; Make a new node ; Outputs: ; DS=DOSGROUP ; ES:BP Points to DPB ; AX = 0 Success ; AX = 1 A node by this name exists and is a directory ; AX = 2 A new node could not be created error ; AX = 3 A node by this name exists and is a file error ; AX = 4 Bad Path error ; AX = 5 Attribute mismatch error ; CARRY SET IF ERROR ; ELSE ; [DIRSTART],[DIRSEC],[CLUSFAC],[CLUSNUM] set to directory ; containing new node. ; [CURBUF+2]:BX Points to entry ; [CURBUF+2]:SI Points to entry.fcb_firclus ; [ThisFCB] is filled in ; If this is a new entry zero is set and ; Attribute byte in entry is directory ; else a file existed by this name and: ; [NAME1] has name ; entry is not changed in any way ; Destroys all registers PUSH AX CALL GetPath MOV DL,CL ; Save CL info POP CX MOV BYTE PTR [ATTRIB],CL MOV CX,AX JNC make_exists ; File existed JNZ make_err_4 ; Path bad OR DL,DL ; Check "CL" return from GETPATH JNZ make_type ; Name simply not found make_err_4: MOV AL,4 ; case 1 bad path make_err_ret: STC return make_type: XOR AL,AL ; nothing exists... assume 0 STC JMP SHORT make_save make_exists: JZ make_exists_dir MOV AL,3 ; file exists type 3 TEST BYTE PTR [ATTRIB],(attr_volume_id+attr_directory) JNZ make_err_ret_5 ; but we wanted a volid or dir OR CH,CH JS make_dev ; No furthur checks if device PUSH CX MOV DS,WORD PTR [CURBUF+2] MOV CH,[BX+dir_attr] ; Get file attributes TEST CH,attr_read_only JNZ make_err_ret_5P ; Cannot create on read only files CALL MatchAttributes make_err_ret_5P: POP CX JZ make_dev ; Attributes ok make_err_ret_5: MOV AL,5 ; Attribute mismatch JMP SHORT make_err_ret make_dev: XOR AL,AL ; Make sure zero set(atts match), carry clear(exists) MOV AL,3 ; Restore correct value JMP SHORT make_save make_exists_dir: MOV AL,1 ; directory exists TEST BYTE PTR [ATTRIB],attr_directory JZ make_err_ret ; we didn't want a directory CLC return ; just return make_save: PUSH AX ; ; set up for call to NewEntry - it is in the middle of FCB_CREATE ; so we must also pre-push two registers. They will be popped off ; by FCB_CREATE ; PUSH SS POP DS ASSUME DS:DOSGROUP PUSHF ;Save state of flags CMP BYTE PTR [NAME1],'.' ;Detect attempt to make '.' or '..' JNZ NOTLDOT ; Needed because no '.' or '..' in root POPF MOV AL,1 ;Force type 2 error JMP SHORT SET2ERR NOTLDOT: POPF PUSH ES LES DI,[ThisFCB] PUSH DS PUSH DI PUSH ES MOV AX,CX invoke NewEntry POP DS POP ES SET2ERR: OR AL,AL POP AX JZ make_set_fcb MOV AL,2 ; create failed case 2 STC return make_set_fcb: ASSUME DS:DOSGROUP PUSH ES LES DI,[THISFCB] INC DI PUSH DS PUSH SI MOV DS,WORD PTR [CURBUF+2] ASSUME DS:NOTHING MOV SI,BX MOV CX,11 REP MOVSB POP SI POP DS ASSUME DS:DOSGROUP POP ES CMP AL,1 JA make_errors OR AL,AL CLC return make_errors: STC return MakeNode ENDP SUBTTL GETPATH -- PARSE AN asciz PATH PAGE procedure GETPATH,near ASSUME DS:NOTHING,ES:NOTHING ; Inputs: ; DS:SI Points to asciz path ; Function: ; Crack the path ; Outputs: ; [DRIVESPEC] is non zero if a drive was specified ; [ROOTSTART] is non zero if a / started the path ; [ATTRIB] set to attr_directory+attr_hidden+attr_system ; Same as FINDPATH except if path specifies a device in which case ; bit 7 of AH will be set and SI and BX will point DOSGROUP relative ; Destroys all registers XOR AX,AX MOV WORD PTR [DRIVESPEC],AX MOV BYTE PTR [ATTRIB],attr_directory+attr_system+attr_hidden LODSB invoke PATHCHRCMP JZ DEFAULTROOT MOV AH,AL LODSB CMP AL,':' JZ DRVSPEC DEC SI DEC SI PUSH DS PUSH SI PUSH SS POP ES CMP BYTE PTR [device_availability],0 JZ NOWDEV CALL GOTPRESTRING2 JNC BUILDFCBJ ; If no carry then we have a device NOWDEV: CALL DEFPATH GOFIND: MOV AL,[NoSetDir] PUSH AX MOV [NoSetDir],0 CALL GETCURRDIR POP AX MOV [NoSetDir],AL POP SI POP DS JMP FINDPATH DEFPATH: XOR AL,AL DRVPATH: invoke GETTHISDRV retc ; Bad drive PUSH SS POP DS invoke FATREAD CLC return DEFAULTROOT: PUSH DS PUSH SI CALL DEFPATH POP SI POP DS ROOTSRCH: INC BYTE PTR [ROOTSTART] CMP BYTE PTR [SI],0 JZ PATHISNULL PUSH DS PUSH SI PUSH ES ; Save pointer to DPB CALL CHKDEV POP ES JNC BUILDFCBJ POP SI POP DS JMP ROOTPATH BUILDFCBJ: POP AX POP AX context es invoke BUILDFCB ; Clears carry sets zero INC AL ; reset zero return DRVSPEC: INC [DRIVESPEC] MOV AL,AH OR AL,20H ; Convert to lower case SUB AL,60H ; Make A=1 PUSH DS PUSH SI PUSH AX context es CALL GotPreString2 ASSUME ES:NOTHING POP AX JNC BuildFCBJ CALL DRVPATH POP SI POP DS retc ; Bad drive LODSB invoke PATHCHRCMP JZ ROOTSRCH DEC SI PUSH DS PUSH SI JMP GOFIND PATHISNULL: CALL SETROOTSRCH ASSUME DS:DOSGROUP XOR AL,AL ; Set zero (directory) clear carry return CHKDEV: ASSUME DS:NOTHING PUSH SS POP ES MOV DI,OFFSET DOSGROUP:DEVSTRING XOR CX,CX MOV CL,DEVSTRLEN CHKPRESTRING: REPE CMPSB JZ GOTPRESTRING DEC SI invoke GETLET ; Try convert to upper case CMP AL,ES:[DI-1] JZ CHKPRESTRING NOPRESTRING: STC return GOTPRESTRING: LODSB invoke PATHCHRCMP JNZ NOPRESTRING GOTPRESTRING2: MOV DI,OFFSET DOSGROUP:NAME1 MOV CX,9 TESTLOOP: invoke GETLET CMP AL,'.' JZ TESTDEVICE invoke PATHCHRCMP JZ NOTDEV OR AL,AL JZ TESTDEVICE STOSB LOOP TESTLOOP NOTDEV: STC return TESTDEVICE: ADD CX,2 MOV AL,' ' REP STOSB PUSH SS POP DS invoke DEVNAME return GETPATH ENDP SUBTTL ROOTPATH, FINDPATH -- PARSE A PATH PAGE procedure ROOTPATH,near ASSUME DS:NOTHING,ES:NOTHING ; Inputs: ; ES:BP Points to DPB ; FATREAD should be called before this routine ; DS:SI Points to asciz string of path which is assumed to start at ; the root (no leading '/'). ; Function: ; Search from root for path ; Outputs: ; Same as FINDPATH ; Destroys all registers PUSH DS CALL SETROOTSRCH POP DS ; NOTE FALL THROUGH entry FINDPATH ASSUME DS:NOTHING,ES:NOTHING ; Inputs: ; ES:BP Points to DPB ; DS:SI Points to asciz string of path (no leading '/'). ; [SECCLUSPOS] = 0 ; [DIRSEC] = Phys sec # of first sector of directory ; [CLUSNUM] = Cluster # of next cluster ; [CLUSFAC] = Sectors per cluster ; Validate_path should be called before this routine is used, ; unless it is KNOWN the path is good. ; Function: ; Parse path name ; Outputs: ; ES:BP Points to DPB ; Carry set if bad path ; DS:SI Points to path element causing failure ; Zero set ; [DIRSTART],[DIRSEC],[CLUSNUM], and [CLUSFAC] are set up to ; start a search on the last directory ; CL is zero if there is a bad name in the path ; CL is non-zero if the name was simply not found ; [ENTFREE] may have free spot in directory ; [NAME1] is the name. ; CL = 81H if '*'s or '?' in name 1, 80H otherwise ; Zero reset ; File in middle of path or bad name in path ; or path too long or malformed path ; ELSE ; DS = DOSGROUP ; AH = device ID ; [CURBUF] contains directory record with match ; [CURBUF+2]:BX Points into [CURBUF] to start of entry ; [CURBUF+2]:SI Points to fcb_FIRCLUS field for entry ; [NAME1] Has entry name ; If last element is a directory zero is set and: ; [DIRSTART],[SECCLUSPOS],[DIRSEC],[CLUSNUM], and [CLUSFAC] ; are set up to start a search on it. ; If last element is a file zero is reset ; Destroys all registers PUSH ES PUSH SI invoke NAMETRANS MOV CL,AL OR CL,80H POP DI POP ES CMP SI,DI JNZ check_device JMP BADPATH check_device: PUSH DS PUSH SI MOV AL,BYTE PTR [SI] ; ; can we see all devices ; context DS CMP BYTE PTR [device_availability],0 JZ FindFile ; ; check name1 to see if we have a device... ; PUSH ES context ES invoke DevName ; blast BX POP ES ASSUME ES:NOTHING JC FindFile OR AL,AL JNZ FileInPath POP SI POP SI context ES invoke BuildFCB INC AL return FindFile: ASSUME ES:NOTHING PUSH DI ; Start of this element PUSH ES PUSH CX CALL FINDENTRY POP CX POP ES POP DI JC BADPATHPOP LDS DI,[CURBUF] ASSUME DS:NOTHING TEST BYTE PTR [BX+dir_attr],attr_directory JZ FileInPath ; ; if we are not setting the directory, then ; check for end of string ; CMP BYTE PTR [NoSetDir],0 JZ SetDir MOV DX,DI MOV AX,DS POP DI POP DS CMP BYTE PTR [DI],0 JZ SetRet PUSH DS PUSH DI MOV DI,DX MOV DS,AX SetDir: MOV DX,[SI] SUB BX,DI SUB SI,DI PUSH BX PUSH AX PUSH SI PUSH CX PUSH [DI.BUFSECNO] MOV BX,DX CALL SETDIRSRCH ASSUME DS:DOSGROUP POP DX XOR AL,AL invoke GETBUFFR POP CX POP SI POP AX POP BX MOV DI,WORD PTR [CURBUF] ADD SI,DI ADD BX,DI POP DI POP DS ASSUME DS:NOTHING MOV AL,[DI] OR AL,AL JZ SETRET INC DI MOV SI,DI invoke PATHCHRCMP JNZ find_bad_name JMP FINDPATH find_bad_name: DEC SI BADPATH: XOR CL,CL ; Set zero STC return FILEINPATH: POP DI POP DS MOV AL,[DI] OR AL,AL JZ INCRET MOV SI,DI ; Path too long STC return INCRET: INC AL ; Reset zero SETRET: PUSH SS POP DS return BADPATHPOP: POP SI POP DS MOV AL,[SI] MOV SI,DI ; Start of bad element OR AL,AL ; zero if bad element is last, non-zero if path too long STC return ROOTPATH ENDP SUBTTL STARTSRCH -- INITIATE DIRECTORY SEARCH PAGE procedure StartSrch,NEAR ASSUME DS:DOSGROUP,ES:NOTHING ; Inputs: ; [THISDPB] Set ; Function: ; Set up a search for GETENTRY and NEXTENTRY ; Outputs: ; ES:BP = Drive parameters ; Sets up LASTENT, ENDENT, ENTFREE=ENTLAST=-1, VOLID=0 ; Destroys all registers (via FATREAD) LES BP,[THISDPB] XOR AX,AX MOV [LASTENT],AX MOV BYTE PTR [VOLID],AL ; No volume ID found DEC AX MOV [ENTFREE],AX MOV [ENTLAST],AX return StartSrch ENDP BREAK ; ; Input: [Attrib] = attribute to search for ; CH = found attribute ; Output: JZ ; JNZ ; procedure MatchAttributes,near ASSUME DS:NOTHING,ES:NOTHING PUSH AX MOV AL,[Attrib] ; AL <- SearchSet NOT AL ; AL <- SearchSet' AND AL,CH ; AL <- SearchSet' and FoundSet AND AL,attr_all ; AL <- SearchSet' and FoundSet and Important ; ; the result is non-zero if an attribute is not in the search set ; and in the found set and in the important set. This means that we do not ; have a match. Do a JNZ or JZ ; POP AX return MatchAttributes ENDP do_ext CODE ENDS END