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

  1. page ,132
  2. ;/*
  3. ; * Microsoft Confidential
  4. ; * Copyright (C) Microsoft Corporation 1991
  5. ; * All Rights Reserved.
  6. ; */
  7. ; SCCSID = @(#)path1.asm 1.1 85/05/14
  8. ; SCCSID = @(#)path1.asm 1.1 85/05/14
  9. .sall
  10. .xlist
  11. .xcref
  12. include dossym.inc
  13. include syscall.inc
  14. include comsw.asm
  15. include comseg.asm
  16. include comequ.asm
  17. .list
  18. .cref
  19. break <Path.Asm>
  20. ;----------------------------------------------------------------------------
  21. ; PATH.ASM contains the routines to perform pathname incovation. Path and
  22. ; Parse share a temporary buffer and argv[] definitions. <Path_Search>,
  23. ; given a pathname, attempts to find a corresponding executable or batch
  24. ; file on disk. Directories specified in the user's search path will be
  25. ; searched for a matching file, if a match is not found in the current
  26. ; directory and if the pathname is actually only an MSDOS filename.
  27. ; <Path_Search> assumes that the parsed command name can be found in
  28. ; argv[0] -- in other words, <Parseline> should be executed prior to
  29. ; <Path_Search>. Alternatively, the command name and appropriate
  30. ; information could be placed in argv[0], or <Path_Search> could be
  31. ; (easily) modified to make no assumptions about where its input is found.
  32. ; Please find enclosed yet another important routine, <Save_Args>, which
  33. ; places the entire arg/argv[]/argbuf structure on a piece of newly
  34. ; allocated memory. This is handy for for-loop processing, and anything
  35. ; else that wants to save the whole shebang and then process other command
  36. ; lines.
  37. ;
  38. ; Alan L, OS/MSDOS August 15, 1983
  39. ;
  40. ; ENTRY:
  41. ; <Path_Search>: argv[0].
  42. ; <Save_Args>: bytes to allocate in addition to arg structure
  43. ; EXIT:
  44. ; <Path_Search>: success flag, best pathname match in EXECPATH.
  45. ; <Save_Args>: success flag, segment address of new memory
  46. ; NOTE(S):
  47. ; * <Argv_calc> handily turns an array index into an absolute pointer.
  48. ; The computation depends on the size of an argv[] element (arg_ele).
  49. ; * <Parseline> calls <cparse> for chunks of the command line. <Cparse>
  50. ; does not function as specified; see <Parseline> for more details.
  51. ; * <Parseline> now knows about the flags the internals of COMMAND.COM
  52. ; need to know about. This extra information is stored in a switch_flag
  53. ; word with each command-line argument; the switches themselves will not
  54. ; appear in the resulting arg structure.
  55. ; * With the exception of CARRY, flags are generally preserved across calls.
  56. ;---------------
  57. ; CONSTANTS:
  58. ;---------------
  59. DEBUGx equ FALSE ; prints out debug info
  60. ;---------------
  61. ; DATA:
  62. ;---------------
  63. TRANDATA SEGMENT PUBLIC BYTE ;AC000;
  64. EXTRN baddrv_ptr:word
  65. TRANDATA ENDS
  66. TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
  67. EXTRN arg:byte
  68. EXTRN BADPMES_ptr:word
  69. EXTRN curdrv:byte
  70. EXTRN EXECPATH:byte
  71. EXTRN search_best_buf:byte
  72. EXTRN search_error:word
  73. EXTRN string_ptr_2:word
  74. EXTRN tpbuf:byte
  75. TRANSPACE ENDS
  76. TRANCODE SEGMENT PUBLIC BYTE ;AC000;
  77. assume cs:trangroup, ds:trangroup, es:trangroup, ss:nothing
  78. break <Path_Search>
  79. ;------------------------------------------------------------------------------
  80. ; PATH_SEARCH tries to find the file it's given, somewhere. An initial value
  81. ; of *argv[0].argstartel == 0 implies that there is no command (empty line
  82. ; or 'd:' or 'd:/'). This check is done in strip; otherwise, strip formats
  83. ; the filename/pathname into tpbuf. Search(tpbuf) is executed to see if we
  84. ; have a match, either in the current working directory if we were handed
  85. ; a filename, or in the specified directory, given a pathname. If this call
  86. ; fails, and we were given a pathname, then Path_Search fails. Otherwise,
  87. ; Path_Crunch is repeatedly invoked on tpbuf[STARTEL] (if there's a drive
  88. ; prefix, we want to skip it) for each pathstring in userpath. Success on
  89. ; either the first invocation of search or on one of the succeeding calls
  90. ; sets up the appropriate information for copying the successful pathname
  91. ; prefix (if any) into the result buffer, followed by the successful filename
  92. ; match (from [search_best_buf]). The result is returned in in EXECPATH.
  93. ; ENTRY:
  94. ; argv[0] -- command name and associated information
  95. ; EXIT:
  96. ; AX -- non-zero indicates type of file found
  97. ; EXECPATH -- successful pathname (AX non-zero)
  98. ; NOTE(S):
  99. ; 1) Uses the temporary buffer, tpbuf, from the parse routines.
  100. ; 2) Some files are more equal than others. See search: for rankings.
  101. ; 3) Path_Search terminates as soon as a call to search succeeds, even
  102. ; if search returns an .exe or .bat.
  103. ; 5) Clobbers dma address.
  104. pbuflen equ EXECPATHLEN ; len EXECPATH - ntvdm extended
  105. path_sep_char equ ';'
  106. TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
  107. EXTRN fbuf:byte
  108. EXTRN pathinfo:word
  109. EXTRN psep_char:byte
  110. TRANSPACE ENDS
  111. Procedure Path_Search,NEAR
  112. assume ds:trangroup, es:trangroup
  113. push BX
  114. push CX
  115. push DX ; could use a "stack 'em" instruction
  116. push SI
  117. push DI
  118. push BP
  119. pushf
  120. test DS:arg.argv[0].argflags, (MASK wildcard) + (MASK sw_flag)
  121. jz path_search_ok
  122. path_failure_jmp:
  123. jmp path_failure ; ambiguous commands not allowed
  124. path_search_ok:
  125. call store_pchar ; figure out the pathname separator
  126. mov DX, OFFSET TRANGROUP:fbuf ; clobber old dma value with
  127. trap set_dma ; a pointer to our dma buffer
  128. push ES
  129. invoke find_path ; get a handle (ES:DI) on user path
  130. mov DS:pathinfo[0], ES ; and squirrel it away
  131. mov DS:pathinfo[2], DI ; "old" pathstring pointer
  132. mov DS:pathinfo[4], DI ; "new" pathstring pointer
  133. pop ES
  134. mov BX, pbuflen ; copy/format argv[0] into temp buffer
  135. mov SI, OFFSET TRANGROUP:EXECPATH
  136. invoke strip
  137. jc path_failure_jmp ; if possible, of course
  138. mov DX, SI ; search(EXECPATH, error_message)
  139. mov [search_error], OFFSET TRANGROUP:BADDRV_ptr
  140. invoke search ; must do at least one search
  141. or AX, AX ; find anything?
  142. jz path_noinit ; failure ... search farther
  143. mov BP, AX ; success... save filetype code
  144. mov DI, OFFSET TRANGROUP:EXECPATH
  145. mov SI, DS:arg.argv[0].argpointer
  146. mov CX, DS:arg.argv[0].argstartel
  147. sub CX, SI ; compute prefix bytes to copy
  148. ;
  149. ; We have the number of bytes in the prefix (up to the final component).
  150. ; We need to form the complete pathname including leading drive and current
  151. ; directory.
  152. ;
  153. ; Is there a drive letter present?
  154. ;
  155. cmp word ptr [si], 05c5ch ; If a UNC name, copy straight in
  156. je CopyPath
  157. mov ah,':'
  158. cmp cx,2 ; room for drive letter?
  159. jb AddDrive ; no, stick it in
  160. cmp [si+1],ah ; colon present?
  161. jz MoveDrive ; yes, just move it
  162. AddDrive:
  163. mov al,curdrv ; get current drive
  164. add al,"A" ; convert to uppercase letter
  165. stosw ; store d:
  166. jmp short CheckPath
  167. MoveDrive:
  168. lodsw ; move d:
  169. stosw
  170. sub cx,2 ; 2 bytes less to move
  171. CheckPath:
  172. or al,20h
  173. mov dl,al
  174. sub dl,"a"-1 ; convert to 1-based for current dir
  175. ;
  176. ; Stick in beginning path char
  177. ;
  178. mov al,psep_char
  179. stosb
  180. ;
  181. ; Is there a leading /? If so, then no current dir copy is necessary.
  182. ; Otherwise, get current dir for DL.
  183. ;
  184. cmp cx,1 ; is there room for path char?
  185. jb AddPath ; no, go add path
  186. lodsb
  187. dec cx
  188. cmp al,psep_char ; is there a path separator?
  189. jz MovePath ; yes, go move remainder of path
  190. inc cx
  191. dec si ; undo the lodsb
  192. AddPath:
  193. SaveReg <SI>
  194. mov si,di ; remainder of buffer
  195. trap Current_dir
  196. ;
  197. ; The previous current dir will succeed a previous find_first already worked.
  198. ;
  199. ; Find end of string.
  200. ;
  201. mov di,si
  202. RestoreReg <SI>
  203. mov al,psep_char
  204. cmp byte ptr [di],0 ; root (empty dir string)?
  205. jz MovePath ; yes, no need for path char
  206. ScanEnd:
  207. cmp byte ptr [dI],0 ; end of string?
  208. jz FoundEnd
  209. inc di
  210. jmp ScanEnd
  211. ;
  212. ; Stick in a trailing path char
  213. ;
  214. FoundEnd:
  215. stosb
  216. ;
  217. ; Move remaining part of path. Skip leading path char if present.
  218. ;
  219. MovePath:
  220. cmp [si],al ; first char a path char?
  221. jnz CopyPath
  222. inc si ; move past leading char
  223. dec cx ; drop from count
  224. CopyPath:
  225. jcxz CopyDone ; no chars to move!
  226. rep movsb
  227. CopyDone:
  228. jmp path_success ; run off and form complete pathname
  229. path_noinit:
  230. test DS:arg.argv[0].argflags, MASK path_sep
  231. jnz path_failure ; complete pathname specified ==> fail
  232. mov BH, path_sep_char ; semicolon terminates pathstring
  233. mov DX, DS:arg.argv[0].argstartel ; this is where the last element starts
  234. sub DX, DS:arg.argv[0].argpointer ; form pointer into EXECPATH,
  235. add DX, OFFSET TRANGROUP:EXECPATH ; skipping over drive spec, if any
  236. path_loop:
  237. call path_crunch ; pcrunch(EXECPATH, pathinfo)
  238. mov BP, AX ; save filetype code
  239. lahf ; save flags, just in case
  240. or BP, BP ; did path_crunch find anything?
  241. jne path_found
  242. sahf ; see? needed those flags, after all!
  243. jnc path_loop ; is there anything left to the path?
  244. path_failure:
  245. xor AX, AX
  246. ;; jmp short path_exit ; 3/3/KK
  247. jmp path_exit ;AC000; 3/3/KK
  248. path_found: ; pathinfo[] points to winner
  249. mov DI, OFFSET TRANGROUP:EXECPATH
  250. mov CX, pathinfo[4] ; "new" pointer -- end of string
  251. mov SI, pathinfo[2] ; "old" pointer -- beginning of string
  252. ;
  253. ; BAS Nov 20/84
  254. ; Look at the pathname and expand . and .. if they are the first element
  255. ; in the pathname (after the drive letter)
  256. ;
  257. push ES
  258. push pathinfo[0]
  259. pop ES
  260. ;SR;
  261. ; Oops! Gets fooled if path= \;..
  262. ; We should also check if a drive letter is really present
  263. ;
  264. cmp Byte Ptr ES:[SI+2],'.' ; Look for Current dir at start of path
  265. jnz path_cpy
  266. cmp byte ptr es:[si+1],':' ;does path have drive letter?
  267. jnz path_cpy ;no, copy the path string
  268. push CX ; Save pointer to end of string
  269. mov AL, ES:[SI]
  270. mov [DI],AL ; Copy drive letter, :, and root char
  271. mov AL, ES:[SI+1] ; to EXECPATH
  272. mov [DI+1],AL
  273. mov AL,psep_char
  274. mov [DI+2],AL
  275. push SI ; Save pointer to begining of string
  276. mov DL,ES:[SI] ; Convert device letter for cur dir
  277. or DL,20h
  278. sub DL,"a"-1
  279. mov SI,DI ; pointer to EXECPATH
  280. add SI, 3 ; Don't wipe out drive and root info
  281. trap Current_dir
  282. invoke DStrlen ; Determine length of present info
  283. add SI,CX ; Don't copy over drive and root info
  284. dec SI
  285. mov DI,SI ; Point to end of target string
  286. pop SI ; Restore pointer to begining of string
  287. add SI, 3 ; Point past drive letter, :, .
  288. pop CX ; Restore pointer to end of string
  289. path_cpy:
  290. pop ES
  291. sub CX, SI ; yields character count
  292. push DS ; time to switch segments
  293. push pathinfo[0] ; string lives in this segment
  294. pop DS
  295. cld
  296. ;; rep movsb 3/3/KK ; copy the prefix path into EXECPATH
  297. Kloop: ;AN000; 3/3/KK
  298. lodsb ;AN000; 3/3/KK
  299. stosb ;AN000; 3/3/KK
  300. invoke testkanj ;AN000; 3/3/KK
  301. jz NotKanj1 ;AN000; 3/3/KK
  302. dec cx ;AN000; 3/3/KK
  303. JCXZ PopDone ;AN000; Ignore boundary error 3/3/KK
  304. movsb ;AN000; 3/3/KK
  305. dec cx ;AN000; 3/3/KK
  306. cmp cx,1 ;AN000; One char (the terminator) left ? 3/3/KK
  307. ja Kloop ;AN000; no. 3/3/KK
  308. PopDone: ;AN000; 3/3/KK
  309. POP DS ;AN000; Yes ES:DI->terminator, last char is 3/3/KK
  310. mov AL, psep_char ;AN000; KANJI 3/3/KK
  311. jmp Short path_store ;AN000; 3/3/KK
  312. NotKanj1:
  313. loop Kloop
  314. pop DS ; return to our segment
  315. dec DI ; overwrite terminator
  316. mov AL, psep_char ; with a pathname separator
  317. cmp al,byte ptr [di-1]
  318. jz path_success
  319. path_store: ;AN000; 3/3/KK
  320. stosb
  321. path_success:
  322. mov SI, OFFSET TRANGROUP:search_best_buf
  323. xor CX, CX
  324. path_succ_loop:
  325. lodsb ; append winning filename to path
  326. stosb ; (including terminating null)
  327. or al,al
  328. jnz path_succ_loop
  329. mov AX, BP ; retrieve filetype code
  330. path_exit:
  331. popf
  332. pop BP
  333. pop DI
  334. pop SI ; chill out...
  335. pop DX
  336. pop CX
  337. pop BX
  338. ret
  339. EndProc Path_Search
  340. break <Store_Pchar>
  341. ;----------------------------------------------------------------------------
  342. ; STORE_PCHAR determines the pathname-element separator and squirrels
  343. ; it away. In other words, must we say '/bin/ls' or '\bin\ls'?
  344. ; ENTRY:
  345. ; EXIT:
  346. ; NOTE(S):
  347. ; * Uses <psep_char>, defined in <path_search>.
  348. ;---------------
  349. ;---------------
  350. Procedure Store_PChar,NEAR
  351. ;---------------
  352. assume ds:trangroup, es:trangroup
  353. push AX
  354. mov AL, '/' ; is the pathname-element separator
  355. invoke pathchrcmp ; a regular slash?
  356. jz store_slash ; if yes, remember slash
  357. mov al,'\'
  358. mov [psep_char], al ; otherwise, remember back-slash
  359. pop ax
  360. ret
  361. store_slash:
  362. mov [psep_char], al
  363. pop ax
  364. return
  365. ;---------------
  366. EndProc Store_Pchar
  367. ;----------------------------------------------------------------------------
  368. break <Path_Crunch>
  369. ;----------------------------------------------------------------------------
  370. ; PATH_CRUNCH takes a prefix from a prefix string, and a suffix from
  371. ; EXECPATH, and smooshes them into tpbuf. The caller may supply an
  372. ; additional separator to use for breaking up the path-string. Null is the
  373. ; default. Once the user-string has been formed, search is invoked to see
  374. ; what's out there.
  375. ; ENTRY:
  376. ; BH -- additional terminator character
  377. ; SI -- pointer into pathstring to be dissected
  378. ; DX -- pointer to stripped filename
  379. ; EXIT:
  380. ; AX -- non-zero (file type), zero (nothing found)
  381. ; SI -- moves along pathstring from call to call
  382. ; [search_best_buf] -- name of best file (AX non-zero)
  383. ; [tpbuf] -- clobbered
  384. ; NOTE(S):
  385. ; * Implicit in this code is the ability to specify when to search
  386. ; the current directory (if at all) through the PATH defined by
  387. ; the user, a la UNIX (e.g., PATH=;c:\bin;c:\etc searches the
  388. ; current directory before the bin and etc directories of drive c).
  389. ;---------------
  390. Procedure Path_Crunch,NEAR
  391. ;---------------
  392. assume ds:trangroup, es:trangroup
  393. push BX
  394. push CX
  395. push DX
  396. push DI
  397. push SI
  398. pushf
  399. call store_pchar ; figure out pathname separator
  400. mov DI, OFFSET TRANGROUP:tpbuf ; destination of concatenated string
  401. mov SI, pathinfo[4] ; "new" pointer to start with
  402. mov pathinfo[2], SI ; becomes "old" pointer
  403. push DS ; save old segment pointer
  404. push pathinfo[0] ; replace with pointer to userpath's
  405. pop DS ; segment
  406. xor cl,cl ;AN000; clear flag for later use 3/3/KK
  407. path_cr_copy:
  408. lodsb ; get a pathname byte
  409. or al,al ; check for terminator(s)
  410. jz path_seg ; null terminates segment & pathstring
  411. cmp AL, BH
  412. jz path_seg ; BH terminates a pathstring segment
  413. invoke testkanj ;AN000; 3/3/KK
  414. jz NotKanj2 ;AN000; 3/3/KK
  415. stosb ;AN000; 3/3/KK
  416. movsb ;AN000; 3/3/KK
  417. MOV CL,1 ;AN000; CL=1 means latest stored char is DBCS 3/3/KK
  418. jmp path_cr_copy ;AN000; 3/3/KK
  419. NotKanj2: ;AN000; 3/3/KK
  420. xor cl,cl ;AN000; CL=0 means latest stored char is SBCS 3/3/KK
  421. stosb ; save byte in concat buffer
  422. jmp path_cr_copy ; loop until we see a terminator
  423. path_seg:
  424. pop DS ; restore old data segment
  425. mov pathinfo[4], SI ; save "new" pointer for next time
  426. mov BL, AL ; remember if we saw null or not...
  427. ;;; REMOVE NEXT 3 LINES FOR CURDIR SPEC
  428. xor AX, AX ; in case nothing in pathstr...
  429. cmp DI, OFFSET TRANGROUP:tpbuf ; was there really anything in pathstr?
  430. je path_cr_leave ; if nothing was copied, pathstr empty
  431. path_cr_look: ; form complete pathname
  432. mov al, psep_char ; add pathname separator for suffix
  433. or cl,cl ;AN000; 3/3/KK
  434. jnz path_cr_store ;AN000; this is a trailing byte of ECS code 3/3/KK
  435. cmp al,byte ptr [di-1]
  436. jz path_cr_l1
  437. path_cr_store: ;AN000; 3/3/KK
  438. stosb
  439. path_cr_l1:
  440. mov SI, DX
  441. path_cr_l2:
  442. lodsb ; tack the stripped filename onto
  443. stosb ; the end of the path, up to and
  444. or AL, AL ; including the terminating null
  445. jnz path_cr_l2
  446. mov DX, OFFSET TRANGROUP:tpbuf ; and look for an appropriate file...
  447. mov [search_error], OFFSET TRANGROUP:BADPMES_ptr
  448. invoke search ; results are in AX & search_best_buf
  449. path_cr_leave:
  450. or BL, BL ; did we finish off the pathstring?
  451. jz path_cr_empty ; null in BL means all gone...
  452. popf ; otherwise, plenty left
  453. clc
  454. jmp short path_cr_exit
  455. path_cr_empty:
  456. popf
  457. stc
  458. path_cr_exit:
  459. pop SI
  460. pop DI
  461. pop DX
  462. pop CX
  463. pop BX
  464. ret
  465. ;---------------
  466. EndProc Path_Crunch
  467. ;----------------------------------------------------------------------------
  468. trancode ends
  469. END
  470.