UTILS.FDO
上传用户:xiaogehua
上传日期:2007-01-08
资源大小:1183k
文件大小:68k
源码类别:

操作系统开发

开发平台:

Asm

  1. ;    File              : $UTILS.FDO$
  2. ;
  3. ;    Description       :
  4. ;
  5. ;    Original Author   : DIGITAL RESEARCH
  6. ;
  7. ;    Last Edited By    : $CALDERA$
  8. ;
  9. ;-----------------------------------------------------------------------;
  10. ;    Copyright Work of Caldera, Inc. All Rights Reserved.
  11. ;      
  12. ;    THIS WORK IS A COPYRIGHT WORK AND CONTAINS CONFIDENTIAL,
  13. ;    PROPRIETARY AND TRADE SECRET INFORMATION OF CALDERA, INC.
  14. ;    ACCESS TO THIS WORK IS RESTRICTED TO (I) CALDERA, INC. EMPLOYEES
  15. ;    WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF
  16. ;    THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN CALDERA, INC. WHO
  17. ;    HAVE ACCEPTED THE CALDERA OPENDOS SOURCE LICENSE OR OTHER CALDERA LICENSE
  18. ;    AGREEMENTS. EXCEPT UNDER THE EXPRESS TERMS OF THE CALDERA LICENSE
  19. ;    AGREEMENT NO PART OF THIS WORK MAY BE USED, PRACTICED, PERFORMED,
  20. ;    COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED,
  21. ;    CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST,
  22. ;    TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF
  23. ;    CALDERA, INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT
  24. ;    AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO CRIMINAL AND
  25. ;    CIVIL LIABILITY.
  26. ;-----------------------------------------------------------------------;
  27. ;
  28. ;    *** Current Edit History ***
  29. ;    *** End of Current Edit History ***
  30. ;
  31. ;    $Log$
  32. ;    UTILS.FDO 1.39 94/11/30 13:39:18 
  33. ;    added share_delay function   
  34. ;    UTILS.FDO 1.37 94/07/13 15:42:01
  35. ;    Change to rename/delete of file open in compatibility modes
  36. ;    UTILS.FDO 1.36 94/06/28 11:10:10
  37. ;    Limit ddsc allocation to 1st 255
  38. ;    UTILS.FDO 1.34 94/04/25 19:33:04
  39. ;    Reject blank names (ie. all spaces) when parsing path
  40. ;    We used to die in rebuild_ldt_curdir (GATEWAY problem)
  41. ;    UTILS.FDO 1.33 93/12/16 13:57:06 
  42. ;    Fix path_prep bug when dir in path doesn't exist
  43. ;    UTILS.FDO 1.32 93/12/09 23:56:10 
  44. ;    Move non-inherited bit to correct place in file handle
  45. ;    UTILS.FDO 1.31 93/12/08 03:30:03 
  46. ;    Add extra check to offer_join: consider JOIN B: FRED, SUBST L: FREDFRED
  47. ;    A CD L: would see FRED at the root of B: and change into it, so we
  48. ;    would end up at FRED, so we only check if ROOTLEN=2
  49. ;    UTILS.FDO 1.27 93/11/19 17:45:14
  50. ;    Fix for SERVER print queue viewing problem
  51. ;    UTILS.FDO 1.26 93/11/08 16:30:12
  52. ;    Get dat/time on device handle returns current date/time
  53. ;    UTILS.FDO 1.25 93/09/14 20:03:42
  54. ;    Trust LFLG_PHYSICAL
  55. ;    UTILS.FDO 1.23 93/09/03 20:26:09
  56. ;    Add "no critical errors" support (int 21/6C)
  57. ;    UTILS.FDO 1.22 93/07/26 18:11:00
  58. ;    re-arrange DHNDL_DCNTHI for the benefit of Geoworks
  59. ;    UTILS.FDO 1.21 93/07/20 22:43:48
  60. ;    Even fewer checks on int 25/26 
  61. ;    ENDLOG
  62. ; General utility include module for FDOS.A86
  63. select_pb2:
  64. ;----------
  65. call get_pb2_drive ; get drive from parameter block
  66. ; jmp select_unique ; select drive, make HDS unique
  67. select_unique:
  68. ;-------------
  69. ; entry: AL = drive to select (0-15)
  70. mov byte ptr path_drive,al ; save logical drive
  71. jmp select_logical_drv ; select the drive
  72. logical2physical:
  73. ;----------------
  74. ; On Entry:
  75. ; AL = drive to select
  76. ; On Exit:
  77. ; AL = appropriate physical drive to select
  78. ;
  79. ; This routine is called by low level routines (func_ddio, func_getdpb)
  80. ; and bypasses the checks for networked/joined drives together with the
  81. ; normal media change checks. It does however handle SUBST'd drives.
  82. ;
  83. call get_ldt_raw ; ES:BX -> LDT for our drive
  84.  jc logical2physical10 ; if we don't have one must be physical
  85. test es:LDT_FLAGS[bx],LFLG_JOINED
  86.  jnz logical2physical10 ; joined drive - treat as physical
  87. test es:LDT_FLAGS[bx],LFLG_SUBST
  88.  jz logical2physical10 ; as long as we aren't SUBST'd it OK
  89. mov al,es:LDT_NAME[bx] ; get the drive from the ascii name
  90. and al,1fh ;  as the drive may require rebuilding
  91. dec ax ; make it zero based
  92. logical2physical10:
  93. ret
  94. Public dbcs_lead
  95. dbcs_lead:
  96. ;---------
  97. ; Return true if given byte is the first of a double byte character.
  98. ; Entry
  99. ; al  = byte to be tested
  100. ; Exit
  101. ; Z Flag = 1 - byte is a DBCS lead
  102. ;   0 - byte is not a DBCS lead
  103. ; Lost
  104. ; no registers changed
  105. if KANJI
  106. push si
  107. push bx
  108. push ax
  109. ; First get a pointer to the double byte lead table in the COUNTRY info.
  110. mov si, offset DBCS_tbl+2 ; ds:si -> double byte table
  111. ; Examine each entry in the table to see if it defines a range that includes
  112. ; the given character.
  113. mov bl, al ; bl = byte to be tested
  114. dbcs_loop:
  115. lods ss:ax ; al/ah = start/end of range
  116. test  ax, ax ; end of table?
  117.  jz dbcs_no ;  yes - exit (not in table)
  118. cmp al, bl ; start <= bl?
  119.  ja dbcs_loop ;  no - try next range
  120. cmp ah, bl ; bl <= end?
  121.  jb dbcs_loop ;  no - try next range
  122. cmp al, al ; return with Z flag set
  123. jmp dbcs_exit
  124. dbcs_no:
  125. cmp al, 1 ; return with Z flag reset
  126. dbcs_exit:
  127. pop ax
  128. pop bx
  129. pop si
  130. ret
  131. else
  132. test al, al ; force non-0 condition
  133. ret
  134. endif
  135. kanji_eos:
  136. ;---------
  137. ; entry: ES:DI -> string to find the end of
  138. ; exit: ES:DI -> character before NUL byte
  139. mov  dx,di ; in case string is empty
  140. kanji_eos1:
  141. mov al,es:[di] ; get next character
  142. test al,al ; is it the final NUL byte
  143.  jz kanji_eos9 ; return if NUL found
  144. mov dx,di
  145. inc di ; move to next character
  146. if KANJI
  147. call dbcs_lead ; is this first half of 16-bit char?
  148.  jne kanji_eos1 ; skip if normal character
  149. inc di ; else skip 2nd half (should really check)
  150. endif
  151. jmps kanji_eos1 ; loop back for next character
  152. kanji_eos9:
  153. mov di,dx ; ES:DI -> last character
  154. ret ; end of string found
  155. path_chop:
  156. ;---------
  157. ; entry: ES:DI -> path = "d:level1level2"
  158. ; exit:          path = "d:level1"
  159. mov al,es:[di] ; get next character
  160. test al,al ; end of string?
  161.  jz path_chop2 ; yes, string scanned
  162. inc di ; next character
  163. if KANJI
  164. call dbcs_lead ; lead-in of 16-bit character?
  165.  jne path_chop1 ; no, normal 8-bit
  166. inc di ; skip hi-byte (should really check)
  167. jmps path_chop ; try again
  168. path_chop1:
  169. endif
  170. call check_slash ; is this a path character
  171.  jne path_chop ; loop back if not path character
  172. mov dx,cx ; last but one '/' = last '/'
  173. mov cx,di ; last '/' = current '/'
  174. jmps path_chop ; repeat
  175. path_chop2:
  176. mov di,dx ; ES:DI -> last but one slash + 1
  177. sub ax,ax ; get a NUL byte
  178. stosb ; chop off the last level
  179. ret
  180. Public rebuild_ldt_root
  181. rebuild_ldt_root:
  182. ;----------------
  183. ; On Entry:
  184. ; ES:BX -> LDT_ to rebuild
  185. ; fdos_hds = physical root for this drive
  186. ; On Exit:
  187. ; ES:BX preserved
  188. ; LDT_ROOT rebuilt from ASCII LDT_NAME
  189. ;
  190. push ds
  191. push es ! pop ds ; DS:BX -> LDT_
  192. push ss ! pop es
  193. mov di,offset temp_ldt ; ES:DI -> temp LDT_
  194. lea si,LDT_NAME+3[bx] ; point to start of pathname
  195. mov cx,LDT_ROOTLEN[bx] ; CX = end of root portion
  196. xor ax,ax ; assume we want root block
  197. sub cx,3 ; skip the 'D:'
  198.  jbe rebuild_ldt_root10 ; nothing to do unless SUBST'd
  199. rep movsb ; copy the root portion of the name
  200. call select_dir ; select this directory
  201.  jnc rebuild_ldt_root10
  202. xor ax,ax
  203. mov LDT_ROOTLEN[bx],2 ; force ourselves into the root
  204. mov LDT_NAME+3[bx],al ;  as the media has changed
  205. rebuild_ldt_root10:
  206. push ds ! pop es ; ES:BX -> LDT_
  207. pop ds
  208. mov ax,fdos_hds_blk
  209. mov es:LDT_ROOT[bx],ax ; update our root block
  210. if JOIN
  211. mov al,fdos_hds_drv ;  and the physical drive
  212. mov es:LDT_DRV[bx],al
  213. endif
  214. ret
  215. rebuild_ldt_curdir:
  216. ;------------------
  217. ; On Entry:
  218. ; ES:BX -> LDT_ to rebuild
  219. ; fdos_hds = logical root of this drive
  220. ; On Exit:
  221. ; ES:BX preserved
  222. ; LDT_DRV and LDT_BLK rebuilt from ASCII LDT_NAME
  223. ;
  224. push ds
  225. push es ! pop ds ; DS:BX -> LDT_
  226. push ss ! pop es
  227. mov di,offset temp_ldt ; ES:DI -> temp LDT_
  228. mov si,LDT_ROOTLEN[bx] ; SI = end of root portion
  229. lea si,LDT_NAME[bx+si] ; point to subdir entry
  230. lodsb ; get 1st char
  231. call check_slash ; is it a leading '' ?
  232.  je rebuild_ldt_curdir10 ; yes, discard it
  233. dec si ; else leave it alone
  234. rebuild_ldt_curdir10:
  235. test al,al ; anything to do?
  236.  jz rebuild_ldt_curdir40 ;  no, we are already there
  237. rebuild_ldt_curdir20:
  238. lodsb ! stosb ; copy the string
  239. test al,al ; until we hit the terminating NUL
  240.  jnz rebuild_ldt_curdir20
  241. dec di
  242. call select_dir ; select this directory
  243.  jnc rebuild_ldt_curdir40
  244. mov si,LDT_ROOTLEN[bx] ; SI = end of root portion
  245. cmp si,3 ; is root real root or a subdir ?
  246.  ja rebuild_ldt_curdir30
  247. mov si,3 ; real root, leave '' alone
  248. rebuild_ldt_curdir30:
  249. mov LDT_NAME[bx+si],0 ; move ASCII to root
  250. rebuild_ldt_curdir40:
  251. push ds ! pop es ; ES:BX -> LDT_
  252. pop ds
  253. mov ax,fdos_hds_blk
  254. mov es:LDT_BLK[bx],ax ; update our curdir block
  255. if JOIN
  256. mov al,fdos_hds_drv ;  and the physical drive
  257. mov es:LDT_DRV[bx],al
  258. endif
  259. ret
  260. select_dir:
  261. ;----------
  262. ; On Entry:
  263. ; DS:BX -> LDT
  264. ; ES:DI -> end of ASCII path
  265. ; temp_ldt contains dir to select
  266. ; On Exit:
  267. ; DS:BX preserved
  268. ; CY set on error, root of original drive reselected
  269. ;
  270. mov ax,'.' ; append a "." in case it's the root
  271. stosw ;  (and so a NULL path)
  272. xor ax,ax
  273. stosb
  274. push ds ! push bx ; make sure LDT survives
  275. push ss ! pop ds ; DS back to SYSDAT
  276. mov si,offset temp_ldt ; ES:SI -> directory to select
  277. call path_prep_next ;  try to move into it
  278. if JOIN
  279. call offer_join ; are we opening a JOIN'd drive ?
  280.  jnc select_dir20
  281. endif
  282. call finddfcbf ; find the directory entry
  283.  jz select_dir10 ; stop if we can't
  284. test DATTS[bx],DA_DIR ; check if directory
  285.  jz select_dir10 ; fail if this is a file
  286. push ds ! pop es
  287. lea di,DNAME[bx] ; ES:DI -> ASCII name to open
  288. mov cx,8+3
  289. mov al,' '
  290. repe scasb ; is it all spaces ?
  291.  je select_dir10 ; if so reject it
  292. call open_dir
  293.  jnc select_dir20
  294. select_dir10:
  295. mov ax,fdos_hds_root ; move to the virtual root
  296. mov fdos_hds_blk,ax
  297. stc ; return error
  298. select_dir20:
  299. pop bx ! pop ds
  300. ret
  301. eject
  302. ; Run down the path and parse final name
  303. ; exit: ds:dx -> info_fcb parsed at path end
  304. ; cf = 1, and al = code on any error
  305. path_prep:
  306. les di,dword ptr fdos_pb+2 ; es:di -> path name
  307. path_prep_ptr:
  308. call path_prep_check ; try to prepare path
  309.  jnc path_prep_good ; skip if success
  310. jmp fdos_error ; return error to application
  311. path_prep_drive_error:
  312. ; stc ; return CY set
  313. mov ax,ED_DRIVE ; with correct error code
  314. path_prep_good:
  315. ret
  316. path_prep_check:
  317. call get_path_drive ; from asciiz or default
  318.  jc path_prep_drive_error ; continue if drive A: - Z:
  319. path_prep_cont:
  320. push di ; DX = drive code (0-15)
  321. push es ; save string address
  322. push ds ! pop es ; ES = SYSDAT
  323. call select_unique ; select the drive and
  324. pop es
  325. pop si ; es:si -> past drive
  326. lods es:al ; get first character
  327. call check_slash ; if '' or '/' then start at root
  328.  jne path_prep_curdir ;  else select current directory
  329. push es
  330. call path_prep_root ; fake a '.' entry for the root
  331. pop es
  332. lods es:al ; get next char
  333. dec si ; forget we looked
  334. test al,al ; if just a '' stop now
  335.  jz path_prep_done
  336.     call    check_slash     
  337.  jne path_prep_next ;  otherwise start processing from root
  338. mov ax,ED_ACCESS ; get correct error code
  339. stc ;  and return if \
  340. ret
  341. path_prep_curdir:
  342. ; We need to select the current directory as a start for our operations
  343. dec si ; forget about char we looked at
  344. push es ! push si ;  and save position in name
  345. mov al,logical_drv ; get the current logical drive
  346. call get_ldt ;  and hence the LDT structures
  347.  jc path_prep_curdir30 ; no LDT, leave at physical root
  348. if JOIN
  349. mov al,fdos_hds_drv ; are we on a known drive ?
  350. sub al,es:LDT_DRV[bx] ; (we may be on joined drive)
  351.  jne path_prep_curdir10 ; if not better rebuild
  352. cbw ! dec ax ; AX = FFFF
  353. else
  354. mov ax,0FFFFh
  355. endif
  356. cmp ax,es:LDT_BLK[bx] ; do we need to do a rebuild
  357.  jne path_prep_curdir20 ;  or can we trust the media ?
  358. path_prep_curdir10:
  359. call rebuild_ldt_curdir ; better reselect current dir
  360. path_prep_curdir20:
  361. mov ax,es:LDT_BLK[bx] ; move to current directory block
  362. mov fdos_hds_blk,ax
  363. path_prep_curdir30:
  364. pop si ! pop es ; ES:SI -> name again
  365. path_prep_next:
  366. ;--------------
  367. ; Called by disk change code to rebuild an HDS_ for a drive after
  368. ; media change detected.
  369. ; On Entry:
  370. ; ES:SI -> pathname to rebuild
  371. ; fdos_hds = HDS_ to rebuild
  372. ; On Exit:
  373. ; CY set if problem (AX=error code)
  374. ; ES=DS
  375. ;
  376. cmp es:byte ptr [si],0 ; can't have trailing '/' or ''
  377.  je path_prep_error ;   return this as an error
  378. mov ax,path_drive
  379. inc ax ; al = drive (one based)
  380. call parse_path ; set up the info_fcb
  381.  jc path_prep_error ; skip on any parse error
  382. test al,al ; AL = delimiter
  383.  jz path_prep_done ; are we at the end ?
  384. cmp word ptr info_fcb+1,' .'
  385.  je path_prep_next ; CHDIR (".") => stay where we are
  386. call check_no_wild ; no wilds cards in path's
  387.  je path_prep_error ; skip if wild cards found
  388. if JOIN
  389. push es
  390. push si
  391. call offer_join ; are we opening a JOIN'd drive ?
  392. pop si
  393. pop es
  394.  jnc path_prep_next ; if so move on to next stage
  395. endif
  396. push es
  397. push si ; save string address
  398. push ds ! pop es ; ES = local segment
  399. call finddfcbf ; locate the directory entry
  400. pop si
  401. pop es ; restore string address
  402.  jz path_prep_error ; no, missing directory in path
  403. test DATTS[bx],DA_DIR ; check if directory
  404.  jz path_prep_error ; fail if this is a file
  405. push es ! push si ; save string address
  406. push ds ! pop  es ; ES = local segment
  407. if PASSWORD
  408. call check_pwd_any ; check if PW req'd & supplied
  409. endif
  410. call open_dir ; go down one level
  411. pop si ! pop  es ; restore string address
  412.  jnc path_prep_next ; if open is good, repeat
  413. path_prep_error:
  414. mov ax,ED_PATH ; return code in case of error
  415. stc ; indicate error to caller
  416. ret
  417. path_prep_done:
  418. cmp info_fcb+1,'.' ; is it '.' or '..' ?
  419.  jne path_prep_exit ; if so get its full name
  420. if JOIN
  421. call offer_join ; are we opening a JOIN'd drive ?
  422.  jnc path_prep_root ;  if so move into the dir
  423. endif
  424. call finddfcbf ; find the directory entry
  425.  jz path_prep_exit ; stop if we can't
  426. call open_dir ; move into the directory
  427.  jc path_prep_error ; stop if we can't
  428. mov cx,DBLOCK1[bx] ; are we destined for the root ?
  429.  jcxz path_prep_root ; yes, stop - we won't find anything
  430. push fdos_hds_root
  431. mov fdos_hds_root,0 ; don't stop at virtual root
  432. call find_parent ; find the parental entry
  433. pop fdos_hds_root
  434.  jz path_prep_error ; (shouldn't happen)
  435. mov ax,DPWD[bx] ; get password hash code from entry
  436. mov local_password,ax ; ensure we can get back down
  437. lea si,DNAME[bx] ; point to it's name
  438. mov cx,11
  439. push ds ! pop es
  440. mov di,offset info_fcb+1
  441. rep movsb ; copy parental name to info_fcb
  442. path_prep_exit:
  443. push ds ! pop  es ; restore ES to local segment
  444. clc
  445. ret
  446. path_prep_root:
  447. push ds ! pop es ; ES = local segment
  448. mov al,info_fcb ; preserve drive setting
  449. call clear_info_fcb
  450. mov info_fcb+1,'.' ; fake a '.' directory
  451. ret
  452. clear_info_fcb:
  453. ;--------------
  454. ; Sets up a clean info_fcb for later use
  455. ; On Entry:
  456. ; AL = drive
  457. ; On Exit:
  458. ; All regs preserved
  459. ;
  460. push di ! push cx ! push ax
  461. mov di,offset info_fcb
  462. stosb ; set the drive code
  463. mov cx,11
  464. mov al,' '
  465. rep stosb ; fill name with blanks
  466. if PASSWORD
  467. mov cx,8
  468. mov di,offset password_buffer
  469. rep stosb ; blank password buffer
  470. mov es:local_password,cx ; zero out local password
  471. endif
  472. pop ax ! pop cx ! pop di
  473. clc
  474. ret
  475. eject
  476. ; Get drive from path name, or if none, use default drive
  477. ; On Entry:
  478. ; es:di -> path name
  479. ; On Exit:
  480. ; AL = path_drive = sepcified or default drive
  481. ; es:di -> past drive name
  482. ; cf = 1 if illegal drive name
  483. get_path_drive:
  484. cmp es:byte ptr [di],0 ; check if string is empty
  485.  je get_path_error ;    which isn't O.K. at all
  486. cmp es:byte ptr 1[di],':' ; if the second char is ':',
  487.  jz get_path_explicit ;    then drive is in pathname
  488. call current_dsk2al
  489. jmps get_path_ok ; common code from here
  490. get_path_explicit:
  491. mov al,es:[di] ; grab the drive designator
  492. call toupper ; make sure it is upper case
  493. sub al,'A' ; correct offset. if too
  494.  jb get_path_error ;   small, return error
  495. cmp al,ss:last_drv
  496.  jae get_path_error
  497. inc di
  498. inc di ; it's ok, bump the pointer
  499. get_path_ok:
  500. xor ah,ah ; zero ah and clc
  501. mov path_drive,ax ; save for other functions
  502. ret
  503. get_path_error:
  504. stc ; flag the error
  505. ret
  506. eject
  507. asciiz_dev_offer:
  508. ;----------------
  509. ; On Entry:
  510. ; PB+2 -> pathname
  511. ; On Exit:
  512. ; Only come back if not a device
  513. ;
  514. ; See if the filename is that of a simple device
  515. ; eg. 'CON', 'A:CON', 'CON.EXT'
  516. ; We should also accept 'DEV' format
  517. ; eg. 'DEVCON', "A:DEVCON'
  518. ; More complicated forms should be ignored - they will be handled
  519. ; after the pathname is parsed.
  520. ; eg. 'A:CON', 'CON', 'SUBDIRCON.EXT'
  521. ;
  522. push ds
  523. mov si,2[bp] ; SI -> parameter block
  524. lds si,ds:2[si] ; DS:SI -> file specification
  525. cmp ds:byte ptr 0[si],0 ; NUL names are stupid, but
  526.  je asciiz_dev_offer30 ;  you do get them....
  527. cmp ds:byte ptr 1[si],':' ; is a drive specified
  528.  jne asciiz_dev_offer10
  529. inc si ! inc si ; skip that, but no more
  530. asciiz_dev_offer10:
  531. push ss ! pop es ; ES:DI -> scratch FCB in build
  532. mov di,offset name_buf ;  name in pcmode data buffer
  533. mov al,' '
  534. mov cx,8+3
  535. rep stosb ; start by clearing name
  536. mov al,[si] ; beware of 'DEVname' format..
  537. call check_slash ; if not slash carry on
  538.  jne asciiz_dev_offer15
  539. lodsb ; possible, lets look at rest
  540. lodsb
  541. call toupper
  542. cmp al,'D' ; is 'D'possible ?
  543.  jne asciiz_dev_offer30
  544. lodsb
  545. call toupper
  546. cmp al,'E' ; is 'DE' on ?
  547.  jne asciiz_dev_offer30
  548. lodsb
  549. call toupper
  550. cmp al,'V' ; is 'DEV' on ?
  551.  jne asciiz_dev_offer30
  552. lodsb ; finally how about trailing ''
  553. call check_slash
  554.  jne asciiz_dev_offer30
  555. mov al,[si] ; check for delimiter
  556. asciiz_dev_offer15:
  557. call check_delim ; if first char = delimiter
  558.  jz asciiz_dev_offer30 ;  then it can't be a device
  559. mov di,offset name_buf ; build name in scratch FCB
  560. mov cx,8 ; length of name field
  561. call parse_one ; parse just the name
  562. cmp al,'.'
  563.  jnz asciiz_dev_offer20 ; do we have to parse an extention ?
  564. mov di,offset name_buf+8 ; di -> fcb ext field
  565. mov cx,3 ; length of ext field
  566. call parse_one ; parse just extension
  567. asciiz_dev_offer20:
  568. test al,al ; if not a NUL by now forget it
  569.  jnz asciiz_dev_offer30
  570. push ss ! pop ds
  571. mov si,offset name_buf ; DS:SI -> name
  572. call check_device_common ; try to find the name
  573.  jnc asciiz_dev_accept ; if we can handle it here
  574. asciiz_dev_offer30:
  575. pop ds ; DS back to normal
  576. push ss ! pop es ; ditto with ES
  577. ret ; not a device - proceed
  578. asciiz_dev_accept:
  579. ;----------------
  580. ; We have found a match in the device at ES:BX
  581. ;
  582. mov ss:word ptr current_device,bx
  583. mov ss:word ptr current_device+WORD,es
  584. pop ds ; DS = SYSDAT again
  585. pop ax ; discard return address
  586. call local_disk ; we need the MX
  587. les bx,ss:current_device ; ES:BX -> device header
  588. cmp fdos_pb,FD_EXPAND
  589.  je asciiz_dev_accept20
  590. cmp fdos_pb,4Eh ; is it FD_FFIRST ?
  591.  je asciiz_dev_accept10
  592. jmp open_dev ; open the device locally
  593. asciiz_dev_accept10:
  594. jmp first_dev ; 'find' the device locally
  595. asciiz_dev_accept20:
  596. jmp expand_dev ; 'expand' the device locally
  597. eject
  598. chk_no_dev: ; check file is not a character device
  599. ;----------
  600. ; On Entry:
  601. ; info_fcb contains parsed filename
  602. ; On Exit:
  603. ; Don't return if it's a character device
  604. ;
  605. call check_device ; is this a device ?
  606.  jnc chk_not_dev10
  607. push ds ! pop es ; ES points to data again
  608. ret
  609. chk_not_dev10:
  610. jmp fdos_ED_ACCESS ; blow caller away
  611. check_device:
  612. ;------------
  613. ; On Entry:
  614. ; info_fcb contains parsed filename
  615. ; On Exit:
  616. ; CY set if not found
  617. ; else
  618. ; CY clear if found
  619. ; ES:BX -> device header
  620. ;
  621. mov si,offset info_fcb+1 ; DS:SI -> name to check
  622. ; jmp check_device_common
  623. check_device_common:
  624. ;-------------------
  625. ; On Entry:
  626. ; DS:SI -> 8 byte buffer to check
  627. ; On Exit:
  628. ; CY set if not found
  629. ; else
  630. ; CY clear if found
  631. ; ES:BX -> device header
  632. ;
  633. push ss ! pop es ; Get the PCMODE Data Segment
  634. mov bx,offset dev_root ;  hence the Device List
  635. mov ax,si ; keep copy of start in AX
  636. check_device10:
  637. test es:DH_ATTRIB[bx],DA_CHARDEV
  638.  jz check_device20 ; skip unless it's a character device
  639. lea di,DH_NAME[bx] ; ES:DI -> device name
  640. mov cx,8/2 ; compare file name w/o extension
  641. repe cmpsw ; compare until CX == 0 or mismatch
  642.  je check_device30
  643. check_device20:
  644. mov si,ax ; restore starting address
  645. les bx,es:DH_NEXT[bx] ; get next device driver
  646. cmp bx,0FFFFh ; end of the chain ?
  647.  jne check_device10
  648. stc ; indicate character device not found
  649. check_device30:
  650. ret
  651. eject
  652. no_dir_vol:
  653. ;----------
  654. test DATTS[bx],DA_DIR+DA_VOLUME
  655.  jnz dir_vol_err ; return error if label or directory
  656. ret ; else it's O.K.
  657. dir_vol_err:
  658. jmp fdos_ED_ACCESS ; return "access denied"
  659. eject
  660. get_pb2_drive:
  661. ;-------------
  662. mov al,byte ptr fdos_pb+2 ; get requested drive code
  663. dec al ; Get the default drive if
  664.  jns get_pb2_drv1 ; the requested drive is 00
  665. call current_dsk2al ; AL = default drive
  666. get_pb2_drv1:
  667. ret
  668. eject
  669. mkdir_init:
  670. ;----------
  671. push ax ; Init 1st block of the directory
  672. call zeroblk ; zero the block
  673. pop ax ! push ax ; get the block number
  674. xor bx,bx ; seek to beginning of cluster
  675. call fill_dirbuf ; DI -> directory entry
  676. pop dx ! push dx ; get our own block #
  677. mov ax,' .' ; this is the "." directory
  678. call init_dot ; set name, attrib, time, date, block1
  679. call flush_dirbuf ; copy '.' entry to sector buffer
  680. pop ax ; get the block number
  681. mov bx,1 ; do 2nd entry
  682. call fill_dirbuf ; DI -> directory entry
  683. call hdsblk
  684. xchg ax,dx ; DX = parent directory
  685. mov ax,'..' ; this is the ".." directory
  686. ; call init_dot ; fall into INIT_DOT
  687. ; ret
  688. init_dot:
  689. mov dirp,di ; save directory entry for SETPCD
  690. push di
  691. mov DBLOCK1[di],dx ; our own block #
  692. stosw ; store "." or ".."
  693. mov al,' '
  694. mov cx,11-2
  695. rep stosb ; pad the name with spaces
  696. mov al,DA_DIR
  697. stosb ; attribute = directory
  698. call GetTOD ; get time/date of creation
  699. pop bx
  700. jmp stamp_date_and_time ; set date DX and time AX in dir BX
  701. eject
  702. ; Utility functions for RMDIR and UNLINK
  703. rmdir_ok: ; make sure directory not in use
  704. ;--------
  705. ;
  706. mov bx,dirp ; get the directory entry
  707. mov ax,DBLOCK1[bx] ; block number of directory
  708. xor bx,bx ; start at beginning
  709. rmdir_ok1:
  710. push ax ! push bx ; save block, offset
  711. call fill_dirbuf ; locate directory entry
  712. pop bx ! pop ax ; restore offset, block
  713. cmp DNAME[di],0 ; is it virgin entry?
  714.  je rmdir_ok4 ;    yes, no entries above here
  715. cmp DNAME[di],0E5h ; is it deleted entry?
  716.  je rmdir_ok3 ;    yes, no problems yet...
  717. cmp DNAME[di],'.' ; is it "." or ".."?
  718.  je rmdir_ok3
  719. if DELWATCH
  720. ; We have found a dir entry - better check if it is a pending delete
  721. ; and that delwatch is installed. Then we can ignore it.
  722. test DATTS[di],DA_VOLUME ; is the volume label bit set
  723.  jz rmdir_not_empty ;  no, can't be pending delete
  724. xor dx,dx ; (also sets DH = DELW_RDMASK)
  725. ; cmp dx,DBLOCK1[di] ; is it really a pending delete ?
  726. ;  jz rmdir_not_empty ; yes, fall thru to delwatch check
  727. xchg ax,dx ; AH = DELW_RDMASK, DX = dir cluster
  728. mov si,di ; -> directory buffer (for DELWATCH)
  729. callf ss:fdos_stub ; is the delwatch TSR installed
  730. xchg ax,dx ; AX = dir cluster
  731.  jnc rmdir_ok3 ; delwatch will handle pending deletes
  732. rmdir_not_empty:
  733. endif
  734. mov ax,ED_ACCESS ; return "access denied" if not empty
  735. rmdir_inuse: ; directory not empty or in use:
  736. jmp fdos_error ; return the error
  737. rmdir_ok3: ; else this entry O.K.
  738. inc bx ; check next directory entry
  739. cmp bx,dirperclu ; cluster completed?
  740.  jb rmdir_ok1 ; loop back if more to come
  741. call getnblk ; get next block in directory
  742. sub bx,bx ; start at beginning of block
  743. cmp ax,lastcl ; end of cluster chain?
  744.  jb rmdir_ok1 ; loop back if not done yet
  745. rmdir_ok4: ; directory is empty
  746. mov al,adrive
  747. call hshdscrd ; discard the hash values
  748. clc ; "go ahead with RMDIR..."
  749. ret ; return, ready for the evil deed...
  750. chkcds: ; check if any process uses directory to delete
  751. ;------
  752. ; On Entry:
  753. ; dirp -> directory entry of DIR to check
  754. ; On Exit:
  755. ; CY clear if DIR is in use
  756. ;
  757. mov bx,dirp
  758. mov cx,DBLOCK1[bx] ; block number of directory to delete
  759. mov dl,physical_drv ; get the drive the subdir is in
  760. mov al,-1 ; start with drive A:
  761. chkcds10:
  762. inc ax ; next drive
  763. call get_ldt_raw ; ES:BX -> LDT for drive
  764.  jc chkcds20 ; bail if if bad drive
  765. test es:byte ptr LDT_FLAGS+1[bx],(LFLG_NETWRKD+LFLG_PHYSICAL)/100h
  766.  js chkcds10 ; it can't be a network drive
  767.  jz chkcds10 ; it must be a physical drive
  768. cmp dl,es:LDT_DRV[bx] ; does the drive match?
  769.  jne chkcds10 ; no, don't bother then
  770. cmp es:LDT_BLK[bx],0ffffh ; is it valid
  771.  jne    chkcds19
  772. push ax
  773. push cx
  774. push dx
  775. call select_logical_drv ; select with media change check
  776. call rebuild_ldt_curdir ; rebuild LDT_
  777. pop dx
  778. pop cx
  779. pop ax
  780. chkcds19:
  781. if 0
  782. ; This didn't make the beta, so leave until the next release
  783. ; We really need to make sure we relog all SUBST's drives before
  784. ; we can be sure this is valid and fail the rmdir
  785. cmp cx,es:LDT_ROOT[bx] ; is this our root block ?
  786.  je chkcds20 ; (ie. a SUBST'd drive)
  787. endif
  788. cmp cx,es:LDT_BLK[bx] ; does the block match
  789.  jne chkcds10 ; no, try next drive
  790. chkcds20:
  791. ret
  792. eject
  793. ;
  794. ; Go down one level in directory
  795. ; On Entry:
  796. ; DIRP -> directory to open
  797. ; PATH_DRIVE = drive to use
  798. ; On Exit:
  799. ; AX = fdos_hds_blk (the current directory block)
  800. ; CY clear on success
  801. ; CY set on error
  802. ;
  803. open_dir:
  804. mov bx,dirp
  805. test DATTS[bx],DA_DIR ; check if directory
  806. stc
  807.  jz open_dir20 ; fail if this is a file
  808. cmp word ptr info_fcb+1,'..'
  809.  jne open_dir10 ; watch out if going up a level
  810. mov ax,fdos_hds_blk ; get current block
  811. cmp ax,fdos_hds_root ; check if at logical root already
  812.  jne open_dir10 ;  and if not carry on
  813. cmp ax,DBLOCK1[bx] ; if we are already at the virtual root
  814. stc ;  and want to stay there that's OK
  815.  jne open_dir20 ; otherwise return an error
  816. open_dir10:
  817. mov al,physical_drv ; remember the drive
  818. mov fdos_hds_drv,al
  819. mov ax,DBLOCK1[bx] ; remember this directory block
  820. mov fdos_hds_blk,ax
  821. clc ; success
  822. open_dir20:
  823. ret
  824. Public hdsblk
  825. ;======
  826. hdsblk: ;/* check if we are in subdirectory */
  827. ;======
  828. ;
  829. ; exit: AX = directory block number
  830. ; ZF = set if at root
  831. ; regs: others preserved
  832. mov ax,fdos_hds_blk ; get current directory block
  833. test ax,ax ; set ZF
  834. ret
  835. parent2save_area:
  836. ;-----------------
  837. ; On Entry:
  838. ; AX = cluster number of parent to find
  839. ; On Exit:
  840. ; save_area contains parental name (DX = length of name)
  841. ;
  842. call find_parent ; locate parent directory
  843.  jz path_error ; stop in case we're in a mess
  844. lea si,DNAME[bx] ; get parent directory name
  845. mov di,offset save_area ; ES:DI -> scratch area
  846. ; jmp unparse ; make it ASCIIZ file name
  847. ; build ASCIIZ string from directory entry
  848. ; entry: BX -> directory buffer
  849. ; ES:DI -> output buffer
  850. ; exit: ES:DI -> next byte in buffer
  851. unparse:
  852. ;-------
  853. push di ; save base of name
  854. mov cx,8 ; remainder of up to 7 characters
  855. lea si,DNAME[bx] ; SI -> directory name
  856. call unparse_field ; copy name, strip trailing blanks
  857. mov al,'.'
  858. stosb ; add the dot for start of extension
  859. push di ; remember where extention starts
  860. mov cx,3 ; copy 3-char extension
  861. lea si,DNAME+8[bx] ; SI -> directory extention
  862. call unparse_field ; copy extension, strip trailing blanks
  863. pop ax ; recover start of extension
  864. cmp ax,di ; did we generate extension?
  865.  jne unparse1 ; skip if we did
  866. dec di ; else eat the '.'
  867. unparse1:
  868. xor ax,ax
  869. stosb ; NUL-terminate the name
  870. pop bx ; ES:BX -> base of name
  871. cmp es:byte ptr [bx],05h
  872.  jne unparse2 ; if not mapped E5 (deleted entry/Kanji)
  873. mov es:byte ptr [bx],0E5h ; else map back to E5 for Kanji support
  874. unparse2:
  875. ret
  876. unparse_field:
  877. ;-------------
  878. ; entry: DS:SI -> disk buffer
  879. ; ES:DI -> ASCIIZ name to build
  880. ; CX = field length
  881. ; On Exit:
  882. ; ES:DI -> end of name
  883. ; BX preserved
  884. push si ; save start of field
  885. add si,cx ; SI -> end of field
  886. inc cx ; one extra for LOOPE dec
  887. unprsf10:
  888. dec si ; lets look at the previous char
  889. cmp ds:byte ptr [si],' ' ; trailing space ?
  890. loope unprsf10
  891. pop si ; SI = start of field
  892. rep movsb
  893. ret
  894. path_error:
  895. jmp fdos_ED_PATH ; return "invalid path" error
  896. mkspace_parent:
  897. ;--------------
  898. ; save_area contains the parental name, DX bytes long. We wish to insert it
  899. ; into an ASCIIZ string so make DX bytes of space at ES:DI.
  900. ; On Entry:
  901. ; ES:DI -> ASCIIZ, DX = byte count
  902. ; On Exit:
  903. ; DS:SI -> parents name, CX = length of parent (DX on entry)
  904. ;
  905. mov al,0 ; find end of name
  906. mov cx,128 ; max. path length
  907. repne scasb ; scan for end of path
  908. neg cx
  909. add cx,128 ; CX = string length including NUL
  910. mov ax,cx
  911. add ax,dx
  912. cmp ax,64
  913.  ja path_error
  914. dec di ; ES:DI -> ''
  915. mov si,di ; SI -> source of copy
  916. add di,dx ; point to beyond insertion
  917. push ds
  918. push es ! pop ds ; move string backwards to make space
  919. std ! rep movsb ! cld ; for directory name
  920. pop ds
  921. mov cx,dx ; CX = length of new directory name
  922. mov si,offset save_area ; SI -> unparsed name
  923. ret
  924. ; find parent directory starting with cluster AX
  925. ; entry: AX = cluster of parent to find
  926. ; exit: ZF = 1 if not found (shouldn't happen)
  927. ; -or-
  928. ; ZF = 0 if found, BX=DIRP -> dir entry
  929. find_parent:
  930. mov blk,ax ; save the block number
  931. push ds ! pop es
  932. mov di,offset info_fcb+1
  933. mov ax,'..' ! stosw ; file name is '..'
  934. mov al,' ' ; pad with spaces
  935. mov cx,9 ! rep stosb
  936. call finddfcbf ; find pointer to parent
  937.  jz fndpar2 ; shouldn't happen...
  938. call open_dir ; go up one level
  939.  jc fndpar3 ; screwed up by security...
  940. call setenddir ; search from beginning
  941. fndpar1:
  942. sub cx,cx
  943. call getdir ; find next directory entry
  944.  jz fndpar2 ; end of directory
  945. mov al,DNAME[bx] ; check if deleted file
  946. cmp al,0E5h
  947.  je fndpar1 ; skip empty slots
  948. cmp al,0
  949.  je fndpar2 ; end of directory
  950. test DATTS[bx],DA_DIR ; try to find directory
  951.  jz fndpar1 ; skip plain files
  952. mov ax,DBLOCK1[bx] ; get starting cluster
  953. cmp ax,blk
  954.  jne fndpar1
  955. fndpar3:
  956. or ax,0FFFFh ; force non-zero condition
  957. fndpar2:
  958. ret ; ZF = 0 if found
  959. eject
  960. path_prep_chk:
  961. ;-------------
  962. ; Run down the path and parse final name
  963. ; exit: ds:dx -> info_fcb parsed at path end
  964. call path_prep ; prepare the path
  965. call chk_no_dev ; devices not allowed
  966. chk_no_dot_or_wild:
  967. ;------------------
  968. call chk_no_dot ; no subdirs entries either
  969. ; jmp chk_no_wild ; wild cards not allowed
  970. eject
  971. chk_no_wild: ; make sure path doesn't contain wild cards
  972. ;----------- ;  (or is all spaces)
  973. call check_no_wild ; error if any wildcards
  974.  jne check_no_wild_ret ;  or if all spaces
  975. jmp fdos_ED_FILE ; return "invalid filename"
  976. check_no_wild: ; make sure path doesn't contain wild cards
  977. ;------------- ;  (or is all spaces) ZF set on problem
  978. push es
  979. push ds ! pop es ; ES -> SYSDAT
  980. mov di,offset info_fcb+1
  981. mov cx,11
  982. mov al,'?' ; scan for wild cards
  983. repne scasb
  984.  je check_no_wild_exit ; skip if wild cards found
  985. mov di,offset info_fcb+1
  986. mov cx,11
  987. mov al,' ' ; scan for all spaces
  988. repe scasb ; ZF set if a problem
  989. check_no_wild_exit:
  990. pop es
  991. check_no_wild_ret:
  992. ret
  993. chk_for_root:
  994. ;------------
  995. ; On Entry:
  996. ; info_fcb -> name of failed search
  997. ; fdos_hds -> dir we searched in
  998. ; On Exit:
  999. ; ZF set if a search for root (or '.' in root)
  1000. ;
  1001. cmp fdos_hds_blk,0 ; are we in the root ?
  1002.  jne chk_for_root10 ; no, no further checks required
  1003. push ds ! pop es
  1004. mov di,offset info_fcb+1
  1005. mov al,'.' ;  check for root
  1006. scasb ; is it a '.' entry ?
  1007.  jne chk_for_root10
  1008. mov cx,8+3-1
  1009. mov al,' '
  1010. repe scasb ; is it all spaces ?
  1011. chk_for_root10:
  1012. ret
  1013. ; Parse a pathname into an info_fcb
  1014. ; entry: es:si -> asciiz string
  1015. ; AX = drive code
  1016. ; exit: es:si -> next asciiz name in path
  1017. ; dx -> fcb
  1018. ; CY clear, AL = 0 if end of string
  1019. ; CY set, AX = error code
  1020. parse_path:
  1021. ;----------
  1022. push ds ! push  es
  1023. pop ds ! pop   es
  1024. call clear_info_fcb ; initialise to blanks and drive AL
  1025. mov dx,offset info_fcb ; use a scratch fcb
  1026. mov di,dx ; dx saves initial di
  1027. inc di
  1028. mov ax,[si] ; check first two chars
  1029. cmp al,'.' ; special case:  if name = '.'
  1030.  jne parse_path20 ;   then we parse it differently
  1031. movsb ; copy the '.'
  1032. cmp ah,'.' ; special case:  if name = '..'
  1033.  jne parse_path10 ;   then we parse it differently
  1034. movsb ; copy '..'
  1035. parse_path10:
  1036. lodsb ; get next char
  1037. cmp al,' ' ; skip all spaces
  1038.  je parse_path10
  1039. jmps parse_path30 ; now exit as normal
  1040. parse_path20:
  1041. call check_delim ; if first char = delimeter
  1042.  je parse_path30 ;   then only allow ''
  1043. ; filename begins with a legal char, parse it normally
  1044. mov di,dx
  1045. inc di ; di -> fcb name field
  1046. mov cx,8 ; length of name field
  1047. call parse_one ; parse just the name
  1048. mov di,dx ; DI -> FCB
  1049. cmp es:byte ptr 1[di],0E5h ; is first character E5?
  1050.  jne parse_path30 ; skip if not
  1051. mov es:byte ptr 1[di],05h ; else make it internal synonym
  1052. parse_path30:
  1053. cmp al,'.'
  1054.  jne parse_path40 ; skip if no extension
  1055. add di,9 ; di -> fcb ext field
  1056. mov cx,3 ; length of ext field
  1057. call parse_one ; parse just extension
  1058. parse_path40:
  1059. if PASSWORD
  1060. cmp al,';' ; check if password specified
  1061.  jne parse_path50 ; skip if no password
  1062. mov di,offset password_buffer
  1063. mov cx,8 ; length of password field
  1064. call parse_one ; parse just password
  1065. push ax
  1066. push ds ! push si
  1067. push ss ! pop ds ; DS:SI -> ASCII password
  1068. mov si,offset password_buffer
  1069. call hash_pwd ; AX = encrypted password
  1070. mov local_password,ax ; remember it in case we need it
  1071. pop si ! pop ds
  1072. pop ax
  1073. endif
  1074. parse_path50:
  1075. test al,al ; a NUL is OK
  1076.  jz parse_path90
  1077. call check_slash ; if terminator != '' or '/',
  1078. stc ; assume an error
  1079.  jne parse_path80 ; report it if so
  1080. parse_path60:
  1081. lodsb ; get next character
  1082. call check_delim ; we expect a normal character
  1083.  jne parse_path80 ;  here - exit if we've got one
  1084. call check_slash ; swallow ''s at this point and leave
  1085.  je parse_path60 ;  other delimiters for next time
  1086. cmp al,'.' ; trailing '.' ?
  1087.  jne parse_path75
  1088. mov cx,si ; remember position of '.'
  1089. parse_path70:
  1090. lodsb ; now discard trailing spaces
  1091. cmp al,' '
  1092.  je parse_path70 ; keep going until we lose all spaces
  1093. test al,al ; stop at a NUL
  1094.  jz parse_path50
  1095. call check_slash ; if it's a '' try again
  1096.  je parse_path50
  1097. mov si,cx ; retract to the '.'
  1098. parse_path75:
  1099. mov al,'' ; return '' as the delimiter
  1100. clc ;  and exit with no problems
  1101. parse_path80:
  1102. dec si ; retract a byte (CY unaffected)
  1103. parse_path90:
  1104. push  ds  !  push  es
  1105. pop   ds  !  pop   es
  1106. ret
  1107. Public parse_one
  1108. ; Parse a single name or extension
  1109. ; On Entry:
  1110. ; DS:SI -> asciiz name
  1111. ; ES:DI -> start of fcb field
  1112. ; CX = field size
  1113. ; On Exit:
  1114. ; AL = last char parsed
  1115. ;
  1116. ; nb. make no assumptions about DS and ES
  1117. ;
  1118. parse_one:
  1119. lodsb ; grab asciiz char
  1120. cmp al,'*' ; if char = *, then fill
  1121.  jz parse_one_wild ;   rest of field with '?'
  1122. call check_delim ; if char is not delimiter,
  1123.  jnz parse_one_char ;   then move it to fcb
  1124. ret ; if delimiter, return
  1125. parse_one_wild:
  1126. mov al,'?'
  1127. rep stosb ; after filling
  1128. jmps parse_one_ignore ; skip until a delimiter
  1129. parse_one_char:
  1130. if KANJI
  1131. call dbcs_lead ; is it 1st byte of Kanji pair?
  1132.  jnz parse_one_skip ; skip if straight 8-bit
  1133. inc si ; assume both chars discarded
  1134. dec cx ; we will copy 2 bytes
  1135.  jcxz parse_one_ignore ; ignore both if only room for one
  1136. stosb ; thats the first byte
  1137. dec si ; point at 2nd again
  1138. lodsb ; get the 2nd byte
  1139. parse_one_skip:
  1140. endif
  1141. stosb ; send char to fcb
  1142. loop parse_one ; get another character from ASCIIZ string
  1143. parse_one_ignore:
  1144. lodsb
  1145. call check_delim ; ignore up to next delimiter
  1146.  jnz parse_one_ignore
  1147. ret
  1148. ;
  1149. ;
  1150. ; Check for a path name delimiter
  1151. ; entry: AL = ASCIIZ char
  1152. ; exit: all registers preserved
  1153. ; ZF = 1 if char is a delimeter
  1154. ; ZF = 0 if char is legal in file names
  1155. Public check_delim
  1156. check_delim:
  1157. ;-----------
  1158. cmp al,' ' ; if any printable char,
  1159.  jae check_delim_char ;   then skip
  1160. cmp al,al ; set zf
  1161. ret
  1162. check_delim_char:
  1163. if KANJI
  1164. call dbcs_lead ; if it's 1st of kanji pair
  1165.  jne check_delim10 ; DON'T upper case it
  1166. test al,al ; clear zf
  1167. ret ; (should really check the 2nd byte)
  1168. check_delim10:
  1169. endif
  1170. call toupper ; make it upper case
  1171. push es ! push di ! push cx
  1172. push cs ! pop es
  1173. lea di,delim_string ; es:di -> delimeters
  1174. mov cx,length delim_string
  1175. cld
  1176. repnz scasb ; match al against the list
  1177. pop cx ! pop di ! pop es
  1178. clc ; never return cf set
  1179. ret ; with zf set by scasb
  1180. delim_string db  ':.;,=+<>|/"[]' ; DOS delimeters
  1181. ; Check AX for '\'
  1182. Public check_dslash
  1183. check_dslash:
  1184. xchg al,ah
  1185. call check_slash
  1186. xchg al,ah
  1187.  jne check_slash_done
  1188. ; jmp check_slash
  1189. ; Check delimeter character for '' or '/'
  1190. ; entry: al = char
  1191. ; exit: zf = 1 if either slash
  1192. check_slash:
  1193. cmp al,'' ; if first char is a backslash
  1194.  jz check_slash_done ;   or a frontslash, then
  1195. cmp al,'/' ;   return with zf set
  1196. check_slash_done:
  1197. clc ; never return cf set
  1198. ret
  1199. ; Convert character to upper case
  1200. ; WARNING - may be called with DS <> SYSDAT
  1201. toupper:
  1202. ;-------
  1203. test al,al
  1204.  js toupper_intl
  1205. cmp al,'a'
  1206.  jb isupper
  1207. cmp al,'z'
  1208.  ja isupper
  1209. sub al,'a'-'A'
  1210. isupper:
  1211. ret
  1212. toupper_intl:
  1213. callf ss:intl_xlat ; call international upper case vector
  1214. ret
  1215. eject
  1216. kill_file: ; release clusters for file/dir and delete entry
  1217. ;---------
  1218. mov bx,dirp ; get pointer to directory entry
  1219. if DELWATCH
  1220. call hdsblk ; AX = directory root cluster
  1221. xchg ax,dx ; DX = dir cluster
  1222. mov cx,dcnt ; CX = directory index for entry
  1223. mov ah,DELW_DELETE ; we are about to delete this dir
  1224. mov al,physical_drv ;  directory entry so give delwatch
  1225. callf ss:fdos_stub ;  a chance to make it pending delete
  1226.  jnc kill_file10 ; delwatch took it - just update dir
  1227. endif
  1228. mov al,0E5h ; deleted file mark
  1229. xchg al,DNAME[bx] ; delete the directory entry
  1230. mov DUNDEL[bx],al ; save 1st letter for UNDEL command
  1231. mov ax,DBLOCK1[bx] ; get starting block #
  1232. call delfat ; release all clusters
  1233. kill_file10:
  1234. jmp flush_dirbuf ; update the directory
  1235. ; done it! (DIR/FAT still dirty)
  1236. eject
  1237. mustbe_nolbl:
  1238. ;------------
  1239. ; On Entry:
  1240. ; None
  1241. ; On Exit:
  1242. ; Only returns if no label exists
  1243. ; forces us to root of drive
  1244. ;
  1245. push ds ! pop es ; ES = DS for string ops
  1246. mov si,offset info_fcb+1
  1247. mov di,offset save_area ; SI->search name, DI->save area
  1248. mov cx,11
  1249. push di ; save save_area
  1250. push si ; save info_fcb+1
  1251. push cx ; save length
  1252. rep movsb ; copy search name into save area
  1253. pop cx ; CX = length (11)
  1254. pop di ; DI = info_fcb+1
  1255. push di
  1256. push cx
  1257. mov al,'?' ; now fill info_fcb with wildcards
  1258. rep stosb
  1259. call find_labelf ; look for a volume label
  1260. pop cx ; CX = length (11)
  1261. pop di ; DI = info_fcb+1
  1262. pop si ; SI = save_area
  1263. push ds ! pop es ; ES = DS for string ops
  1264. rep movsb ; restore info_fcb
  1265.  jnz mustbe_nolbl10 ; if we found a label bail out
  1266. ret
  1267. mustbe_nolbl10:
  1268. jmp fdos_ED_ACCESS ; return access denied
  1269. find_labelf: ; find label only
  1270. ;----------- ; forces us to root
  1271. ; On Entry:
  1272. ; None
  1273. ; On Exit:
  1274. ; ZF clear if volume label found
  1275. ; dirp/dcnt tell where label is
  1276. ;
  1277. call setenddir ; start from beginning
  1278. ; jmp find_label
  1279. find_label: ; find label only
  1280. ;---------- ; forces us to root
  1281. ; On Entry:
  1282. ; dcnt -> location to search from
  1283. ; On Exit:
  1284. ; ZF clear if volume label found
  1285. ; dirp/dcnt tell where label is
  1286. ;
  1287. mov chdblk,0 ; don't assume sequential access
  1288. mov fdos_hds_blk,0 ; look for labels in the root
  1289. mov finddfcb_mask,000ffh ; return VOL labels, not pending dels
  1290. find_label30:
  1291. call finddfcb ; find matching file name
  1292.  jz find_label40 ; skip if not found
  1293. test DATTS[bx],DA_VOLUME
  1294.  jz find_label30 ; try again if not a volume label
  1295. find_label40:
  1296. mov finddfcb_mask,DA_VOLUME*256
  1297. ret ; back to no VOL labels or pending dels
  1298. if UNDELETE
  1299. find_pending_delete:  ; find pending delete only
  1300. ;-------------------
  1301. ; On Entry:
  1302. ; dcnt -> location to search from
  1303. ; On Exit:
  1304. ; ZF clear if pending delete entry found
  1305. ; dirp/dcnt tell where entry is
  1306. ;
  1307. mov finddfcb_mask,0h ; return pending delete entries
  1308. find_pending_delete10:
  1309. mov al,05h ; replace 1st char with 05h
  1310. xchg al,info_fcb+1 ;  saving char we really want
  1311. push ax
  1312. call finddfcb ; find matching file name
  1313. pop ax
  1314. mov info_fcb+1,al ; restore original 1st letter
  1315.  jz find_pending_delete30 ; skip if not found
  1316. test DATTS[bx],DA_VOLUME ; Is it a pending delete entry
  1317.  jz find_pending_delete10 ; No, try again if not a volume label
  1318. cmp word ptr DBLOCK1[bx],0  ; Is this a pending delete entry
  1319.  jz find_pending_delete10 ; No, try again if not correct
  1320. cmp al,'?' ; wildcard is OK
  1321.  je find_pending_delete20
  1322. cmp al,DUNDEL[bx] ; does saved char match what we want?
  1323.  jne find_pending_delete10
  1324. find_pending_delete20:
  1325. and DATTS[bx],not DA_VOLUME ; mask out volume bit
  1326. mov al,DUNDEL[bx] ; move deleted character to normal
  1327. mov DNAME[bx],al ;  position for return
  1328. or al,al ; clear the zero flag (assumes al!=0)
  1329. find_pending_delete30:
  1330. mov finddfcb_mask,DA_VOLUME*256
  1331. ret ; back to no VOL labels or pending dels
  1332. endif
  1333. eject
  1334. find_xfn: ; find spare external file number
  1335. ;--------
  1336. ; exit: DI = new handle
  1337. push es ; save ES while we play
  1338. xor di,di ; return handle 0 if don't have PSP
  1339. call get_xftptr
  1340.  jc fndxfn2
  1341. mov bx,di ; save the offset
  1342. mov al,0FFh ; look for unused slot
  1343. repne scasb ; loop while CX != 0 and *ES:DI != 0FFh
  1344.  jne fndxfn3 ; ZF = 1 if match, else none found
  1345. dec di ; DI = matching offset
  1346. sub di,bx ; DI = handle index
  1347. fndxfn2:
  1348. pop es
  1349. clc ; indicate no error
  1350. ret
  1351. fndxfn3:
  1352. pop es
  1353. stc ; indicate an error
  1354. ret
  1355. Public alloc_dhndl
  1356. alloc_dhndl:
  1357. ;-----------
  1358. ; provisionally allocate a spare DHNDL_, do not return without one
  1359. ; On Entry:
  1360. ; None
  1361. ; On Exit:
  1362. ; AX = IFN of handle
  1363. ; ES:BX -> DHNDL_ structure
  1364. ; (All other regs preserved)
  1365. call find_dhndl ; try to find a spare DHNDL_
  1366.  jc fdos_ED_HANDLE ; bail out if we can't
  1367. ret
  1368. mustbe_free_handle:
  1369. ;------------------
  1370. ; return an error to user if either an XFN or an IFN is unavailable
  1371. ; On Entry:
  1372. ; None
  1373. ; On Exit:
  1374. ; None
  1375. ;
  1376. call alloc_dhndl ; make sure we can allocate a DHNDL
  1377. mov es:DHNDL_COUNT[bx],0 ; free it in case open/creat fails
  1378. ; (we are protected by local_disk)
  1379. ; jmp alloc_xfn ; make sure an XFN is also free
  1380. Public alloc_xfn
  1381. alloc_xfn: ; find spare external file number
  1382. ;--------
  1383. ; exit: DI = new handle
  1384. call find_xfn ; try to find spare slot in XFT
  1385.  jc fdos_ED_HANDLE ; "out of handles" if no luck
  1386. mov fdos_ret,di ; else save the resulting handle
  1387. ret
  1388. fdos_ED_HANDLE:
  1389. mov ax,ED_HANDLE ; out of user file #s, all 20 in use
  1390. jmp fdos_error
  1391. ; Allocate & initialize file handle:
  1392. ; entry: AX = open mode
  1393. ; DIRP -> directory entry
  1394. ; exit: ES:BX = CURRENT_DHNDL = file handle
  1395. ; AX = fdos_ret = IFN
  1396. ; -or-
  1397. ; System call fails with ED_HANDLE
  1398. open_handle:
  1399. ;-----------
  1400. mov bx,dirp ; else get directory entry
  1401. test DATTS[bx],DA_RO ; check if file is r/o - if so
  1402.  jz creat_handle ;  make handle r/o too
  1403. and ax,not DHM_RWMSK
  1404. creat_handle:
  1405. ;------------
  1406. ; entry point for create file - when you create a read-only file
  1407. ; you still get a handle you can write with !
  1408. push ax ; save open mode
  1409. xchg ax,si ; SI = open mode
  1410. mov di,S_OM_COMPAT ; check if open/sharing modes are compatible
  1411. call check_with_share ; does SHARE approve ?
  1412. call alloc_dhndl ; allocate a DHNDL_ structure
  1413. mov fdos_ret,ax ; remember IFN in case it's FCB
  1414. pop dx ! push dx ; DX = open mode
  1415. push es ! push bx ; save DHNDL_ pointer
  1416. test dh,DHM_FCB/100h ; FCB call?
  1417.  jne creat_handle10 ; skip XFN allocation if FCB
  1418. push ax ; save IFN
  1419. call alloc_xfn ; allocate spare XFN
  1420. pop ax ; recover IFN
  1421. mov bx,di ; BX = XFN
  1422. call get_xftptr ; ES:DI -> user file table
  1423.  jc creat_handle10 ; skip if we don't have one
  1424. mov es:[di+bx],al ; set IFN in PSP
  1425. creat_handle10:
  1426. pop bx ! pop es
  1427. lea di,DHNDL_COUNT[bx] ; point at open count
  1428. mov ax,1
  1429. stosw ; open by one
  1430. pop ax ; recover open mode
  1431. mov cx,DHAT_TIMEOK+DHAT_CLEAN
  1432. test al,DHM_LOCAL ; is it private ?
  1433.  jz creat_handle20
  1434. or ch,DHAT_LOCAL/256 ; rememmber it's local
  1435. and al,not DHM_LOCAL ; clear inherit bit
  1436. creat_handle20:
  1437. ; lea di,DHNDL_MODE[bx] ; update the mode
  1438. stosw
  1439. mov si,dirp
  1440. mov al,DATTS[si] ; get file attribute byte
  1441. lea di,DHNDL_DATRB[bx] ; now copy file attribute
  1442. stosb ;  to DHNDL_
  1443. xchg ax,cx ; AX = attributes
  1444. or al,physical_drv ; get physical drive
  1445. ; lea di,DHNDL_WATTR[bx] ; make as clean disk file
  1446. stosw
  1447. ; lea di,DHNDL_DEVOFF[bx] ; ES:DI -> dd entry in DHNDL_
  1448. mov ax,ss:word ptr current_ddsc
  1449. stosw ; point to DDSC_
  1450. mov ax,ss:word ptr current_ddsc+WORD
  1451. stosw
  1452. mov ax,DBLOCK1[si] ; get starting cluster of file
  1453. ; lea di,DHNDL_BLK1[bx]
  1454. stosw
  1455. lea si,DTIME[si]
  1456. ; lea di,DHNDL_TIME[bx]
  1457. movsw ; copy the time
  1458. ; lea di,DHNDL_DATE[bx]
  1459. movsw ; and the date
  1460. lodsw ; skip 1st cluster (already done)
  1461. ; lea di,DHNDL_SIZE[bx]
  1462. movsw ! movsw ; copy the file size
  1463. ; lea di,DHNDL_POS[bx]
  1464. xor ax,ax ; zero current position
  1465. stosw ! stosw
  1466. ; lea di,DHNDL_IDX[bx]
  1467. stosw ; zero block index
  1468. if DOS5
  1469. call hdsblk ; get directory block
  1470. ; lea di,DHNDL_DBLK[bx]
  1471. stosw
  1472. xor ax,ax
  1473. stosw
  1474. else
  1475. ; lea di,DHNDL_BLK[bx]
  1476. stosw ; and current block
  1477. call hdsblk ; get directory block
  1478. ; lea di,DHNDL_DBLK[bx]
  1479. stosw
  1480. endif
  1481. mov ax,dcnt ; set DCNT of file
  1482. ; lea di,DHNDL_DCNTLO[bx]
  1483. stosb ; store low byte of DCNT
  1484. mov es:DHNDL_DCNTHI[bx],ah ;  and hi byte
  1485. ; lea di,DHNDL_NAME[bx] ; copy name from dir entry
  1486. mov si,dirp
  1487. mov cx,11
  1488. rep movsb
  1489. xor ax,ax
  1490.     stosw               ; zero DWORD 
  1491.     stosw               
  1492. lea di,DHNDL_SHARE[bx] ; zero sharing record
  1493. stosw
  1494. if DOS5
  1495. stosw ! stosw ! stosw ; zero DHNDL_BLK + IFS
  1496. endif
  1497. callf ss:share_stub+S_OPEN ; we have opened this handle
  1498. ;  ask SHARE to register it
  1499.  jc create_handle30
  1500. mov ax,fdos_ret ; AX = handle to return
  1501. ret
  1502. create_handle30: ; free the handle again
  1503. push ax
  1504. mov ax,fdos_ret
  1505. call release_handle2
  1506. pop ax
  1507. jmp fdos_error
  1508. Public verify_handle
  1509. verify_handle:
  1510. ;-------------
  1511. ; On Exit:
  1512. ; ES:BX = DHNDL_
  1513. ; CY set if bad file handle (nb. device handle is bad)
  1514. ;
  1515. call check_handle ; make sure we can access it
  1516.  jc vfy_hnd9 ; return if character device
  1517. select_handle: ; select directory of current handle
  1518. ;-------------
  1519. ; On Entry:
  1520. ; ES:BX -> DHNDL_
  1521. ; On Exit:
  1522. ; ES:BX preserved
  1523. ;
  1524. mov al,es:DHNDL_ATTR[bx] ; get physical drive
  1525. and al,DHAT_DRVMSK ;  from attrib field
  1526. push es ! push bx
  1527. call select_physical_drv ; select the drive
  1528. pop bx ! pop es
  1529. mov ax,es:DHNDL_DBLK[bx]
  1530. mov fdos_hds_blk,ax ; copy HDS_BLK
  1531. clc ; handle is OK file
  1532. vfy_hnd9:
  1533. ret ; good handle
  1534. ; Checks if parameter is a legal file handle:
  1535. ; Entry: CURRENT_DHNDL = handle to verify
  1536. ; Exit: ES:BX = DHNDL_ if O.K.
  1537. ; CY clear if local disk file
  1538. ; CY set if device/network handle
  1539. ; Note: doesn't return on error
  1540. check_handle:
  1541. ;------------
  1542. les bx,current_dhndl
  1543. test es:DHNDL_WATTR[bx],DHAT_REMOTE+DHAT_DEV
  1544. stc ; assume device/network file
  1545.  jnz chkhnd10 ; return with CY = 0 if disk file
  1546. callf ss:share_stub+S_UPDATE ; make sure DHNDL_ info valid
  1547.  jc chkhnd20 ; if not close it down
  1548. chkhnd10:
  1549. ret
  1550. chkhnd20:
  1551. call get_xftptr ; ES:BX -> XFT
  1552.  jc fdos_ED_H_MATCH ; skip if not handle
  1553. mov bx,fdos_pb+2 ; get XFN so we can poke
  1554. mov es:byte ptr [di+bx],0ffh
  1555. ;  PSP handle to closed
  1556. ; jmp  fdos_ED_H_MATCH ; return "invalid handle"
  1557. fdos_ED_H_MATCH:
  1558. mov ax,ED_H_MATCH ; "invalid handle"
  1559. jmp fdos_error ; return an error
  1560. public vfy_dhndl_ptr
  1561. vfy_dhndl_ptr:
  1562. ;=============
  1563. ; Verifies file handles at FDOS_xxxx calling level
  1564. ; before MXdisk is locked.
  1565. ; On Entry:
  1566. ; SS:BP -> func #, parm off, parm seg
  1567. ; stack holds two ret addresses + above values
  1568. ; On Exit:
  1569. ; ES:BX -> DHNDL_
  1570. mov si,2[bp] ; SI -> parameter block
  1571. mov ax,2[si] ; get file handle from parameter block
  1572. test ss:byte ptr remote_call+1,DHM_FCB/100h; if we are doing an FCB operation
  1573.  jnz vfy_dhndl10 ;  deal only with IFN, forget PSP
  1574. mov es,ss:current_psp
  1575. cmp ax,PSP_XFNMAX ; CX = # entries in table
  1576.  jae vfy_dhndl_err
  1577. les di,PSP_XFTPTR ; ES:DI -> user file table
  1578. mov bx,ax ; get user file number (0-19)
  1579. mov al,es:[bx+di] ; get IFN for this handle
  1580. vfy_dhndl10:
  1581. cmp al,0ffh ; invalid handle?
  1582.  je vfy_dhndl_err ; 00h-FEh only
  1583. les bx,ss:file_ptr ; get the address of the first entry
  1584. vfy_dhndl20:
  1585. cmp ax,es:DCNTRL_COUNT[bx] ; handle in this block?
  1586.  jae vfy_dhndl50 ; skip to try next block if not
  1587.     mov ah,DHNDL_LEN     
  1588. mul ah
  1589. add ax,DCNTRL_LEN ; skip the header
  1590. add bx,ax ; add to start of structure
  1591. mov cx,es:DHNDL_COUNT[bx] ; fail if the handle is not in use
  1592.      jcxz   vfy_dhndl_err
  1593. inc cx ; FFFF = pre-allocated is also failed
  1594.  jz vfy_dhndl_err
  1595. cmp ss:WindowsHandleCheck,26h
  1596. ; have we been patched
  1597.  jne vfy_dhndl30 ;  yes, don't check owner
  1598. mov ax,ss:machine_id ; get current process
  1599. cmp ax,es:DHNDL_UID[bx] ;  are we the owning process
  1600.  jne vfy_dhndl_err ; no, return an error
  1601. vfy_dhndl30:
  1602. mov ss:word ptr current_dhndl,bx
  1603. mov ss:word ptr current_dhndl+WORD,es
  1604. test es:DHNDL_MODE[bx],DHM_NOCRIT
  1605.  jnz vfy_dhndl40 ; are critical errors allowed ?
  1606. ret
  1607. vfy_dhndl40:
  1608. or valid_flg,NO_CRIT_ERRORS
  1609. ret ; remember no critical errors possible
  1610. vfy_dhndl50:
  1611. sub ax,es:DCNTRL_COUNT[bx] ; update the internal file number
  1612. les bx,es:DCNTRL_DSADD[bx] ; get the next entry and check
  1613. cmp bx,0FFFFh ;   for the end of the list
  1614.  jnz vfy_dhndl20
  1615. vfy_dhndl_err:
  1616. add sp,WORD ; pop return addr - return to caller
  1617. mov bx,ED_H_MATCH ;  with "invalid handle" error
  1618. ret
  1619. ; On Entry:
  1620. ; FDOS_PB+2 = external file handle to release
  1621. ; On Exit:
  1622. ; ES:BX -> DHNDL_
  1623. release_handle:
  1624. ;--------------
  1625. mov ax,fdos_pb+2 ; get user file number (0-19)
  1626. release_handle2:
  1627. ;---------------
  1628. call get_xftptr ; ES:DI -> XFN table
  1629.  jc release_ifn ; IFN = XFN if no PSP
  1630. cmp ax,cx ; more than in handle table?
  1631.  jae rlshnd_err ; return error if too large
  1632. xchg ax,bx ; BX = external file number
  1633. mov al,0FFh ; get old IFN, release XFN
  1634. xchg al,es:[bx+di] ; get IFN for this handle
  1635. cmp al,0FFh
  1636.  je rlshnd_err
  1637. release_ifn:
  1638. call ifn2dhndl ; ES:BX -> DHNDL_
  1639.  jnc check_no_dir_ret ; return if no error
  1640. rlshnd_err: ; else bad handle
  1641. jmp fdos_ED_H_MATCH ; return the error
  1642. eject
  1643. check_no_dir: ; check if entry is directory
  1644. ;--------
  1645. ; entry: BX -> directory entry
  1646. test DATTS[bx],DA_DIR ; test if directory
  1647.  jnz chk_ro_err ; skip if a directory
  1648. check_no_dir_ret:
  1649. ret ; else return to caller
  1650. check_ro: ; check if file write protected
  1651. ;--------
  1652. ; entry: BX -> directory entry
  1653. test DATTS[bx],DA_RO ; test if file r/o
  1654.  jnz chk_ro_err ; skip if file r/o
  1655. ret ; else return to caller
  1656. chk_ro_err:
  1657. jmp fdos_ED_ACCESS ; return "access denied" if r/o
  1658. discard_files: ; discard all handles on adrive
  1659. ;-------------
  1660. mov al,adrive
  1661. callf ss:share_stub+S_DISCARD ; tell share to forget about files
  1662. ret
  1663. ; Close file if it's us in compatibility modes
  1664. close_if_same_psp:
  1665. ;-----------------
  1666. ; Note: We first check if the file is open by anyone other
  1667. ; than the same UID and PSP, or is open in shared mode.
  1668. ; In either case we deny the operation.
  1669. ; Otherwise we fall through and close the file.
  1670. ; We could do it in one with a new share, but this way means
  1671. ; less changes.
  1672. ;
  1673. mov di,S_DENY_IF_OPEN ; check if file already open
  1674. call check_with_share ; and stop if it is
  1675. ; jmp close_if_open
  1676. ; Make sure our file is not open
  1677. close_if_open:
  1678. ;-------------
  1679. ; entry: HDSADR->BLK = block # of directory
  1680. ; HDSADR->DRV = drive number
  1681. ; DCNT = directory position
  1682. ; Note: If the file is open by any other process,
  1683. ; error ED_SHAREFAIL is returned from the system call
  1684. ; If open by us (same UID, any PSP) in compatibility mode,
  1685. ; close it and allow us to proceed.
  1686. mov di,S_CLOSE_IF_OPEN ; check if file already open
  1687. ; jmps check_with_share
  1688. check_with_share:
  1689. ;----------------
  1690. ; On Entry:
  1691. ; DI = S_ share query
  1692. ; On Exit:
  1693. ; Come back if share says it's OK.
  1694. ;
  1695. call hdsblk ; get directory block in AX
  1696. xchg ax,dx ; directory block
  1697. mov cx,dcnt ; get the directory count in CX
  1698. mov al,physical_drv ; get physical drive in AL
  1699. callf ss:share_stub[di] ; ask SHARE if it knows of anyone open
  1700.  jc check_with_share10
  1701. ret ; must be OK.
  1702. check_with_share10:
  1703. jmp fdos_error ; bail out with an error
  1704. eject
  1705. eject
  1706. ;
  1707. ; Return a pointer to the DOS Handle corresponding to the internal
  1708. ; handle number passed in AX
  1709. ;
  1710. ; On Entry:
  1711. ; AL = IFN
  1712. ;
  1713. ; On Exit:
  1714. ; ES:BX -> DOS handle (All other Regs preserved)
  1715. ; CY set if no corresponding valid DHNDL_
  1716. ;
  1717. Public ifn2dhndl
  1718. ifn2dhndl:
  1719. push ax
  1720. xor ah,ah ; make IFN a word
  1721. les bx,ss:file_ptr ; get the address of the first entry
  1722. ifn2dh10:
  1723. cmp ax,es:DCNTRL_COUNT[bx] ; handle in this block?
  1724.  jae ifn2dh20 ; skip if not
  1725. mov ah,DHNDL_LEN ;  calculate offset of the DOS Handle
  1726. mul ah
  1727. add bx,ax ; add structure offset (should be 0) 
  1728. add bx,DCNTRL_LEN ;    and then skip the header
  1729. pop ax
  1730. clc
  1731. ret ; ES:BX -> valid DHDNL_
  1732. ifn2dh20:
  1733. sub ax,es:DCNTRL_COUNT[bx] ; update the internal file number
  1734. les bx,es:DCNTRL_DSADD[bx] ; get the next entry and check
  1735. cmp bx,0FFFFh ;   for the end of the list
  1736.  jnz ifn2dh10 
  1737. ifn2dh15:
  1738. pop ax
  1739. stc
  1740. ret ; invalid file handle number
  1741. ;
  1742. ; Allocate a DHNDL_ structure
  1743. ;
  1744. ; On Entry:
  1745. ; None
  1746. ;
  1747. ; On Exit:
  1748. ; CY clear if handle allocated
  1749. ; AX = IFN of handle
  1750. ; ES:BX -> DOS handle
  1751. ; (All other Regs preserved)
  1752. ;
  1753. Public find_dhndl
  1754. find_dhndl:
  1755. push cx ! push dx ! push di ! push si
  1756. mov ax,ss:machine_id ; get current process
  1757. mov dx,ss:owning_psp ; DX = owining PSP
  1758. xor si,si ; SI = IFN
  1759. les di,ss:file_ptr ; get the address of the first entry
  1760. find_dh10:
  1761. mov cx,es:DCNTRL_COUNT[di] ; get # handles in this block
  1762.  jcxz find_dh40 ; skip if none
  1763. lea bx,DCNTRL_LEN[di] ; ES:BX -> 1st DHNDL_
  1764. find_dh20:
  1765. push cx
  1766. cli ; be alone while looking at handles
  1767. mov cx,es:DHNDL_COUNT[bx]
  1768.  jcxz find_dh50 ; if handle free grab it
  1769. inc cx ; FFFF = allocated but unused
  1770.  jnz find_dh30
  1771. cmp ax,es:DHNDL_UID[bx] ; was it allocated to us
  1772.  jne find_dh30
  1773. cmp dx,es:DHNDL_PSP[bx] ; if so use it again
  1774.  je find_dh60
  1775. find_dh30:
  1776. sti ; finished with this handle
  1777. pop cx
  1778. inc si ; onto next IFN
  1779. cmp si,0FFh ; only handles 00-FE are valid
  1780.  jae find_dh45 ;  so bail if out of range
  1781. add bx,DHNDL_LEN ; onto next handle in the block
  1782. loop find_dh20
  1783. find_dh40:
  1784. les di,es:DCNTRL_DSADD[di] ; get the next entry and check
  1785. cmp di,0FFFFh ;  it's valid
  1786.  jne find_dh10
  1787. find_dh45:
  1788. stc ; no more handles,
  1789. jmps find_dh70 ;  exit in failure..
  1790. find_dh50:
  1791. mov es:DHNDL_COUNT[bx],0FFFFh
  1792. mov es:DHNDL_UID[bx],ax ; allocate it to us
  1793. mov es:DHNDL_PSP[bx],dx
  1794. find_dh60:
  1795. sti ; safe again
  1796. pop cx ; discard handle count
  1797. xchg ax,si ; AX = IFN
  1798. mov ss:word ptr current_dhndl,bx
  1799. mov ss:word ptr current_dhndl+WORD,es
  1800. mov ss:current_ifn,ax
  1801. clc ; we have found and allocated a handle
  1802. find_dh70:
  1803. pop di ! pop si ! pop dx ! pop cx
  1804. ret
  1805. Public get_xftptr
  1806. get_xftptr:
  1807. ;----------
  1808. ; On Entry:
  1809. ; None
  1810. ; On Exit:
  1811. ; ES:DI -> PSP_XFTPTR for current_psp
  1812. ; CX = # entries in it
  1813. ; CY set if not PSP operation (eg. FCB's)
  1814. ; (all other regs preserved)
  1815. ;
  1816. test ss:byte ptr remote_call+1,DHM_FCB/100h; if we are doing an FCB operation
  1817.  jnz get_xftptr_err ;  deal only with IFN, forget PSP
  1818. mov es,ss:current_psp
  1819. mov cx,PSP_XFNMAX ; CX = # entries in table
  1820. les di,PSP_XFTPTR ; ES:DI -> user file table
  1821. ret
  1822. get_xftptr_err:
  1823. stc ; forget about XFN's
  1824. ret
  1825. Public current_dsk2al
  1826. current_dsk2al:
  1827. ;--------------
  1828. ; AL = current default drive
  1829. mov al,ss:current_dsk
  1830. ret
  1831. Public lds_si_dmaptr
  1832. lds_si_dmaptr:
  1833. ;-------------
  1834. ; On Entry:
  1835. ; None
  1836. ; On Exit:
  1837. ; DS:SI -> current DMA address
  1838. ; (All other regs preserved)
  1839. lds si,ss:dword ptr dma_offset
  1840. ret
  1841. public les_di_dmaptr
  1842. les_di_dmaptr:
  1843. ;-------------
  1844. ; On Entry:
  1845. ; None
  1846. ; On Exit:
  1847. ; ES:DI -> current DMA address
  1848. ; (All other regs preserved)
  1849. les di,ss:dword ptr dma_offset
  1850. ret
  1851. Public copy_asciiz
  1852. copy_asciiz:
  1853. ;----------
  1854. ; Copy an ASCIIZ string from DS:SI to ES:DI
  1855. lodsb ! stosb
  1856. test al,al
  1857.  jnz copy_asciiz
  1858. ret
  1859. if JOIN
  1860. check_join:
  1861. ;----------
  1862. ; On Entry:
  1863. ; fdos_hds -> HDS we wish to check
  1864. ; On Exit:
  1865. ; AH = drive (zero based) from fdos_hds_drv
  1866. ; AL = drive (zero based) of the JOIN root
  1867. ; if JOINed drive
  1868. ;     ZF clear
  1869. ; else
  1870. ;     ZF set
  1871. ; (All other regs presrved)
  1872. ;
  1873. push es ! push bx
  1874. mov al,fdos_hds_drv ; get drive from HDS_
  1875. mov ah,al ; save HDS_DRV in AH
  1876.   cmp join_drv,0 ; need we do anything ?
  1877.  je check_join30 ;  not if we haven't JOIN'd
  1878. cmp fdos_hds_root,0 ; is virtual root the physical one ?
  1879.  jne check_join10 ;  if not we can't be JOIN'd
  1880. call get_ldt ; ES:BX -> LDT for this drive
  1881.  jc check_join10 ; bad LDT - we can't be joined
  1882. test es:LDT_FLAGS[bx],LFLG_JOINED
  1883.  jz check_join30
  1884. mov al,es:LDT_NAME[bx] ; get drive letter
  1885. sub al,'A' ; make drive letter zero based
  1886. mov bl,byte ptr path_drive ; get the logical drive we are on
  1887. push ax
  1888. mov al,bl ; AL = logical drive we are using
  1889. call get_ldt ; ES:BX -> LDT for this drive
  1890. pop ax
  1891.  jc check_join10 ; no valid LDT..
  1892. cmp es:LDT_NAME+2[bx],'' ; are we at the root ?
  1893.  jne check_join10 ; no, it can't be match
  1894. mov bl,es:LDT_NAME[bx] ; get the root drive for this drive
  1895. sub bl,'A' ; make drive letter zero based
  1896. cmp al,bl ; are we on the JOIN'd drive ?
  1897. mov bl,0ffh ; assume we are
  1898.  je check_join20 ; were we ?
  1899. check_join10:
  1900. mov al,ah ; restore HDS_DRV
  1901. xor bl,bl ; return with ZF clear
  1902. check_join20:
  1903. test bl,bl ; set ZF appropriately
  1904. check_join30:
  1905. pop bx ! pop es
  1906. ret
  1907. offer_join: ; are we opening a JOIN'd drive ?
  1908. ;----------
  1909. ; If we are at the root of a JOIN'd drive moving up ("..") fiddle HDS
  1910. ; onto parental JOIN drive root.
  1911. ; If we are at the root of a non-JOIN'd drive see if we are searching for
  1912. ; a JOIN'd drive directory
  1913. ; On Entry:
  1914. ; info_fcb = entry we are searching for
  1915. ; On Exit:
  1916. ; CY set if not a JOIN'd drive
  1917. ;
  1918. cmp join_drv,0 ; need we do anything ?
  1919.  jne oj_dochecks ; not, if we haven't JOIN'd
  1920. oj_rejected:
  1921. stc ; not a JOIN drive
  1922. ret
  1923. oj_dochecks:
  1924. ;-----------
  1925. ; Before we do anything else we must be at the physical root of a drive
  1926. ; with a valid LDT. We then check for two cases
  1927. ; 1) Doing a '..' from a JOIN'd drive to it's parental root
  1928. ; 2) Opening a directory correpsonding to a JOIN'd drive
  1929. ;
  1930. mov al,info_fcb ; AL -> drive we are looking for
  1931. call get_ldt ; ES:BX -> LDT for this drive
  1932.  jc oj_rejected ; bad LDT - we can't be joined
  1933. cmp es:LDT_ROOTLEN[bx],2 ; is root at top level ?
  1934.  ja oj_rejected ; no, skip the rest
  1935. cmp fdos_hds_blk,0 ; are we at the root ?
  1936.  jne oj_rejected ; if not we needn't do anything
  1937. ; We have validated HDS_, so now check for case 1)
  1938. call check_join ; is it a joined drive ?
  1939.  jz oj_dir ; if not skip to case 2)
  1940. cmp word ptr info_fcb+1,'..'; else is it a '..' in JOIN'd root?
  1941.  jne oj_rejected ; if not we needn't do anything
  1942. call mvhds_drvroot ; do '..' from root -> real root
  1943. clc ; we handled it it !
  1944. ret
  1945. oj_dir:
  1946. ;------
  1947. ; We are in the physical root of a non-joined drive. We now need to see if
  1948. ; the dir we are searching for corresponds with a joined drive
  1949. ;
  1950. push si ! push di
  1951. call build_match_name ; join_name = what we are looking for
  1952. call look_for_match ; see if we can find it
  1953.  jc oj_dir10
  1954. call mvhds_drvroot ; we have a match - move into it
  1955. clc ; say we handled it
  1956. oj_dir10:
  1957. pop di ! pop si
  1958. ret
  1959. look_for_match:
  1960. ;--------------
  1961. ; Compare join_name against available JOIN drives.
  1962. ; Return with CY clear if we found it, ES:BX -> LDT, AL the drive
  1963. xor ch,ch
  1964. mov cl,join_drv ; search this many drives
  1965. xor ax,ax ; start with drive A:
  1966. mov ah,last_drv
  1967. call get_ldt ; ES:BX -> LDT for this drive
  1968.  jnc lfm20
  1969. ret ; no LDT's...
  1970. lfm10:
  1971. inc al ; next drive
  1972. cmp al,ah ; paranioa - check if we have reached
  1973.  jae lfm50 ;  last_drv and exit if so
  1974. add bx,LDT_LEN ; next LDT
  1975. lfm20:
  1976. test es:LDT_FLAGS[bx],LFLG_JOINED
  1977.  jz lfm10 ; if not JOIN'd try next candidate
  1978. lea di,LDT_NAME[bx] ; ES:DI -> JOIN info
  1979. mov si,offset join_name ; lets see if it matches the
  1980. push ax
  1981. lfm30:
  1982. lodsb ; get a byte
  1983. scasb ; does it match ?
  1984.  jne lfm40 ; no, forget it
  1985. test al,al ; end of the string yet ?
  1986.  jnz lfm30 ; no, keep trying
  1987. lfm40:
  1988. pop ax
  1989.  je lfm60 ; did we match ?
  1990. loop lfm10 ; no, if any JOIN's left try them
  1991. lfm50:
  1992. stc ; we didn't find it
  1993. lfm60:
  1994. ret
  1995. build_match_name:
  1996. ;----------------
  1997. ; Fill join_name with the "C:JOIN" we want to find
  1998. ;
  1999. mov al,info_fcb ; AL -> drive we are looking for
  2000. dec al ; make it zero based
  2001. call get_ldt ; ES:BX -> LDT for this drive
  2002. mov al,es:LDT_NAME[bx] ; get the drive "D"
  2003. push ds ! pop es ; ES -> SYSDAT
  2004. mov di,offset join_name ; construct the target name
  2005. stosb ; plant the drive letter
  2006. mov ax,':'
  2007. stosw ; now we have "d:"
  2008. mov bx,offset info_fcb+1 ; DS:SI -> name we are looking for
  2009. jmp unparse ; unparse the name
  2010. BDOS_DATA dseg word
  2011. join_name db 'd:filename.ext',0
  2012. BDOS_CODE cseg
  2013. Public mv_join_root
  2014. mv_join_root:
  2015. ;------------
  2016. ; Poke the fdos_hds to be the root. If it's the physical root we then
  2017. ; see if it is a JOIN'd drive. If it is we poke the drive and reselect
  2018. ; the disk so we are at the real root of the drive.
  2019. ;
  2020. push bx ! push si ! push di ; save index registers
  2021. mov ax,fdos_hds_root
  2022. mov fdos_hds_blk,ax ; move us to virtual root
  2023. test ax,ax ; is it the real root ?
  2024.  jnz mvj_root10 ; if not forget about JOIN'd drives
  2025. call check_join ; are we joined ?
  2026.  jz mvj_root10 ; no, we've done enough
  2027. call mvhds_drvroot ; make it real root
  2028. mvj_root10:
  2029. pop di ! pop si ! pop bx ; restore index registers
  2030. ret
  2031. mvhds_drvroot:
  2032. ;-------------
  2033. ; On Entry:
  2034. ; AL = Drive (0 based physical)
  2035. ; On Exit:
  2036. ; None
  2037. ;
  2038. ; Poke the HDS to be at the root of drive AL and select that drive
  2039. ;
  2040. mov fdos_hds_drv,al ; change to joined drive
  2041. xor dx,dx
  2042. mov fdos_hds_blk,dx ; put us back to the root again
  2043. mov fdos_hds_root,dx
  2044. cmp al,physical_drv ; already there ?
  2045.  je mvhds_drvroot10 ; then skip the selection
  2046. call select_physical_drv ; select the drive
  2047. mvhds_drvroot10:
  2048. jmp path_prep_root ; info_fcb = '.'
  2049. ; ret
  2050. endif ;JOIN
  2051. eject
  2052. stamp_dir_entry:
  2053. ;---------------
  2054. ; On Entry:
  2055. ; DIRP -> None
  2056. ; On Exit:
  2057. ; None
  2058. ;
  2059. ; Apply current date/time stamp to a directory, along with any other
  2060. ; security information required.
  2061. ;
  2062. if PASSWORD
  2063. mov cx,local_password ; were we given a password ?
  2064.  jcxz stamp_dir_entry10 ;  if so apply it
  2065. mov bx,dirp
  2066. mov DPWM[bx],PWM_ANY ; deny all for compatibility
  2067. or DATTS[bx],DA_HIDDEN ;  make dir entry hidden
  2068. mov DPWD[bx],cx ;  with this password
  2069. stamp_dir_entry10:
  2070. endif
  2071. call ReadTOD ; get current time/dat
  2072. mov bx,dirp
  2073. ; jmp stamp_date_and_time
  2074. stamp_date_and_time:
  2075. ; On Entry:
  2076. ; BX -> directory entry
  2077. ; AX = time
  2078. ; DX = date
  2079. ; On Exit:
  2080. ; None
  2081. ; stamp a directory entry with a given date and time
  2082. mov DDATE[bx],dx
  2083. mov DTIME[bx],ax
  2084. mov ah,PASSWD_CREAT ; call out to SECURITY TSR
  2085. callf ss:fdos_stub
  2086.  jc stamp_date_and_time10
  2087. jmp fdos_error ; return an error if required
  2088. stamp_date_and_time10:
  2089. ret
  2090. public ReadTOD
  2091. ReadTOD:
  2092. ;-------
  2093. ; On Entry:
  2094. ; None
  2095. ; On Exit:
  2096. ; DX = internal date format
  2097. ; AX = internal time format
  2098. ;
  2099. call ReadTimeAndDate ; get current time/date from BIOS
  2100. ; jmp GetTOD
  2101. GetTOD:
  2102. ;-------
  2103. ; On Entry:
  2104. ; None
  2105. ; On Exit:
  2106. ; DX = internal date format
  2107. ; AX = internal time format
  2108. ;
  2109. mov ax,yearsSince1980 ; year is bits 9-15
  2110. mov cl,4
  2111. shl ax,cl
  2112. add al,month ; month is bits 4-8
  2113. mov cl,5
  2114. shl ax,cl
  2115. add al,dayOfMonth ; day is bits 0-3
  2116. xchg ax,dx ; DX = date
  2117. mov al,hour ; hour is bits 11-15
  2118. mov cl,6
  2119. shl ax,cl
  2120. add al,minute ; minute is bits 5-10
  2121. mov cl,5
  2122. shl ax,cl
  2123. mov cl,second ; second/2 is bits 0-4
  2124. shr cl,1 ;
  2125. add al,cl
  2126. ret
  2127. select_from_DTA:
  2128. ;----------------
  2129. ; called by search next/undelete/purge to select a disk and prepare for
  2130. ; a directory search based upon DTA contents.
  2131. ;
  2132. push ds
  2133. call lds_si_dmaptr ; DS:SI -> DMA address
  2134. lodsb ; get search drive
  2135. pop ds
  2136. dec ax ; (stored 1-relative)
  2137. mov path_drive,ax ; restore path drive
  2138. call select_physical_drv ; select the drive in AL
  2139. push ds
  2140. push ds ! pop es ; ES = local segment
  2141. call lds_si_dmaptr ; DS:SI -> DMA address
  2142. inc si ; skip the drive #
  2143. mov di,offset info_fcb+1 ; copy FCB back to INFO_FCB
  2144. mov cx,11
  2145. rep movsb
  2146. lodsb ; get search attribute
  2147. mov es:attributes,al
  2148. lodsw ; get directory count
  2149. mov es:dcnt,ax
  2150. lodsw ; get the directory block
  2151. pop ds ; restore data segment
  2152. mov fdos_hds_blk,ax
  2153. ret
  2154. if PASSWORD
  2155. check_pwd_d: ; check if PW protected in any mode
  2156. ;-----------
  2157. mov ax,PWM_D
  2158. jmps check_pwd
  2159. check_pwd_any: ; check if PW protected in any mode
  2160. ;-------------
  2161. mov ax,PWM_ANY
  2162. ; jmps check_pwd
  2163. check_pwd: ; check for password mismatch
  2164. ;---------
  2165. ; entry: AX = password mode to be checked
  2166. ; DIRP -> directory entry for file
  2167. ; exit: BX, SI preserved
  2168. push ax
  2169. push bx
  2170. mov bx,dirp ; BX -> file to be opened/deleted/etc.
  2171. xchg ax,cx ; password mode in CX
  2172. mov ah,PASSWD_CHECK ; call out to SECURITY TSR
  2173. callf ss:fdos_stub
  2174.  jnc check_pwd20
  2175. mov ax,DPWD[bx] ; get password hash code from entry
  2176.  jcxz check_pwd10 ; exit if no password
  2177. cmp ax,global_password ; compare with default password
  2178.  je check_pwd10 ; yes, go ahead
  2179. cmp ax,local_password ; is it one we've just parsed ?
  2180.  je check_pwd10 ; yes, go ahead
  2181. ; else we've got a password mismatch
  2182. test cx,DPWM[bx] ; test if password mode affects us
  2183.  jz check_pwd10 ; skip if attempted access O.K.
  2184. mov ax,ED_PASSWORD ; return password error
  2185. check_pwd20:
  2186.     jmp fdos_error      
  2187. check_pwd10:
  2188. pop bx
  2189. pop ax
  2190. ret
  2191. Public hash_pwd
  2192. hash_pwd: ; compute 16-bit hash code for 1st COMMON_DMA password
  2193. ;--------
  2194. ; On Entry:
  2195. ; DS:SI -> 8 character password
  2196. ; On Exit:
  2197. ; AX = password hash code or 0000 if none (ZF set)
  2198. ; SI corrupted, all other regs preserved
  2199. ;
  2200. push cx
  2201. push bp
  2202. mov cx,8 ; ch = 0, cl = 8
  2203. mov bp,sp ; reverse and upper-case the name
  2204. sub sp,cx ;  using temp buffer on the stack
  2205. xor ax,ax ; zero null password flag
  2206. hash_pwd1:
  2207. lodsb ; get next ASCII character
  2208. call toupper ; international upper case
  2209. dec bp
  2210. mov ss:[bp],al ; copy password char to encrypted buff
  2211. or al,al ; is password char zero?
  2212.  jz hash_pwd2 ; yes
  2213. cmp al,' ' ; is password char blank?
  2214.  je hash_pwd2 ; yes
  2215. inc ah ; password is not null
  2216. hash_pwd2:
  2217. add ch,al ; add password char to encrypt CRC
  2218. dec cl
  2219.  jnz hash_pwd1
  2220. mov al,ch ; AL = password CRC
  2221. mov cx,8 ; encrypt 8 characters
  2222. or ah,al ; if CRC = 0 and all 00 or ' '
  2223.  jz hash_pwd6 ;    then there is no password
  2224. hash_pwd3:
  2225. xor ss:[bp],al ; encrypt password on stack
  2226. inc bp
  2227. loop hash_pwd3
  2228. xor bp,bp ; initialize hash code
  2229. mov cx,4 ; 8 bytes = 4 words
  2230. hash_pwd4:
  2231. pop ax ; get two encrypted characters
  2232. rol ax,cl ; juggle them about a bit
  2233. xor bp,ax ; "add" them into hash code
  2234. loop hash_pwd4 ; repeat for whole password
  2235.  jnz hash_pwd5 ; skip if result is non-zero
  2236. inc bp ; else force it to be non-zero
  2237. hash_pwd5:
  2238. xchg ax,bp ; return hash code in AX
  2239. hash_pwd6:
  2240. add sp,cx ; tidy up stack if buffer not poped
  2241. test ax,ax ; set ZF flag appropriately
  2242. pop bp
  2243. pop cx
  2244. ret
  2245. endif
  2246. public share_delay
  2247. ; waste time before retrying operation that failed due to SHARE intervention
  2248. share_delay:
  2249. cmp ss:byte ptr remote_call,0
  2250.  jne share_delay_30
  2251. push cx
  2252. mov cx,ss:net_delay
  2253.  jcxz share_delay_20
  2254. share_delay_10:
  2255. push cx
  2256. xor cx,cx
  2257. loop $
  2258. pop cx
  2259. loop share_delay_10
  2260. share_delay_20:
  2261. pop cx
  2262. share_delay_30:
  2263. ret