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

操作系统开发

开发平台:

Asm

  1. title 'DIRS - dos directory support'
  2. ;    File              : $DIRS.A86$
  3. ;
  4. ;    Description       :
  5. ;
  6. ;    Original Author   : DIGITAL RESEARCH
  7. ;
  8. ;    Last Edited By    : $CALDERA$
  9. ;
  10. ;-----------------------------------------------------------------------;
  11. ;    Copyright Work of Caldera, Inc. All Rights Reserved.
  12. ;      
  13. ;    THIS WORK IS A COPYRIGHT WORK AND CONTAINS CONFIDENTIAL,
  14. ;    PROPRIETARY AND TRADE SECRET INFORMATION OF CALDERA, INC.
  15. ;    ACCESS TO THIS WORK IS RESTRICTED TO (I) CALDERA, INC. EMPLOYEES
  16. ;    WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF
  17. ;    THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN CALDERA, INC. WHO
  18. ;    HAVE ACCEPTED THE CALDERA OPENDOS SOURCE LICENSE OR OTHER CALDERA LICENSE
  19. ;    AGREEMENTS. EXCEPT UNDER THE EXPRESS TERMS OF THE CALDERA LICENSE
  20. ;    AGREEMENT NO PART OF THIS WORK MAY BE USED, PRACTICED, PERFORMED,
  21. ;    COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED,
  22. ;    CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST,
  23. ;    TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF
  24. ;    CALDERA, INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT
  25. ;    AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO CRIMINAL AND
  26. ;    CIVIL LIABILITY.
  27. ;-----------------------------------------------------------------------;
  28. ;
  29. ;    *** Current Edit History ***
  30. ;    *** End of Current Edit History ***
  31. ;
  32. ;    $Log$   
  33. ;    DIRS.A86 1.13 94/12/01 13:16:24
  34. ;    changed error code if directory entry cannot be allocated;    
  35. ;    DIRS.A86 1.12 93/08/27 18:49:04
  36. ;    hash code fixup on previously unused entries resets hash count
  37. ;    pcformat bug where an extra (zero-length) command.com was left on disk
  38. ;    ENDLOG
  39. ;
  40. ; Date    Who Modification
  41. ; ---------  --- ---------------------------------------
  42. ;   19 Aug 91 Initial version created for VLADIVAR
  43. eject
  44. include bdos.equ
  45. include i:mserror.equ
  46. include i:fdos.equ
  47. eject
  48. PCMODE_DATA dseg
  49. if DELWATCH
  50. extrn fdos_stub:dword ; for calling delwatch TSR
  51. endif
  52. BDOS_DATA dseg word
  53. extrn adrive:byte
  54. EXTRN clsize:WORD
  55. extrn diradd:word
  56. extrn dirinroot:word
  57. EXTRN dirperclu:WORD
  58. EXTRN dosfat:WORD
  59. extrn hashroot:dword
  60. extrn hashmax:word
  61. EXTRN info_fcb:BYTE
  62. extrn  lastcl:word
  63. extrn psecsiz:word
  64. eject
  65. hash rw 2 ; hash code work area
  66. ; The dirbcb says what is in the local dirbuf
  67. dirbcb db 0ffh ; drive of dirbuf entry
  68. dirbcb_cl dw 0 ; cluster of dirbuf entry
  69. dirbcb_dcnt dw 0 ; directory index of dirbuf entry
  70. dirbcb_block rw 2 ; block of dirbuf entry
  71. dirbcb_offset dw 0 ; byte offset in block of dirbuf entry
  72. public dirbuf
  73. dirbuf rb 32 ; local directory buffer
  74. public dirp
  75. dirp dw 0 ; directory entry pointer
  76. public dcnt
  77. dcnt dw 0 ; directory index count
  78. public finddfcb_mask
  79. finddfcb_mask dw 0800h ; hi byte = reject DA_VOLUME attribs
  80. ; lo byte = accept non-0 start clusters
  81. ; 00FF = include labels, but not
  82. ; pending deletes
  83. ; 0000 = include everything
  84. public chdblk
  85. chdblk dw 0 ; current cluster # of directory
  86. BDOS_CODE cseg
  87. extrn alloc_cluster:NEAR
  88. extrn clus2sec:near
  89. extrn hdsblk:near ; get current directory block
  90. extrn fdos_error:NEAR
  91. extrn fixfat:NEAR
  92. extrn getnblk:NEAR
  93. extrn locate_buffer:near
  94. extrn update_dir:NEAR
  95. extrn update_fat:NEAR
  96. extrn zeroblk:near
  97. eject
  98. public allocdir
  99. public discard_dirbuf
  100. public finddfcb
  101. public finddfcbf
  102. public fill_dirbuf
  103. public flush_dirbuf
  104. public getdir
  105. public hshdscrd
  106. public mkhsh
  107. public setenddir
  108. eject
  109. ;----------
  110. fill_dirbuf: ;get 32 byte directory entry
  111. ;----------
  112. ; On Entry:
  113. ; AX = cluster to read (0=root)
  114. ; BX = dir within cluster
  115. ; On Exit:
  116. ; DI -> dirbuf entry
  117. call discard_dirbuf ; invalidate block in case of error
  118. mov dirbcb_cl,ax ; remember which cluster
  119. mov dirbcb_dcnt,bx ;  and dir entry we want
  120. test ax,ax ; are we in the root ?
  121.  jz fill_dirbuf10
  122. mov cl,FCBSHF
  123. shl bx,cl ; BX = byte offset in cluster
  124. call clus2sec ; DX:AX -> sector
  125. jmps fill_dirbuf20 ; BX = offset in sector
  126. fill_dirbuf10:
  127. mov ax,FCBLEN
  128. mul bx ; DX:AX = byte offset
  129. div psecsiz ; AX = sector offset, DX = byte offset
  130. mov bx,dx ; BX = byte offset in sector
  131. xor dx,dx
  132. add ax,diradd ; add in start of root dir
  133. adc dx,dx
  134. fill_dirbuf20:
  135. mov dirbcb_block,ax ; we want this sector
  136. mov dirbcb_block+WORD,dx
  137. mov dirbcb_offset,bx
  138. xchg ax,dx ; DX = low word of sector
  139. mov ah,al ; AH = low byte of high word
  140. push bx ; save byte offset in sector
  141. mov cx,0FF00h+BF_ISDIR ; locate directory sector
  142. call locate_buffer ; ES:SI -> BCB_
  143. pop bx ; BX = offset within sector
  144. push es ! pop ds ; DS:SI -> buffer control block
  145. lea si,BCB_DATA[si+bx] ; DS:SI -> data in buffer
  146. push ss ! pop es
  147. mov di,offset dirbuf ; ES:DI -> dir buffer
  148. push di
  149. mov cx,32/WORD ; copy into local buffer
  150. rep movsw
  151. pop di ; DI -> dir buffer
  152. push ss ! pop ds
  153. mov al,adrive ; remember where we are
  154. mov dirbcb,al ;  so we can write it back
  155. ret
  156. ;------------
  157. flush_dirbuf:
  158. ;------------
  159. mov al,0FFh
  160. xchg al,dirbcb ; do we have anything to flush ?
  161. cmp al,adrive
  162.  jne flush_dir20 ; skip if invalid contents
  163. mov si,offset dirbcb_block
  164. lodsw ; get low word of block
  165. xchg ax,dx ; put it in DX where it belongs
  166. lodsw ; get high word of block
  167. mov ah,al ; AH:DX -> block to find
  168. mov cx,0FF00h+BF_ISDIR ; look for directory
  169. call locate_buffer ; locate physical sector
  170. or es:BCB_FLAGS[si],BF_DIRTY; mark this buffer as modified
  171. mov bx,dirbcb_offset ; BX = offset within buffer
  172. lea di,BCB_DATA[si+bx] ; ES:DI -> offset in buffer
  173. mov al,es:[di] ; AL = 1st character of dir entry
  174. mov si,offset dirbuf ; get CP/M buffer address
  175. mov cx,32/WORD
  176. rep movsw ; copy modified entry back
  177. push ax
  178. xor dh,dh ; we only want HCB_ if it's there
  179. mov cx,dirbcb_cl ;  and it's this cluster
  180. call find_hcb ; does an HCB_ exist for this entry ?
  181. pop ax
  182.  jc flush_dir20 ; no, skip update
  183. mov di,dirbcb_dcnt ; we want this dir entry
  184. cmp di,es:HCB_CNT[bx] ; is this within the hashed entries ?
  185.  jae flush_dir20 ;  no, skip the fixup
  186. test al,al ; are we using a never used entry ?
  187.  jnz flush_dir10 ; if so don't trust subsequent hash
  188. inc di ;  codes as they have never been read.
  189. mov es:HCB_CNT[bx],di ; Truncate table to force a read of the
  190. dec di ;  next dir entry (which will normally
  191. flush_dir10: ;  also be never used)
  192. shl di,1 ; DI = offset of hashed entry
  193. lea di,HCB_DATA[bx+di]
  194. mov si,offset dirbuf ; this is the dir entry
  195. call mkhsh ; AX = hash code of our entry
  196. stosw ; update hash code for dir entry
  197. flush_dir20:
  198. push ds ! pop es ; ES = local data segment
  199. ret
  200. ;--------------
  201. discard_dirbuf:
  202. ;--------------
  203. mov dirbcb,0FFh ; invalidate dirbuf
  204. ret
  205. ;--------
  206. rd_pcdir:
  207. ;--------
  208. ; Exit: AX = offset of directory entry
  209. ;    = 0 if end of directory
  210. mov bx,dcnt
  211. inc bx
  212. mov dcnt,bx ; dcnt=dcnt+1
  213. call hdsblk ; AX = current directory block
  214.  jz rd_pcdir40 ; skip if we're at the root
  215. ; we we in a subdirectory - lets follow the chain
  216. xchg ax,cx ; keep subdir cluster in CX
  217. mov ax,FCBLEN ; AX = size of dir entry
  218. mul bx ; DX:AX = offset of set entry we want
  219. div clsize ; AX = # clusters to skip, DX = offset in cluster
  220. xchg ax,dx ; DX = # to skip, AX = offset in cluster
  221. xchg ax,cx ; AX = start of chain, CX = offset in cluster
  222. xchg bx,cx ; BX = offset in cluster, CX = dcnt
  223.  jcxz rd_pcdir20 ; 1st subdir entry, we are already there
  224. mov cx,chdblk ; do we already know where we are ?
  225.  jcxz rd_pcdir10 ;  if not trace from start of chain
  226. xchg ax,cx ; AX = cluster of last dir entry
  227. test bx,bx ; have we moved onto next cluster?
  228.  jnz rd_pcdir20 ; no, trust me..
  229. mov dx,1 ; move on to next entry in the chain
  230. rd_pcdir10:
  231. or dx,dx ; skip along chain until we arrive
  232.  jz rd_pcdir20 ;  at the destination cluster
  233. dec dx
  234. push bx
  235. push dx
  236. call getnblk ; AX = next cluster in chain
  237. pop dx
  238. pop bx
  239. cmp ax,lastcl ; have we fallen off the end of the chain ?
  240.  jbe rd_pcdir10
  241. jmps rd_pcdir30 ; yes, set end of directory
  242. rd_pcdir20:
  243. mov chdblk,ax ; remember this cluster for next time
  244. mov cl,FCBSHF ; to divide by fcb size
  245. shr bx,cl ; BX = dir offset in cluster
  246. jmps rd_pcdir50 ;  now go and find the entry
  247. rd_pcdir30:
  248. call setenddir ; yes, set dcnt to end of directory
  249. jmps rd_pcdir60
  250. rd_pcdir40:
  251. ; we are in the root directory
  252. cmp bx,dirinroot ; end of the root directory ?
  253.  jae rd_pcdir30
  254. rd_pcdir50:
  255. call fill_dirbuf ;locate directory entry
  256. xchg ax,di ; AX -> dir entry
  257. cmp dcnt,ENDDIR
  258.  jnz rd_pcdir70
  259. rd_pcdir60:
  260. xor ax,ax ; return 0 if endofdir
  261. rd_pcdir70:
  262. mov bx,ax
  263. ret
  264. ;---------
  265. setenddir: ;set dcnt to the end of directory (dcnt = 0ffffh)
  266. ;---------
  267. mov dcnt,ENDDIR
  268. mov chdblk,0
  269. ret
  270. chk_wild: ;check fcb for ? marks
  271. ;--------
  272. ; On Entry:
  273. ; bx -> FCB
  274. ; On Exit:
  275. ; ZF set if ? found
  276. ; BX preserved
  277. push ds ! pop es ; ES -> SYSDAT
  278. lea di,byte ptr FNAME[bx] ; ES:DI -> name to scan
  279. mov cx,11
  280. mov al,'?' ; scan for wild cards
  281. repne scasb
  282. ret
  283. eject
  284. eject
  285. ;---------
  286. finddfcbf: ; Find matching directory fcb(dfcb) from beginning of directory
  287. ;---------
  288. call setenddir ; set up for search first
  289. ;--------
  290. finddfcb: ; Find matching directory fcb(dfcb)
  291. ;--------
  292. mov cx,2
  293. ;------
  294. getdir:
  295. ;------
  296. ; entry: CH  = offset info_fcb (always 0 except from rename)
  297. ; CL  =  search length
  298. ; 0 = return next fcb
  299. ; 1 = return empty fcb
  300. ; 2 = find match  (Based on info_fcb)
  301. ; 3 = find match?  Based on info_fcb
  302. ;
  303. ; exit: AX,BX,DIRP = pointer to dfcb
  304. ;      0 = no match (end of directory)
  305. ;      other = offset of requested directory entry
  306. ; ZF = zero flag is set based on AX
  307. ;
  308. ; Note: The most common call for this function is with CX =
  309. ; 2 (match with name, not extent)  with 'dcnt' set to
  310. ; 0FFFFh  (search  from  beginning  of the  directory
  311. ; (e.g.   open,  create,   delate,   rename,   etc.).
  312. ; Therefore  we try  to optimize  directory  searches
  313. ; using a dynamic hash table...
  314. ;struct dirfcb *getdir(offset,srchl);
  315. cmp dcnt,0FFFFh ;if ((dcnt == 0xffff) &&
  316.  jne gtd_next
  317. mov hash+2,cx ; Save off calling option
  318. xor ax,ax ; hash code 0 for free entry
  319. cmp cx,1 ; what kind of search?
  320.  je gtdo15 ; CL=1: find free entry (AX=0)
  321.  jb gtd_next ; CL=0: find any entry (unhashed)
  322. or ch,ch ; name in INFO_FCB+1?
  323.  jnz gtd_next ; no, unhashed search
  324. mov bx,offset info_fcb
  325. call chk_wild ; wildcards used in search?
  326.  jz unhshd1 ; yes, can't use hashing
  327. mov si,offset info_fcb+1 ; else compute hash code
  328. call mkhsh ;    for name to find
  329. gtdo15:
  330. mov hash,ax ; save it for search
  331. call hdsblk ; get directory block
  332. gtdo3:
  333. push ax ; save dir block for later
  334. call hashsrch ; try and use hashing to find a match
  335.  jnc gtdo4 ; look closer if we get possible match
  336. add dcnt,ax ;  else skip known non-matches
  337. pop ax ; recover current dir block
  338. test ax,ax ; if we are in the root
  339.  jz unhashed ;  we must search the hard way
  340. xchg ax,bx
  341. mov ax,dcnt ; should we go onto next cluster ?
  342. inc ax ; only if next entry is the start
  343. xor dx,dx ;  of a cluster
  344. div dirperclu
  345. xchg ax,bx
  346. test dx,dx ; at start of cluster ?
  347.  jnz unhashed
  348. call getnblk ; onto next cluster until we are
  349. cmp ax,lastcl ;  at the end of the chain
  350.  jbe gtdo3
  351. jmps unhashed ; out of luck
  352. gtdo4:
  353. add dcnt,ax ; we have found a match, so start
  354. pop ax ;  search here
  355. ; jmps unhashed
  356. unhashed: ;   /* locate entry */
  357. mov chdblk,0
  358. unhshd1:
  359. mov cx,hash+2 ;}
  360. gtd_next:
  361. ;--------
  362. push cx
  363. call rd_pcdir ; Get Next DFCB
  364. pop cx
  365. gtd_exit:
  366. mov dirp,ax ; assume this is the one
  367. mov bx,ax
  368. or ax,ax ; should we exit with not found ?
  369.  jz gtd2
  370. cmp cl,NEXT ; Caller wishes next dfcb?
  371.  jne gtd3 ; NO
  372. gtd2:
  373. mov ax,bx ; return BX (DIRP or NULLPTR)
  374. or ax,ax ; return ZF (1 = not found)
  375. ret
  376. gtd3:
  377. cmp cl,EMPTY ; Caller wishes an empty dfcb?
  378.  jne gtd4 ; NO
  379. mov al,DNAME[bx] ; Get directory type
  380. or al,al ; Is it free?
  381.  jz gtd2 ; YES (00 -> never used)
  382. cmp al,0E5h ; Is the dfcb empty?
  383.  je gtd2 ; YES  (E5 -> erased)
  384. jmps gtd_next ; NO, try the next
  385. gtd4: ; looking for particular entry
  386. call hdsblk ; Are we at the root?
  387.  jnz gtd5 ; skip if not
  388. mov ax,dcnt ; check for end of directory
  389. cmp ax,dirinroot ; have we reached end of root?
  390. mov ax,0 ; assume we have
  391.  jae gtd_exit ; exit if we have
  392. gtd5:
  393. mov al,DNAME[bx] ; Get dfcb type
  394. cbw
  395. or ax,ax ; Are we at End Of Directory(EOD)
  396.  jz gtd_exit ; YES
  397. cmp al,0E5h ; Is this a free fcb?
  398.  je gtd_next ; Yes, try again
  399. mov ax,finddfcb_mask ; do we want labels/pending deletes
  400. test DATTS[bx],ah ; filter out volume labels?
  401.  jnz gtd_next ;  we normally reject them
  402. if DELWATCH
  403. cbw ; we want labels - do we want
  404. test word ptr DBLOCK1[bx],ax ;  DELWATCH pending deletes
  405.  jnz gtd_next ;  ie. labels with fat chain
  406. endif
  407. push cx ; we are interested - but does
  408. mov al,ch ;  the name match ?
  409. cbw
  410. add ax,offset info_fcb+1
  411. xor si,si ; we want SI = entry to match and
  412. xchg ax,si ;   AL = 0 indicating assumed match
  413. mov cx,11 ; 11 chars in filename
  414. mov di,bx ; ES:DI -> directory entry
  415. match3:
  416.  jcxz match4 ; stop if we have done all 11
  417. repe cmpsb ; compare if 11 bytes the same
  418.  je match4 ;  skip if all bytes the same
  419. cmp byte ptr 0-1[si],'?' ; else was INFO_FCB byte = '?'
  420.  je match3 ;  in that case it matches too
  421. inc ax ; else we didn't match (AL<>0)
  422. match4:
  423. pop cx
  424. or al,al ; did we match ?
  425.  jnz gtd_next ; no, try for another
  426. mov bx,dirp ; Return (BX)
  427. jmp gtd2
  428. eject
  429. find_hcb: ; find HCB_ for given drive
  430. ;--------
  431. ; On Entry:
  432. ; CX = cluster we are looking for
  433. ; DH = 00 if exact match required
  434. ;      FF if we want to recyle oldest HCB_
  435. ; On Exit:
  436. ; CY set, AX=0 if HCB_ not found
  437. ; CY clear ES:BX = offset of HCB_ (moved to head of list)
  438. ; (AX/DX trashed, All other regs preserved)
  439. ;
  440. les bx,hashroot ; get our hashing pointer
  441. mov ax,es
  442. or ax,bx ; is hashing enabled ?
  443.  jz find_hcb30
  444. mov dl,adrive ; look for this drive
  445. cmp cx,es:HCB_CLU[bx] ; does cluster match?
  446.  jne find_hcb10 ; goto next if not
  447. cmp dl,es:HCB_DRV[bx] ; does drive match?
  448.  jne find_hcb10 ; goto next if not
  449. ; clc
  450. ret ; we have a match on the 1st one
  451. find_hcb10:
  452. ; no match, so look futher along the chain
  453. mov ax,es:HCB_LINK[bx] ; onto the next entry
  454. test ax,ax ; is there one ?
  455.  jz find_hcb20
  456. xchg ax,bx ; AX = previous entry, BX = current
  457. cmp cx,es:HCB_CLU[bx] ; does cluster match?
  458.  jne find_hcb10 ; goto next if not
  459. cmp dl,es:HCB_DRV[bx] ; does drive match?
  460.  jne find_hcb10 ; goto next if not
  461. ; we have a match, but it's not the first so recycle it
  462. mov dx,es:HCB_LINK[bx] ; get link to the rest of the chain
  463. xchg ax,bx ; BX = previous entry
  464. mov es:HCB_LINK[bx],dx ; unlink ourselves from chain
  465. mov bx,ax ; BX = current entry
  466. xchg ax,word ptr hashroot ; put current entry at the head
  467. mov es:HCB_LINK[bx],ax ;  and relink the rest of the chain
  468. ; clc
  469. ret
  470. find_hcb20:
  471. ; we have been all along the chain with no luck
  472. xor ax,ax
  473. test dh,dh ; no HCB_ - do we want to recyle ?
  474.  jz find_hcb30 ;  if not skip
  475. mov es:HCB_CNT[bx],ax ; we need to recycle oldest HCB_
  476. mov es:HCB_CLU[bx],cx ;  so mark as us, but with nothing
  477. mov es:HCB_DRV[bx],dl ;  in it
  478. ; clc
  479. ret
  480. find_hcb30:
  481. stc ; return failure
  482. ret
  483. eject
  484. ;-----
  485. mkhsh:
  486. ;-----
  487. ;
  488. ; entry: SI = 11 byte FCB to convert to hash code
  489. ; exit: AX = 1..FFFF is hash code (00/E5 == 0)
  490. ; uses: DX
  491. ; saves: BX,CX,DI,BP
  492. ;
  493. ; used for hashing the INFO_FCB &
  494. ; directory entries for DOS media
  495. xor dx,dx ;assume hash code is 0000
  496. lodsb
  497. cmp al,0E5h ;if deleted file
  498.  je mkhsh2 ;   or
  499. cmp al,0 ;if virgin entry
  500.  je mkhsh2 ;then hash code = 0;
  501. push cx ;else save CX
  502. and al,7fh
  503. mov dh,al ;initialize hash code MSB
  504. mov cx,10 ;involve other 10 characters
  505. mkhsh1:
  506. lodsb ;get next character
  507. rol dx,1 ;rotate hash code by one bit
  508. and al,7fh ;strip top bit off character
  509. xor dl,al ;XOR the character into the hash code
  510. loop mkhsh1 ;repeat for all characters
  511. pop cx ;restore CX
  512. test dx,dx ;test if zero by any chance
  513.  jnz mkhsh2 ;skip if non-zero
  514. inc dx ;else force it to 1
  515. mkhsh2: ;return hash code in AX
  516. xchg ax,dx
  517. ret
  518. eject
  519. if DELWATCH
  520. Public fixup_hashing
  521. ;
  522. ; update hashing for current drive if DELWATCH changes a directory entry
  523. ;
  524. fixup_hashing:
  525. ;-------------
  526. ; On Entry:
  527. ; AX = segment of dir buffer
  528. ; CX = cluster to fixup (0 = root)
  529. ; DI = directory entry index (clipped to cluster if subdir)
  530. ; AX:SI-> dir entry (single entry for hashing)
  531. ;
  532. ; On Exit:
  533. ; None
  534. ;
  535. push ds
  536. push es
  537. xor dh,dh ; we only want HCB_ if it's there
  538. push ax ; save seg of dir entry
  539. call find_hcb ; does an HCB_ exist for this entry ?
  540. pop ds ; DS:SI -> entry to hash
  541.  jc fixup_ck10 ; not hashed, skip update
  542. cmp di,es:HCB_CNT[bx] ; is this within the hashed entries ?
  543.  jae fixup_ck10 ;  no, skip the fixup
  544. call mkhsh ; AX = hash code of our entry
  545. shl di,1 ; DI = offset of hashed entry
  546. lea di,HCB_DATA[bx+di]
  547. stosw ; update hash code for dir entry
  548. fixup_ck10:
  549. pop es
  550. pop ds
  551. ret ; no
  552. endif
  553. eject
  554. hashsrch:
  555. ;--------
  556. ; entry: AX = starting cluster of directory
  557. ; exit: AX is possible match index
  558. ;
  559. mov dh,0FFh ; we want HCB_ even if it's recycled
  560. xchg ax,cx ;  and this block
  561. call find_hcb ; does an HCB_ exist for this entry ?
  562. ; mov ax,0 ; assume unhashed search required
  563.  jc hashsrch20 ;  start one if no hashing
  564. hashsrch10:
  565. mov cx,es:HCB_CNT[bx] ; we have this many entries hashed
  566.  jcxz hashsrch30 ; skip if nothing hashed yet
  567. mov ax,hash ; look for this hash code
  568. lea di,HCB_DATA[bx] ; DI = offset of start of search
  569. repne scasw ; try to find a match
  570.  jne hashsrch30 ; skip if no match found
  571. lea ax,HCB_DATA+2[bx] ; find word offset of match
  572. xchg ax,di ; return matching index
  573. sub ax,di
  574. shr ax,1 ; make dir offset
  575. hashsrch20:
  576. push ds ! pop es
  577. clc ; we have found it
  578. ret
  579. hashsrch30:
  580. call rehash_entry ; try and hash another entry
  581.  jnc hashsrch10 ;  look again if we succeeded
  582. mov ax,es:HCB_CNT[bx] ; failure, so return # to skip
  583. push ds ! pop es
  584. ; stc ;  for quicker search
  585. ret
  586. rehash_entry:
  587. ;------------
  588. ; entry: ES:BX -> HCB
  589. ; AX = hash cluster number
  590. call hash_entries_to_do ; how many entries still to hash ?
  591.  jcxz rehash_entry40 ; if we have hashed them all exit
  592. push dcnt ; save directory count
  593. mov ax,dcnt ; get previous position
  594. inc ax ; we start looking here
  595. xor dx,dx
  596. div dirperclu ; mask to start of cluster
  597. mul dirperclu
  598. add ax,es:HCB_CNT[bx] ; skip entries we already have
  599. dec ax ; make previous entry BEFORE this
  600. mov dcnt,ax
  601. mov chdblk,0 ; non-sequential access
  602. cmp cx,512/32 ; don't try reading more than 512 bytes
  603.  jb rehash_entry20 ;  at a time - then with 512 byte secs
  604. mov cx,512/32 ;  we only read when we
  605. rehash_entry20:
  606. push es
  607. push bx ; save hash control pointer
  608. push cx ; save # entries to do
  609. push ds ! pop es ; back to small model
  610. xor cx,cx ; return any entry
  611. call gtd_next ; unhashed search
  612. pop cx ; restore # entries to do
  613. pop bx ; restore hash control pointer
  614. pop es
  615. test ax,ax ; anything found
  616.  jz rehash_entry30 ; end of directory
  617. xchg ax,si ; else get directory pointer
  618. mov di,es:HCB_CNT[bx]
  619. shl di,1 ; DI -> 1st new entry
  620. lea di,HCB_DATA[bx+di]
  621. push si
  622. call mkhsh ; else calculate hash into AX
  623. stosw ; add it to hash table
  624. inc es:HCB_CNT[bx] ; remember we did
  625. pop si
  626. lodsb ; get 1st byte of hashed entry
  627. test al,al ; is it zero (ie. never used)?
  628. loopne rehash_entry20 ; get all hash codes
  629.  jcxz rehash_entry30 ; all done ?
  630. call hash_entries_to_do ; how many entries still to hash ?
  631. add es:HCB_CNT[bx],cx ;  we will do them all..
  632. rep stosw ; zap rest of cluster
  633. rehash_entry30:
  634. pop dcnt ; restore count
  635. mov chdblk,0 ; non-sequential access
  636. clc ; we have new hashing codes
  637. ret ; HCB updated with new cluster
  638. rehash_entry40:
  639. stc ; cannot hash no more...
  640. ret
  641. hash_entries_to_do:
  642. ;------------------
  643. ; On Entry:
  644. ; ES:BX -> HCB_
  645. ; On Exit:
  646. ; CX = maximum possible entries we still need to hash for HCB_
  647. ; (All other regs preserved)
  648. ;
  649. mov cx,dirinroot ; assume root dir
  650. cmp es:HCB_CLU[bx],0 ; was it ?
  651.  je hash_etd10
  652. mov cx,dirperclu ; subdir, so cluster limit
  653. hash_etd10:
  654. cmp cx,hashmax ; do we support this many ?
  655.  jb hash_etd20 ;   yes, skip it
  656. mov cx,hashmax ; else limit it to this many
  657. hash_etd20:
  658. sub cx,es:HCB_CNT[bx] ; subtract number we have already done
  659. ret
  660. eject
  661. hshdscrd:
  662. ;--------
  663. ; purge hash blocks for physical drive
  664. ; On Entry:
  665. ; AL = drive to discard (FF = all drives)
  666. ; On Exit:
  667. ; None (All regs preserved)
  668. push ds
  669. push bx
  670. lds bx,hashroot ; get root of hash codes
  671. hshdsc1:
  672. test bx,bx
  673.  jz hshdsc4 ; all blocks done
  674. cmp al,0FFh ; FF means discard all drives
  675.  je hshdsc2
  676. cmp al,ds:HCB_DRV[bx] ; check if matching drive
  677.  jne hshdsc3
  678. hshdsc2:
  679. mov ds:HCB_DRV[bx],0ffh ; h->hd = 0xff;
  680. hshdsc3:
  681. mov bx,ds:HCB_LINK[bx] ; get next hash code block
  682. jmps hshdsc1
  683. hshdsc4:
  684. pop bx
  685. pop ds
  686. ret
  687. eject
  688. enlarge_root:
  689. if DELWATCH
  690. mov ah,DELW_FREERD ; lets ask DELWATCH if it can
  691. mov al,adrive ; free a root directory entry
  692. callf ss:fdos_stub ;  for this drive
  693.  jnc allocdir ; it says it has so try again
  694. endif
  695. allocdir_err:
  696. pop ax ; discard return address
  697. mov ax,ED_MAKE
  698. jmp fdos_error ; return "cannot make dir entry"
  699. ;--------
  700. allocdir: ; Called by rename and MAKE
  701. ;--------
  702. call setenddir ; search for first match
  703. mov cx,1 ; return empty fcb
  704. call getdir ; is there an empty fcb?
  705.  jz allocdir10 ; if so use that
  706. ret
  707. allocdir10:
  708. call hdsblk ; Are we at the root?
  709.  jz enlarge_root ; YES -- Report error(no room)
  710. ; We are in a subdirectory so enlarge it
  711. ; AX has 1st block of subdirectory   NOTE -- AX is never
  712. ; above 'lastcl' on entry.
  713. allocdir20:
  714. cmp ax,lastcl ; Are we at end of subdirectory?
  715.  ja allocdir30 ; YES
  716. push ax
  717. call getnblk ; NO -- get next block then
  718.         pop bx
  719. jmps allocdir20
  720. allocdir30:
  721. push bx ; save last block number
  722. xchg ax,bx ; Get a new block (start from old)
  723. call alloc_cluster
  724. pop bx
  725.  jc allocdir_err ; Report Error(no room on disk)
  726. push ax ; save new block
  727. xchg ax,bx
  728. call fixfat ; Update fat (AX,BX) old last block
  729. ;  points to new last block
  730. pop ax ; Get new last block
  731. push ax
  732. mov bx,dosfat ; 12 or 16 bit fat
  733. call fixfat ; Update fat (AX,BX)  new last block
  734. ;  has end of cluster marker
  735. call update_fat ; Write out to disk
  736. pop ax ; Get new last block
  737. call zeroblk ; Zero it out
  738.         call setenddir ; Set up for search first
  739. mov cx,1 ; Find empty fcb
  740. jmp getdir ; Can not return with not found error
  741. END