Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

526 lines
16 KiB

page ,132
;/*
; * Microsoft Confidential
; * Copyright (C) Microsoft Corporation 1991
; * All Rights Reserved.
; */
; SCCSID = @(#)path1.asm 1.1 85/05/14
; SCCSID = @(#)path1.asm 1.1 85/05/14
.sall
.xlist
.xcref
include dossym.inc
include syscall.inc
include comsw.asm
include comseg.asm
include comequ.asm
.list
.cref
break <Path.Asm>
;----------------------------------------------------------------------------
; PATH.ASM contains the routines to perform pathname incovation. Path and
; Parse share a temporary buffer and argv[] definitions. <Path_Search>,
; given a pathname, attempts to find a corresponding executable or batch
; file on disk. Directories specified in the user's search path will be
; searched for a matching file, if a match is not found in the current
; directory and if the pathname is actually only an MSDOS filename.
; <Path_Search> assumes that the parsed command name can be found in
; argv[0] -- in other words, <Parseline> should be executed prior to
; <Path_Search>. Alternatively, the command name and appropriate
; information could be placed in argv[0], or <Path_Search> could be
; (easily) modified to make no assumptions about where its input is found.
; Please find enclosed yet another important routine, <Save_Args>, which
; places the entire arg/argv[]/argbuf structure on a piece of newly
; allocated memory. This is handy for for-loop processing, and anything
; else that wants to save the whole shebang and then process other command
; lines.
;
; Alan L, OS/MSDOS August 15, 1983
;
; ENTRY:
; <Path_Search>: argv[0].
; <Save_Args>: bytes to allocate in addition to arg structure
; EXIT:
; <Path_Search>: success flag, best pathname match in EXECPATH.
; <Save_Args>: success flag, segment address of new memory
; NOTE(S):
; * <Argv_calc> handily turns an array index into an absolute pointer.
; The computation depends on the size of an argv[] element (arg_ele).
; * <Parseline> calls <cparse> for chunks of the command line. <Cparse>
; does not function as specified; see <Parseline> for more details.
; * <Parseline> now knows about the flags the internals of COMMAND.COM
; need to know about. This extra information is stored in a switch_flag
; word with each command-line argument; the switches themselves will not
; appear in the resulting arg structure.
; * With the exception of CARRY, flags are generally preserved across calls.
;---------------
; CONSTANTS:
;---------------
DEBUGx equ FALSE ; prints out debug info
;---------------
; DATA:
;---------------
TRANDATA SEGMENT PUBLIC BYTE ;AC000;
EXTRN baddrv_ptr:word
TRANDATA ENDS
TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
EXTRN arg:byte
EXTRN BADPMES_ptr:word
EXTRN curdrv:byte
EXTRN EXECPATH:byte
EXTRN search_best_buf:byte
EXTRN search_error:word
EXTRN string_ptr_2:word
EXTRN tpbuf:byte
TRANSPACE ENDS
TRANCODE SEGMENT PUBLIC BYTE ;AC000;
assume cs:trangroup, ds:trangroup, es:trangroup, ss:nothing
break <Path_Search>
;------------------------------------------------------------------------------
; PATH_SEARCH tries to find the file it's given, somewhere. An initial value
; of *argv[0].argstartel == 0 implies that there is no command (empty line
; or 'd:' or 'd:/'). This check is done in strip; otherwise, strip formats
; the filename/pathname into tpbuf. Search(tpbuf) is executed to see if we
; have a match, either in the current working directory if we were handed
; a filename, or in the specified directory, given a pathname. If this call
; fails, and we were given a pathname, then Path_Search fails. Otherwise,
; Path_Crunch is repeatedly invoked on tpbuf[STARTEL] (if there's a drive
; prefix, we want to skip it) for each pathstring in userpath. Success on
; either the first invocation of search or on one of the succeeding calls
; sets up the appropriate information for copying the successful pathname
; prefix (if any) into the result buffer, followed by the successful filename
; match (from [search_best_buf]). The result is returned in in EXECPATH.
; ENTRY:
; argv[0] -- command name and associated information
; EXIT:
; AX -- non-zero indicates type of file found
; EXECPATH -- successful pathname (AX non-zero)
; NOTE(S):
; 1) Uses the temporary buffer, tpbuf, from the parse routines.
; 2) Some files are more equal than others. See search: for rankings.
; 3) Path_Search terminates as soon as a call to search succeeds, even
; if search returns an .exe or .bat.
; 5) Clobbers dma address.
pbuflen equ EXECPATHLEN ; len EXECPATH - ntvdm extended
path_sep_char equ ';'
TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
EXTRN fbuf:byte
EXTRN pathinfo:word
EXTRN psep_char:byte
TRANSPACE ENDS
Procedure Path_Search,NEAR
assume ds:trangroup, es:trangroup
push BX
push CX
push DX ; could use a "stack 'em" instruction
push SI
push DI
push BP
pushf
test DS:arg.argv[0].argflags, (MASK wildcard) + (MASK sw_flag)
jz path_search_ok
path_failure_jmp:
jmp path_failure ; ambiguous commands not allowed
path_search_ok:
call store_pchar ; figure out the pathname separator
mov DX, OFFSET TRANGROUP:fbuf ; clobber old dma value with
trap set_dma ; a pointer to our dma buffer
push ES
invoke find_path ; get a handle (ES:DI) on user path
mov DS:pathinfo[0], ES ; and squirrel it away
mov DS:pathinfo[2], DI ; "old" pathstring pointer
mov DS:pathinfo[4], DI ; "new" pathstring pointer
pop ES
mov BX, pbuflen ; copy/format argv[0] into temp buffer
mov SI, OFFSET TRANGROUP:EXECPATH
invoke strip
jc path_failure_jmp ; if possible, of course
mov DX, SI ; search(EXECPATH, error_message)
mov [search_error], OFFSET TRANGROUP:BADDRV_ptr
invoke search ; must do at least one search
or AX, AX ; find anything?
jz path_noinit ; failure ... search farther
mov BP, AX ; success... save filetype code
mov DI, OFFSET TRANGROUP:EXECPATH
mov SI, DS:arg.argv[0].argpointer
mov CX, DS:arg.argv[0].argstartel
sub CX, SI ; compute prefix bytes to copy
;
; We have the number of bytes in the prefix (up to the final component).
; We need to form the complete pathname including leading drive and current
; directory.
;
; Is there a drive letter present?
;
cmp word ptr [si], 05c5ch ; If a UNC name, copy straight in
je CopyPath
mov ah,':'
cmp cx,2 ; room for drive letter?
jb AddDrive ; no, stick it in
cmp [si+1],ah ; colon present?
jz MoveDrive ; yes, just move it
AddDrive:
mov al,curdrv ; get current drive
add al,"A" ; convert to uppercase letter
stosw ; store d:
jmp short CheckPath
MoveDrive:
lodsw ; move d:
stosw
sub cx,2 ; 2 bytes less to move
CheckPath:
or al,20h
mov dl,al
sub dl,"a"-1 ; convert to 1-based for current dir
;
; Stick in beginning path char
;
mov al,psep_char
stosb
;
; Is there a leading /? If so, then no current dir copy is necessary.
; Otherwise, get current dir for DL.
;
cmp cx,1 ; is there room for path char?
jb AddPath ; no, go add path
lodsb
dec cx
cmp al,psep_char ; is there a path separator?
jz MovePath ; yes, go move remainder of path
inc cx
dec si ; undo the lodsb
AddPath:
SaveReg <SI>
mov si,di ; remainder of buffer
trap Current_dir
;
; The previous current dir will succeed a previous find_first already worked.
;
; Find end of string.
;
mov di,si
RestoreReg <SI>
mov al,psep_char
cmp byte ptr [di],0 ; root (empty dir string)?
jz MovePath ; yes, no need for path char
ScanEnd:
cmp byte ptr [dI],0 ; end of string?
jz FoundEnd
inc di
jmp ScanEnd
;
; Stick in a trailing path char
;
FoundEnd:
stosb
;
; Move remaining part of path. Skip leading path char if present.
;
MovePath:
cmp [si],al ; first char a path char?
jnz CopyPath
inc si ; move past leading char
dec cx ; drop from count
CopyPath:
jcxz CopyDone ; no chars to move!
rep movsb
CopyDone:
jmp path_success ; run off and form complete pathname
path_noinit:
test DS:arg.argv[0].argflags, MASK path_sep
jnz path_failure ; complete pathname specified ==> fail
mov BH, path_sep_char ; semicolon terminates pathstring
mov DX, DS:arg.argv[0].argstartel ; this is where the last element starts
sub DX, DS:arg.argv[0].argpointer ; form pointer into EXECPATH,
add DX, OFFSET TRANGROUP:EXECPATH ; skipping over drive spec, if any
path_loop:
call path_crunch ; pcrunch(EXECPATH, pathinfo)
mov BP, AX ; save filetype code
lahf ; save flags, just in case
or BP, BP ; did path_crunch find anything?
jne path_found
sahf ; see? needed those flags, after all!
jnc path_loop ; is there anything left to the path?
path_failure:
xor AX, AX
;; jmp short path_exit ; 3/3/KK
jmp path_exit ;AC000; 3/3/KK
path_found: ; pathinfo[] points to winner
mov DI, OFFSET TRANGROUP:EXECPATH
mov CX, pathinfo[4] ; "new" pointer -- end of string
mov SI, pathinfo[2] ; "old" pointer -- beginning of string
;
; BAS Nov 20/84
; Look at the pathname and expand . and .. if they are the first element
; in the pathname (after the drive letter)
;
push ES
push pathinfo[0]
pop ES
;SR;
; Oops! Gets fooled if path= \;..
; We should also check if a drive letter is really present
;
cmp Byte Ptr ES:[SI+2],'.' ; Look for Current dir at start of path
jnz path_cpy
cmp byte ptr es:[si+1],':' ;does path have drive letter?
jnz path_cpy ;no, copy the path string
push CX ; Save pointer to end of string
mov AL, ES:[SI]
mov [DI],AL ; Copy drive letter, :, and root char
mov AL, ES:[SI+1] ; to EXECPATH
mov [DI+1],AL
mov AL,psep_char
mov [DI+2],AL
push SI ; Save pointer to begining of string
mov DL,ES:[SI] ; Convert device letter for cur dir
or DL,20h
sub DL,"a"-1
mov SI,DI ; pointer to EXECPATH
add SI, 3 ; Don't wipe out drive and root info
trap Current_dir
invoke DStrlen ; Determine length of present info
add SI,CX ; Don't copy over drive and root info
dec SI
mov DI,SI ; Point to end of target string
pop SI ; Restore pointer to begining of string
add SI, 3 ; Point past drive letter, :, .
pop CX ; Restore pointer to end of string
path_cpy:
pop ES
sub CX, SI ; yields character count
push DS ; time to switch segments
push pathinfo[0] ; string lives in this segment
pop DS
cld
;; rep movsb 3/3/KK ; copy the prefix path into EXECPATH
Kloop: ;AN000; 3/3/KK
lodsb ;AN000; 3/3/KK
stosb ;AN000; 3/3/KK
invoke testkanj ;AN000; 3/3/KK
jz NotKanj1 ;AN000; 3/3/KK
dec cx ;AN000; 3/3/KK
JCXZ PopDone ;AN000; Ignore boundary error 3/3/KK
movsb ;AN000; 3/3/KK
dec cx ;AN000; 3/3/KK
cmp cx,1 ;AN000; One char (the terminator) left ? 3/3/KK
ja Kloop ;AN000; no. 3/3/KK
PopDone: ;AN000; 3/3/KK
POP DS ;AN000; Yes ES:DI->terminator, last char is 3/3/KK
mov AL, psep_char ;AN000; KANJI 3/3/KK
jmp Short path_store ;AN000; 3/3/KK
NotKanj1:
loop Kloop
pop DS ; return to our segment
dec DI ; overwrite terminator
mov AL, psep_char ; with a pathname separator
cmp al,byte ptr [di-1]
jz path_success
path_store: ;AN000; 3/3/KK
stosb
path_success:
mov SI, OFFSET TRANGROUP:search_best_buf
xor CX, CX
path_succ_loop:
lodsb ; append winning filename to path
stosb ; (including terminating null)
or al,al
jnz path_succ_loop
mov AX, BP ; retrieve filetype code
path_exit:
popf
pop BP
pop DI
pop SI ; chill out...
pop DX
pop CX
pop BX
ret
EndProc Path_Search
break <Store_Pchar>
;----------------------------------------------------------------------------
; STORE_PCHAR determines the pathname-element separator and squirrels
; it away. In other words, must we say '/bin/ls' or '\bin\ls'?
; ENTRY:
; EXIT:
; NOTE(S):
; * Uses <psep_char>, defined in <path_search>.
;---------------
;---------------
Procedure Store_PChar,NEAR
;---------------
assume ds:trangroup, es:trangroup
push AX
mov AL, '/' ; is the pathname-element separator
invoke pathchrcmp ; a regular slash?
jz store_slash ; if yes, remember slash
mov al,'\'
mov [psep_char], al ; otherwise, remember back-slash
pop ax
ret
store_slash:
mov [psep_char], al
pop ax
return
;---------------
EndProc Store_Pchar
;----------------------------------------------------------------------------
break <Path_Crunch>
;----------------------------------------------------------------------------
; PATH_CRUNCH takes a prefix from a prefix string, and a suffix from
; EXECPATH, and smooshes them into tpbuf. The caller may supply an
; additional separator to use for breaking up the path-string. Null is the
; default. Once the user-string has been formed, search is invoked to see
; what's out there.
; ENTRY:
; BH -- additional terminator character
; SI -- pointer into pathstring to be dissected
; DX -- pointer to stripped filename
; EXIT:
; AX -- non-zero (file type), zero (nothing found)
; SI -- moves along pathstring from call to call
; [search_best_buf] -- name of best file (AX non-zero)
; [tpbuf] -- clobbered
; NOTE(S):
; * Implicit in this code is the ability to specify when to search
; the current directory (if at all) through the PATH defined by
; the user, a la UNIX (e.g., PATH=;c:\bin;c:\etc searches the
; current directory before the bin and etc directories of drive c).
;---------------
Procedure Path_Crunch,NEAR
;---------------
assume ds:trangroup, es:trangroup
push BX
push CX
push DX
push DI
push SI
pushf
call store_pchar ; figure out pathname separator
mov DI, OFFSET TRANGROUP:tpbuf ; destination of concatenated string
mov SI, pathinfo[4] ; "new" pointer to start with
mov pathinfo[2], SI ; becomes "old" pointer
push DS ; save old segment pointer
push pathinfo[0] ; replace with pointer to userpath's
pop DS ; segment
xor cl,cl ;AN000; clear flag for later use 3/3/KK
path_cr_copy:
lodsb ; get a pathname byte
or al,al ; check for terminator(s)
jz path_seg ; null terminates segment & pathstring
cmp AL, BH
jz path_seg ; BH terminates a pathstring segment
invoke testkanj ;AN000; 3/3/KK
jz NotKanj2 ;AN000; 3/3/KK
stosb ;AN000; 3/3/KK
movsb ;AN000; 3/3/KK
MOV CL,1 ;AN000; CL=1 means latest stored char is DBCS 3/3/KK
jmp path_cr_copy ;AN000; 3/3/KK
NotKanj2: ;AN000; 3/3/KK
xor cl,cl ;AN000; CL=0 means latest stored char is SBCS 3/3/KK
stosb ; save byte in concat buffer
jmp path_cr_copy ; loop until we see a terminator
path_seg:
pop DS ; restore old data segment
mov pathinfo[4], SI ; save "new" pointer for next time
mov BL, AL ; remember if we saw null or not...
;;; REMOVE NEXT 3 LINES FOR CURDIR SPEC
xor AX, AX ; in case nothing in pathstr...
cmp DI, OFFSET TRANGROUP:tpbuf ; was there really anything in pathstr?
je path_cr_leave ; if nothing was copied, pathstr empty
path_cr_look: ; form complete pathname
mov al, psep_char ; add pathname separator for suffix
or cl,cl ;AN000; 3/3/KK
jnz path_cr_store ;AN000; this is a trailing byte of ECS code 3/3/KK
cmp al,byte ptr [di-1]
jz path_cr_l1
path_cr_store: ;AN000; 3/3/KK
stosb
path_cr_l1:
mov SI, DX
path_cr_l2:
lodsb ; tack the stripped filename onto
stosb ; the end of the path, up to and
or AL, AL ; including the terminating null
jnz path_cr_l2
mov DX, OFFSET TRANGROUP:tpbuf ; and look for an appropriate file...
mov [search_error], OFFSET TRANGROUP:BADPMES_ptr
invoke search ; results are in AX & search_best_buf
path_cr_leave:
or BL, BL ; did we finish off the pathstring?
jz path_cr_empty ; null in BL means all gone...
popf ; otherwise, plenty left
clc
jmp short path_cr_exit
path_cr_empty:
popf
stc
path_cr_exit:
pop SI
pop DI
pop DX
pop CX
pop BX
ret
;---------------
EndProc Path_Crunch
;----------------------------------------------------------------------------
trancode ends
END