Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1022 lines
27 KiB

  1. /*****************************************************************************
  2. * *
  3. * FILESYS.C *
  4. * *
  5. * Copyright (C) Microsoft Corporation 1995. *
  6. * All Rights reserved. *
  7. * *
  8. ******************************************************************************
  9. * *
  10. * Module Intent *
  11. * *
  12. * All main File System commands (opening, closing) *
  13. * any given offset, or in a temp file. *
  14. * *
  15. ******************************************************************************
  16. * *
  17. * Current Owner: davej *
  18. *****************************************************************************/
  19. /*****************************************************************************
  20. *
  21. * Created 07/17/95 - davej
  22. * 3/05/97 erinfox Change errors to HRESULTS
  23. *
  24. *****************************************************************************/
  25. static char s_aszModule[] = __FILE__; /* For error report */
  26. #include <mvopsys.h>
  27. #include <iterror.h>
  28. #include <orkin.h>
  29. #include <misc.h>
  30. #include <wrapstor.h>
  31. #include <_mvutil.h>
  32. /*****************************************************************************
  33. * *
  34. * Defines *
  35. * *
  36. *****************************************************************************/
  37. /*****************************************************************************
  38. * *
  39. * Prototypes *
  40. * *
  41. *****************************************************************************/
  42. /***************************************************************************
  43. * *
  44. * Private Functions *
  45. * *
  46. ***************************************************************************/
  47. // FACCESS_READWRITE
  48. // FACCESS_READ
  49. BOOL PASCAL FAR FHfsAccess(HFS hfs, BYTE bFlags)
  50. {
  51. QFSHR qfshr;
  52. BOOL bHasAccess=FALSE;
  53. if (hfs == NULL || (qfshr = _GLOBALLOCK(hfs)) == NULL)
  54. {
  55. return FALSE;
  56. }
  57. if ((qfshr->fsh.bFlags&FSH_READWRITE) && (bFlags&FACCESS_READWRITE))
  58. bHasAccess=TRUE;
  59. if (bFlags&FACCESS_READ)
  60. bHasAccess=TRUE;
  61. _GLOBALUNLOCK(hfs);
  62. return bHasAccess;
  63. }
  64. /***************************************************************************
  65. *
  66. * @doc PRIVATE
  67. *
  68. * @func HFS PASCAL NEAR | HfsOpenFileSysFmInternal |
  69. * Open or Create a file system
  70. *
  71. * @parm FM | fmFileName |
  72. * File name of file system to open or create (FM is identical to LPSTR)
  73. *
  74. * @parm BYTE | bFlags |
  75. * Combinations of the FSH_ flags
  76. * @flag FSH_READWRITE | (0x01) FS will be updated
  77. * @flag FSH_READONLY | (0x02) FS will be read only, no updating
  78. * @flag FSH_CREATE | (0x04) Create a new FS
  79. * @flag FSH_M14 | (0x08) Not used really, since we return
  80. * @flag FSH_FASTUPDATE | (0x10) System Btree is not copied to temp file
  81. * unless absolutely necessary
  82. * @flag FSH_DISKBTREE | (0x20) System Btree is always copied to disk if
  83. * possible for speed. Btree may be very very
  84. * large, and this is NOT recommended for on-line
  85. *
  86. * @parm FS_PARAMS FAR * | lpfsp |
  87. * File system initialization parameters (currently btree block size)
  88. *
  89. * @parm PHRESULT | lpErrb |
  90. * Error return
  91. *
  92. * @rdesc Returns a valid HFS or NULL if an error.
  93. *
  94. ***************************************************************************/
  95. HFS PASCAL NEAR HfsOpenFileSysFmInternal(FM fm,
  96. BYTE bFlags, FS_PARAMS FAR *qfsp, PHRESULT phr)
  97. {
  98. #ifdef MOSMAP // {
  99. // Disable function
  100. if (bFlags&(FSH_CREATE|FSH_READWRITE))
  101. {
  102. SetErrCode (phr, ERR_NOTSUPPORTED);
  103. return NULL;
  104. }
  105. #else // } {
  106. HFS hfs;
  107. QFSHR qfshr;
  108. BTREE_PARAMS btp;
  109. /* make file system header */
  110. if (( hfs = _GLOBALALLOC(GMEM_ZEROINIT|GMEM_SHARE| GMEM_MOVEABLE,
  111. (LONG)sizeof( FSHR) ) ) == NULL )
  112. {
  113. SetErrCode (phr, E_OUTOFMEMORY);
  114. return NULL;
  115. }
  116. qfshr = _GLOBALLOCK(hfs);
  117. _INITIALIZECRITICALSECTION(&qfshr->cs);
  118. // Copy File Moniker
  119. if ((qfshr->fm = FmCopyFm(fm, phr)) == fmNil)
  120. {
  121. SetErrCode(phr,E_OUTOFMEMORY);
  122. exit0:
  123. _DELETECRITICALSECTION(&qfshr->cs);
  124. _GLOBALUNLOCK(hfs);
  125. _GLOBALFREE(hfs);
  126. return 0;
  127. }
  128. // Open or Create fid
  129. if (bFlags&FSH_CREATE)
  130. qfshr->fid = FidCreateFm(qfshr->fm, wReadWrite, wReadWrite, phr);
  131. else
  132. qfshr->fid = FidOpenFm(qfshr->fm,
  133. (WORD)((bFlags & FSH_READONLY)?(wReadOnly | wShareRead) : (wReadWrite | wShareNone)), phr);
  134. if (qfshr->fid == fidNil)
  135. {
  136. exit1:
  137. //FreeListDestroy(qfshr->hfl);
  138. SetErrCode(phr,E_NOPERMISSION);
  139. DisposeFm(qfshr->fm);
  140. goto exit0;
  141. }
  142. qfshr->hsfbFirst=NULL;
  143. qfshr->hsfbSystem=NULL;
  144. // Initialize global SubFile header blocks array - shared by everyone :-)
  145. // So we take multi-threading precautions
  146. if (!_INTERLOCKEDINCREMENT(&mv_gsfa_count))
  147. {
  148. HANDLE hSfa;
  149. mv_gsfa_count=1L;
  150. mv_gsfa=NULL;
  151. _INITIALIZECRITICALSECTION(&mv_gsfa_cs);
  152. if (((hSfa=_GLOBALALLOC(GMEM_ZEROINIT|GMEM_MOVEABLE|GMEM_SHARE,sizeof(SF)*MAXSUBFILES))==NULL) ||
  153. ((mv_gsfa=(SF FAR *)_GLOBALLOCK(hSfa))==NULL))
  154. {
  155. if (hSfa)
  156. _GLOBALFREE(hSfa);
  157. SetErrCode (phr, E_OUTOFMEMORY);
  158. exit2:
  159. if (!(_INTERLOCKEDDECREMENT(&mv_gsfa_count)))
  160. {
  161. if (mv_gsfa)
  162. {
  163. _GLOBALUNLOCK(GlobalHandle(mv_gsfa));
  164. _GLOBALFREE(GlobalHandle(mv_gsfa));
  165. mv_gsfa=NULL;
  166. }
  167. _DELETECRITICALSECTION(&mv_gsfa_cs);
  168. mv_gsfa_count=-1L;
  169. }
  170. goto exit1;
  171. }
  172. mv_gsfa[0].hsfb=(HSFB)-1;
  173. }
  174. if (bFlags&(FSH_READWRITE|FSH_DISKBTREE))
  175. {
  176. // If we are ambitious, we can try lower scratch sizes, but if we are that low
  177. // on memory, chances are we are just going to fail a few steps from here.
  178. HANDLE hBuf;
  179. if (!(hBuf=_GLOBALALLOC(GMEM_ZEROINIT|GMEM_MOVEABLE|GMEM_SHARE,(DWORD)SCRATCHBUFSIZE)))
  180. {
  181. SetErrCode(phr, E_OUTOFMEMORY);
  182. goto exit2;
  183. }
  184. if (!(qfshr->sb.lpvBuffer=_GLOBALLOCK(hBuf)))
  185. {
  186. _GLOBALFREE(hBuf);
  187. goto exit2;
  188. }
  189. qfshr->sb.lcbBuffer=(LONG)SCRATCHBUFSIZE;
  190. _INITIALIZECRITICALSECTION(&qfshr->sb.cs);
  191. }
  192. if (!(bFlags&FSH_CREATE))
  193. {
  194. BYTE bFlagsBtree=0L;
  195. if ((LcbReadFid(qfshr->fid, &qfshr->fsh,(LONG)sizeof(FSH),
  196. phr)) != (LONG)sizeof(FSH))
  197. {
  198. SetErrCode (phr, E_FILEINVALID);
  199. exit3:
  200. if (bFlags&(FSH_READWRITE|FSH_DISKBTREE))
  201. _DELETECRITICALSECTION(&qfshr->sb.cs);
  202. if (qfshr->sb.lpvBuffer)
  203. {
  204. if (!(bFlags&(FSH_READWRITE|FSH_DISKBTREE)))
  205. _DELETECRITICALSECTION(&qfshr->sb.cs);
  206. _GLOBALUNLOCK(GlobalHandle(qfshr->sb.lpvBuffer));
  207. _GLOBALFREE(GlobalHandle(qfshr->sb.lpvBuffer));
  208. }
  209. RcCloseFid(qfshr->fid);
  210. if (bFlags&FSH_CREATE)
  211. RcUnlinkFm(qfshr->fm);
  212. goto exit2;
  213. }
  214. /* Handle MAC swapping */
  215. if (qfshr->fsh.wMagic == SWAPWORD(wFileSysMagic))
  216. {
  217. qfshr->fsh.wMagic = SWAPWORD(qfshr->fsh.wMagic);
  218. qfshr->fsh.foDirectory.dwOffset = SWAPLONG(qfshr->fsh.foDirectory.dwOffset);
  219. qfshr->fsh.foDirectory.dwHigh = SWAPLONG(qfshr->fsh.foDirectory.dwHigh);
  220. qfshr->fsh.foFreeList.dwOffset = SWAPLONG(qfshr->fsh.foFreeList.dwOffset);
  221. qfshr->fsh.foFreeList.dwHigh = SWAPLONG(qfshr->fsh.foFreeList.dwHigh);
  222. qfshr->fsh.foEof.dwOffset = SWAPLONG(qfshr->fsh.foEof.dwOffset);
  223. qfshr->fsh.foEof.dwHigh = SWAPLONG(qfshr->fsh.foEof.dwHigh);
  224. }
  225. qfshr->fsh.bFlags=(qfshr->fsh.bFlags&(~(FSH_READWRITE|FSH_READONLY)))|bFlags;
  226. if (qfshr->fsh.wMagic != wFileSysMagic)
  227. {
  228. SetErrCode (phr, E_FILEINVALID);
  229. goto exit3;
  230. }
  231. if (qfshr->fsh.bVersion != bFileSysVersion)
  232. {
  233. if (qfshr->fsh.bVersion == bFileSysVersionOld)
  234. {
  235. qfshr->fsh.bFlags|=FSH_M14;
  236. SetErrCode(phr, E_BADVERSION); // Try another error specially for M14?
  237. goto exit3;
  238. }
  239. else
  240. {
  241. SetErrCode(phr, E_BADVERSION);
  242. goto exit3;
  243. }
  244. }
  245. // Open Free List if r/w mode
  246. if (bFlags&FSH_READWRITE)
  247. {
  248. if ((!FoEquals(FoSeekFid(qfshr->fid,qfshr->fsh.foFreeList,wSeekSet,
  249. phr),qfshr->fsh.foFreeList)) ||
  250. ((qfshr->hfl=FreeListInitFromFid( qfshr->fid, phr ))==NULL))
  251. {
  252. goto exit3;
  253. }
  254. }
  255. // Open Btree making temp file for btree
  256. //if ((qfshr->hbt = HbtOpenBtreeSz(NULL, hfs,
  257. // (BYTE)((qfshr->fsh.bFlags&FSH_READONLY?HFOPEN_READ:HFOPEN_READWRITE)|HFOPEN_SYSTEM),
  258. // NULL, phr)) == NULL)
  259. // Open Btree, temp only gets made if necessary
  260. bFlagsBtree|=HFOPEN_SYSTEM;
  261. if (qfshr->fsh.bFlags&FSH_READONLY)
  262. {
  263. bFlagsBtree|=HFOPEN_READ;
  264. if (qfshr->fsh.bFlags&FSH_DISKBTREE)
  265. bFlagsBtree|=HFOPEN_FORCETEMP;
  266. }
  267. else
  268. {
  269. bFlagsBtree|=HFOPEN_READWRITE;
  270. if (qfshr->fsh.bFlags&FSH_FASTUPDATE)
  271. bFlagsBtree|=HFOPEN_NOTEMP;
  272. }
  273. //if ((qfshr->hbt = HbtOpenBtreeSz(NULL, hfs,
  274. // (BYTE)((qfshr->fsh.bFlags&FSH_READONLY?HFOPEN_READ:
  275. // ((qfshr->fsh.bFlags&FSH_FASTUPDATE)?HFOPEN_NOTEMP:0)|HFOPEN_READWRITE)|
  276. // HFOPEN_SYSTEM),
  277. // NULL, phr)) == NULL)
  278. if ((qfshr->hbt = HbtOpenBtreeSz(NULL, hfs, bFlagsBtree, phr))==NULL)
  279. {
  280. exit4:
  281. if (qfshr->hfl)
  282. FreeListDestroy(qfshr->hfl);
  283. goto exit3;
  284. }
  285. }
  286. else
  287. {
  288. WORD wFreeListSize = wDefaultFreeListSize;
  289. if ((qfsp) && (qfsp->wFreeListSize))
  290. wFreeListSize = qfsp->wFreeListSize;
  291. qfshr->fsh.wMagic = wFileSysMagic;
  292. qfshr->fsh.bVersion = bFileSysVersion;
  293. qfshr->fsh.bFlags = FSH_READWRITE;
  294. qfshr->fsh.foFreeList.dwOffset = sizeof(FSH); // Free list directly after header
  295. qfshr->fsh.foFreeList.dwHigh = 0L;
  296. qfshr->fsh.foDirectory = foNil; // Filled in with system file start
  297. if (bFlags&FSH_READWRITE)
  298. { if ((qfshr->hfl=FreeListInit(wFreeListSize, phr))==NULL)
  299. {
  300. goto exit3;
  301. }
  302. }
  303. qfshr->fsh.foEof.dwOffset = sizeof(FSH)+FreeListSize(qfshr->hfl,phr); // Free starts here
  304. qfshr->fsh.foEof.dwHigh = 0L;
  305. /* build btree directory */
  306. btp.hfs = hfs;
  307. btp.bFlags = HFOPEN_READWRITE|HFOPEN_SYSTEM;
  308. if (qfsp != NULL)
  309. {
  310. btp.cbBlock = qfsp->cbBlock;
  311. }
  312. else
  313. {
  314. btp.cbBlock = cbBtreeBlockDefault;
  315. }
  316. lstrcpy(btp.rgchFormat, "VOO1"); // "VY", KT_VSTI, FMT_VNUM_FO, FMT_VNUM_LCB, file byte // 'VOL1' works too
  317. qfshr->hbt = HbtCreateBtreeSz(NULL, &btp, phr);
  318. if (qfshr->hbt == NULL)
  319. {
  320. goto exit4;
  321. }
  322. }
  323. // NO harm writing out file system file so far (???)
  324. //LSeekFid(qfshr->fid, 0L, wSeekSet, phr);
  325. //LcbWriteFid(qfshr->fid, &qfshr->fsh, sizeof(FSH), phr);
  326. //Lcb ... also no need to write it out yet!
  327. /* return handle to file system */
  328. _GLOBALUNLOCK(hfs);
  329. return hfs;
  330. #endif //}
  331. }
  332. /***************************************************************************
  333. *
  334. * @doc INTERNAL API
  335. *
  336. * @func HFS PASCAL FAR | HfsCreateFileSysFm |
  337. * Creates a new file system
  338. *
  339. * @parm FM | fmFileName |
  340. * File name of file system to open or create (FM is same as LPSTR)
  341. *
  342. * @parm FS_PARAMS FAR * | lpfsp |
  343. * File system initialization parameters (currently btree block size)
  344. *
  345. * @parm PHRESULT | lpErrb |
  346. * Error return
  347. *
  348. * @rdesc Returns a valid HFS or NULL if an error.
  349. *
  350. ***************************************************************************/
  351. PUBLIC HFS PASCAL FAR EXPORT_API HfsCreateFileSysFm(FM fm,
  352. FS_PARAMS FAR *qfsp, PHRESULT phr)
  353. {
  354. return HfsOpenFileSysFmInternal(fm,FSH_CREATE|FSH_READWRITE,qfsp,phr);
  355. }
  356. /***************************************************************************
  357. *
  358. * @doc INTERNAL API
  359. *
  360. * @func HFS PASCAL FAR | HfsOpenFm |
  361. * Open an existing file system
  362. *
  363. * @parm FM | fmFileName |
  364. * File name of file system to open (FM is same as LPSTR)
  365. *
  366. * @parm BYTE | bFlags |
  367. * Any of the FSH_ flags
  368. * @flag FSH_READWRITE | (BYTE)0x01 FS will be updated
  369. * @flag FSH_READONLY | (BYTE)0x02 FS will be read only, no updating
  370. * @flag FSH_M14 | (BYTE)0x08 Not used really, since we return
  371. * @flag FSH_FASTUPDATE | (BYTE)0x10 System Btree is not copied to temp file
  372. * unless absolutely necessary
  373. * @flag FSH_DISKBTREE | (BYTE)0x20 System Btree is always copied to disk if
  374. * possible for speed. Btree may be very very
  375. * large, and this is NOT recommended for on-line
  376. *
  377. * @parm PHRESULT | lpErrb |
  378. * Error return
  379. *
  380. * @rdesc Returns a valid HFS or NULL if an error.
  381. *
  382. ***************************************************************************/
  383. PUBLIC HFS PASCAL FAR EXPORT_API HfsOpenFm(FM fm, BYTE bFlags,
  384. PHRESULT phr)
  385. {
  386. if (bFlags&FSH_CREATE)
  387. {
  388. SetErrCode(phr, E_INVALIDARG);
  389. return NULL;
  390. }
  391. return HfsOpenFileSysFmInternal(fm,bFlags,NULL,phr);
  392. }
  393. /***************************************************************************
  394. *
  395. * @doc INTERNAL API
  396. *
  397. * @func HRESULT PASCAL FAR | RcCloseHfs |
  398. * Close an opened File System
  399. *
  400. * @parm HFS | hfs |
  401. * Handle of opened file system
  402. *
  403. * @rdesc Returns S_OK if closed OK, else an error
  404. *
  405. * @comm
  406. * state IN:
  407. * state OUT:
  408. * Notes:
  409. *
  410. ***************************************************************************/
  411. HRESULT PASCAL FAR RcCloseHfs(HFS hfs)
  412. {
  413. QFSHR qfshr;
  414. HRESULT errb;
  415. if (hfs == NULL || (qfshr = _GLOBALLOCK(hfs)) == NULL)
  416. {
  417. return(E_INVALIDARG);
  418. }
  419. if (!mv_gsfa_count)
  420. return E_ASSERT;
  421. _ENTERCRITICALSECTION(&qfshr->cs);
  422. // We need to:
  423. // (1) close all subfiles if any open
  424. // (2) close the btree
  425. // (3) r/w write free list
  426. // (4) r/w write header
  427. RcCloseEveryHf(hfs);
  428. //while (qfshr->hsfbFirst)
  429. //{
  430. // qfshr->hsfbFirst=HsfbCloseHsfb(qfshr->hsfbFirst, &errb);
  431. // if (errb.err!=S_OK)
  432. // break;
  433. //}
  434. if ((errb = RcCloseOrFlushHbt(qfshr->hbt, TRUE)) != S_OK)
  435. {
  436. /* out of disk space, internal error, or out of file handles. */
  437. if (errb != E_HANDLE)
  438. {
  439. /* attempt to invalidate FS by clobbering magic number */
  440. LSeekFid(qfshr->fid, 0L, wSeekSet, NULL);
  441. qfshr->fsh.wMagic = 0;
  442. LcbWriteFid(qfshr->fid, &qfshr->fsh, (LONG)sizeof(FSH), NULL);
  443. }
  444. }
  445. else
  446. {
  447. if (qfshr->fsh.bFlags & FSH_READWRITE)
  448. {
  449. FoSeekFid(qfshr->fid, qfshr->fsh.foFreeList, wSeekSet, NULL);
  450. FreeListWriteToFid(qfshr->hfl, qfshr->fid, NULL);
  451. FreeListDestroy(qfshr->hfl);
  452. if (LSeekFid(qfshr->fid, 0L, wSeekSet, &errb) == 0L)
  453. {
  454. LcbWriteFid(qfshr->fid, &qfshr->fsh, (LONG)sizeof(FSH), &errb);
  455. }
  456. }
  457. }
  458. // Remove our access to the global subfile handle object
  459. if (!(_INTERLOCKEDDECREMENT(&mv_gsfa_count)))
  460. {
  461. // Last person using subfile array deletes it too!
  462. // Can we use the GlobalHandle function OK in all environments?
  463. _GLOBALUNLOCK(GlobalHandle(mv_gsfa));
  464. _GLOBALFREE(GlobalHandle(mv_gsfa));
  465. mv_gsfa=NULL;
  466. mv_gsfa_count=-1L;
  467. _DELETECRITICALSECTION(&mv_gsfa_cs);
  468. }
  469. RcCloseFid(qfshr->fid);
  470. _LEAVECRITICALSECTION(&qfshr->cs);
  471. _DELETECRITICALSECTION(&qfshr->cs);
  472. if (qfshr->sb.lpvBuffer)
  473. {
  474. _DELETECRITICALSECTION(&qfshr->sb.cs);
  475. _GLOBALUNLOCK(GlobalHandle(qfshr->sb.lpvBuffer));
  476. _GLOBALFREE(GlobalHandle(qfshr->sb.lpvBuffer));
  477. }
  478. DisposeFm(qfshr->fm);
  479. _GLOBALUNLOCK(hfs);
  480. _GLOBALFREE(hfs);
  481. return errb;
  482. }
  483. /***************************************************************************
  484. *
  485. * @doc INTERNAL API
  486. *
  487. * @func HRESULT PASCAL FAR | RcFlushHfs |
  488. * Write all temporary info in file system to FS file
  489. *
  490. * @parm HFS | hfs |
  491. * Handle of opened file system
  492. *
  493. * @rdesc Returns S_OK if closed OK, else an error
  494. *
  495. * @comm
  496. * state IN:
  497. * state OUT:
  498. * Notes:
  499. *
  500. ***************************************************************************/
  501. HRESULT PASCAL FAR RcFlushHfs(HFS hfs)
  502. {
  503. QFSHR qfshr;
  504. HRESULT errb;
  505. //HSFB hsfbCursor;
  506. HRESULT rc=S_OK;
  507. if (hfs == NULL || (qfshr = _GLOBALLOCK(hfs)) == NULL)
  508. {
  509. return(E_INVALIDARG);
  510. }
  511. _ENTERCRITICALSECTION(&qfshr->cs);
  512. // We need to:
  513. // (1) close all subfiles if any open
  514. // (2) close the btree
  515. // (3) r/w write free list
  516. // (4) r/w write header
  517. RcFlushEveryHf(hfs);
  518. /*
  519. hsfbCursor=qfshr->hsfbFirst;
  520. while (hsfbCursor)
  521. {
  522. HSFB hsfbNext=NULL;
  523. QSFB qsfb;
  524. if (!(qsfb = _GLOBALLOCK(hsfbCursor)))
  525. {
  526. rc=E_OUTOFMEMORY;
  527. exit1:
  528. _LEAVECRITICALSECTION(&qfshr->cs);
  529. _GLOBALUNLOCK(hfs);
  530. return rc;
  531. }
  532. hsfbNext=qsfb->hsfbNext;
  533. if ((rc=RcFlushHsfb(hsfbCursor))!=S_OK)
  534. {
  535. _GLOBALUNLOCK(hsfbCursor);
  536. goto exit1;
  537. }
  538. _GLOBALUNLOCK(hsfbCursor);
  539. hsfbCursor=hsfbNext;
  540. }
  541. */
  542. if ((rc = RcCloseOrFlushHbt(qfshr->hbt, FALSE)) != S_OK)
  543. {
  544. /* out of disk space, internal error, or out of file handles. */
  545. if (rc != E_HANDLE)
  546. {
  547. /* attempt to invalidate FS by clobbering magic number */
  548. LSeekFid(qfshr->fid, 0L, wSeekSet, NULL);
  549. qfshr->fsh.wMagic = 0;
  550. LcbWriteFid(qfshr->fid, &qfshr->fsh, (LONG)sizeof(FSH), NULL);
  551. }
  552. }
  553. else
  554. {
  555. if (qfshr->fsh.bFlags & FSH_READWRITE)
  556. {
  557. FoSeekFid(qfshr->fid, qfshr->fsh.foFreeList, wSeekSet, NULL);
  558. FreeListWriteToFid(qfshr->hfl, qfshr->fid, NULL);
  559. if (LSeekFid(qfshr->fid, 0L, wSeekSet, &errb) == 0L)
  560. {
  561. LcbWriteFid(qfshr->fid, &qfshr->fsh, (LONG)sizeof(FSH), &errb);
  562. }
  563. FidFlush(qfshr->fid);
  564. }
  565. }
  566. _LEAVECRITICALSECTION(&qfshr->cs);
  567. _GLOBALUNLOCK(hfs);
  568. return rc;
  569. }
  570. /***************************************************************************
  571. *
  572. * @doc INTERNAL API
  573. *
  574. * @func HRESULT PASCAL FAR | RcDestroyFileSysFm |
  575. * Deletes a closed file system (removes it from the disk)
  576. *
  577. * @parm FM | fmFileName |
  578. * Name of file to destroy (FM is same as LPSTR)
  579. *
  580. * @rdesc Returns S_OK if deleted
  581. *
  582. ***************************************************************************/
  583. PUBLIC HRESULT PASCAL FAR EXPORT_API RcDestroyFileSysFm(FM fm)
  584. {
  585. #ifdef MOSMAP // {
  586. // Disable function
  587. return ERR_NOTSUPPORTED;
  588. #else // } {
  589. HRESULT errb;
  590. FSH fsh;
  591. FID fid = FidOpenFm(fm, wReadOnly, &errb);
  592. if (fid == fidNil)
  593. return errb;
  594. if (LcbReadFid (fid, &fsh, (LONG)sizeof(FSH), &errb) != (LONG)sizeof(FSH))
  595. {
  596. RcCloseFid(fid);
  597. return E_FILEINVALID;
  598. }
  599. if (fsh.wMagic != wFileSysMagic)
  600. {
  601. RcCloseFid(fid);
  602. return E_FILEINVALID;
  603. }
  604. /* REVIEW: unlink all tmp files for open files? assert count == 0? */
  605. RcCloseFid(fid); /* I'm not checking this return code out of boredom */
  606. return (RcUnlinkFm( fm) );
  607. #endif //}
  608. }
  609. #define MAGIC_FSFILEFIND 0x22334455
  610. /***************************************************************************
  611. *
  612. * @doc INTERNAL API
  613. *
  614. * @func HRESULT PASCAL FAR | RcFindFirstFile |
  615. * Finds the first file equal to or after the given filename. This function
  616. * will always find a filename unless the given search filename is past all
  617. * files in the file system.
  618. *
  619. * @parm LPCSTR | szFileName |
  620. * Name of file to look for. OK to use partial filenames, since the
  621. * first file equal to or after the given filename in the directory
  622. * will be found.
  623. *
  624. * @parm LPFSFILEFIND |lpfsfilefind|
  625. * This structure will be filled with information like file length,
  626. * permission attributes, and file name. It will also be passed to
  627. * RcFindNextFile to get the next filename.
  628. *
  629. * @rdesc Returns S_OK if successful.
  630. *
  631. ***************************************************************************/
  632. PUBLIC HRESULT PASCAL FAR EXPORT_API RcFindFirstFile(HFS hfs, LPCSTR szFilename, FSFILEFIND * pfind)
  633. {
  634. QFSHR qfshr;
  635. HRESULT rc = S_OK;
  636. KEY key;
  637. BTPOS btpos;
  638. FILE_REC fr;
  639. if ((szFilename==NULL) || (pfind==NULL) || (hfs == NULL) || ((qfshr = _GLOBALLOCK(hfs)) == NULL))
  640. return E_INVALIDARG;
  641. key = NewKeyFromSz(szFilename);
  642. _ENTERCRITICALSECTION(&qfshr->cs);
  643. RcLookupByKeyAux(qfshr->hbt, key, &btpos, &fr, FALSE);
  644. if (btpos.bk == bkNil)
  645. { rc=E_NOTEXIST;
  646. goto exit1;
  647. }
  648. GetFrData(&fr);
  649. pfind->btpos=btpos;
  650. pfind->foSize=fr.foSize;
  651. pfind->foStart=fr.foStart;
  652. pfind->bFlags=fr.bFlags;
  653. pfind->hfs=hfs;
  654. pfind->magic=MAGIC_FSFILEFIND;
  655. RcLookupByPos( qfshr->hbt, &btpos, (KEY)pfind->szFilename, 256, &fr );
  656. //GetFrData(&fr);
  657. { DWORD dwLen;
  658. int iOffset;
  659. LPSTR szCursor;
  660. dwLen=FoFromSz(pfind->szFilename).dwOffset;
  661. iOffset=LenSzFo(pfind->szFilename);
  662. szCursor=pfind->szFilename;
  663. while (dwLen--)
  664. { *szCursor=*(szCursor+iOffset);
  665. szCursor++;
  666. }
  667. *szCursor=0x00;
  668. }
  669. exit1:
  670. _LEAVECRITICALSECTION(&qfshr->cs);
  671. DisposeMemory((LPSTR)key);
  672. _GLOBALUNLOCK(hfs);
  673. return rc;
  674. }
  675. /***************************************************************************
  676. *
  677. * @doc INTERNAL API
  678. *
  679. * @func HRESULT PASCAL FAR | RcFindNextFile |
  680. * Finds the next file in the file system directory.
  681. *
  682. * @parm LPFSFILEFIND |lpfsfilefind|
  683. * This structure will be filled with information like file length,
  684. * permission attributes, and file name. It must have already been filled
  685. * by RcFindFirstFile before calling this function.
  686. *
  687. * @rdesc Returns S_OK if successful
  688. *
  689. ***************************************************************************/
  690. PUBLIC HRESULT PASCAL FAR EXPORT_API RcFindNextFile(FSFILEFIND * pfind)
  691. {
  692. QFSHR qfshr;
  693. HRESULT rc = S_OK;
  694. BTPOS btNewPos;
  695. FILE_REC fr;
  696. if ((!pfind) || (pfind->magic!=MAGIC_FSFILEFIND))
  697. return E_INVALIDARG;
  698. if ((pfind->hfs == NULL) || ((qfshr = _GLOBALLOCK(pfind->hfs)) == NULL))
  699. return E_INVALIDARG;
  700. _ENTERCRITICALSECTION(&qfshr->cs);
  701. if (RcNextPos( qfshr->hbt, &pfind->btpos, &btNewPos )==E_NOTEXIST)
  702. {
  703. rc=E_NOTEXIST;
  704. goto exit1;
  705. }
  706. pfind->btpos=btNewPos;
  707. RcLookupByPos( qfshr->hbt, &pfind->btpos, (KEY)pfind->szFilename, 256, &fr );
  708. GetFrData(&fr);
  709. pfind->foSize=fr.foSize;
  710. pfind->bFlags=fr.bFlags;
  711. { LPSTR szCursor;
  712. DWORD dwLen;
  713. int iOffset;
  714. dwLen=FoFromSz(pfind->szFilename).dwOffset;
  715. iOffset=LenSzFo(pfind->szFilename);
  716. szCursor=pfind->szFilename;
  717. while (dwLen--)
  718. { *szCursor=*(szCursor+iOffset);
  719. szCursor++;
  720. }
  721. *szCursor=0x00;
  722. }
  723. exit1:
  724. _LEAVECRITICALSECTION(&qfshr->cs);
  725. _GLOBALUNLOCK(pfind->hfs);
  726. return rc;
  727. }
  728. /***************************************************************************
  729. *
  730. * @doc PRIVATE
  731. *
  732. * @func HFREELIST PASCAL FAR | FreeListInitFromFid |
  733. * Initialize a freelist structure from a fid image. Fid image is
  734. * always in Intel byte ordering format.
  735. *
  736. * @parm FID | fid |
  737. * File id
  738. *
  739. * @parm PHRESULT | lpErrb |
  740. * Error code return - S_OK or E_OUTOFMEMORY
  741. *
  742. * @rdesc Returns handle to a FREELIST, otherwise NULL if error.
  743. *
  744. ***************************************************************************/
  745. PUBLIC HFREELIST PASCAL FAR EXPORT_API FreeListInitFromFid( FID fid, PHRESULT lpErrb )
  746. {
  747. FREELISTHDR freehdr;
  748. QFREELIST qFreeList;
  749. HFREELIST hFreeList = NULL;
  750. WORD wMaxBlocks;
  751. WORD wNumBlocks;
  752. DWORD dwLostBytes;
  753. assert(fid!=fidNil);
  754. if (LcbReadFid(fid, &freehdr, sizeof(FREELISTHDR), lpErrb)!=sizeof(FREELISTHDR))
  755. {
  756. return NULL;
  757. }
  758. wMaxBlocks = freehdr.wMaxBlocks;
  759. wNumBlocks = freehdr.wNumBlocks;
  760. dwLostBytes = freehdr.dwLostBytes;
  761. //wMaxBlocks = qFreeListMem->flh.wMaxBlocks;
  762. //wNumBlocks = qFreeListMem->flh.wNumBlocks;
  763. // Mac-ify
  764. wMaxBlocks = SWAPWORD(wMaxBlocks);
  765. wNumBlocks = SWAPWORD(wNumBlocks);
  766. dwLostBytes = SWAPLONG(dwLostBytes);
  767. assert( wMaxBlocks );
  768. if (!(hFreeList=_GLOBALALLOC(GMEM_ZEROINIT| GMEM_MOVEABLE,
  769. sizeof(FREEITEM)*wMaxBlocks+sizeof(FREELISTHDR))))
  770. {
  771. SetErrCode(lpErrb,E_OUTOFMEMORY);
  772. return NULL;
  773. }
  774. if (!(qFreeList=_GLOBALLOCK(hFreeList)))
  775. {
  776. SetErrCode(lpErrb,E_OUTOFMEMORY);
  777. goto exit1;
  778. }
  779. qFreeList->flh.wMaxBlocks=wMaxBlocks;
  780. qFreeList->flh.wNumBlocks=wNumBlocks;
  781. qFreeList->flh.dwLostBytes=dwLostBytes;
  782. LcbReadFid( fid, qFreeList->afreeitem, sizeof(FREEITEM) * wMaxBlocks, lpErrb);
  783. #ifdef _BIG_E
  784. {
  785. QFREEITEM qCurrent = qFreeList->afreeitem;
  786. WORD wBlock;
  787. for (wBlock=0;wBlock<wNumBlocks;wBlock++)
  788. {
  789. qCurrent->foStart.dwOffset = SWAPLONG(qCurrent->foStart.dwOffset);
  790. qCurrent->foStart.dwHigh = SWAPLONG(qCurrent->foStart.dwHigh);
  791. qCurrent->foBlock.dwOffset = SWAPLONG(qCurrent->foBlock.dwOffset);
  792. qCurrent->foBlock.dwHigh = SWAPLONG(qCurrent->foBlock.dwHigh);
  793. }
  794. }
  795. #endif // _BIG_E
  796. _GLOBALUNLOCK(hFreeList);
  797. return hFreeList;
  798. exit1:
  799. _GLOBALFREE(hFreeList);
  800. return NULL;
  801. }
  802. /***************************************************************************
  803. *
  804. * @doc PRIVATE
  805. *
  806. * @func HRESULT PASCAL FAR | FreeListWriteToFid |
  807. * Write to fid with freelist data. Call FreeListSize first
  808. * to make sure the space is large enough. Memory image will always
  809. * be in Intel byte ordering format.
  810. *
  811. * @parm HFREELIST | hFreeList |
  812. * List to retrieve
  813. *
  814. * @parm FID | fid |
  815. * FID to contain free list data
  816. *
  817. * @parm PHRESULT | lpErrb |
  818. * Error return
  819. *
  820. * @rdesc Number of bytes written
  821. *
  822. ***************************************************************************/
  823. PUBLIC LONG PASCAL FAR EXPORT_API FreeListWriteToFid( HFREELIST hFreeList, FID fid, PHRESULT lpErrb )
  824. {
  825. QFREELIST qFreeList;
  826. WORD wMaxBlocks;
  827. WORD wNumBlocks;
  828. DWORD dwLostBytes;
  829. LONG lcbSize;
  830. LONG lcbWritten=0L;
  831. assert(fid!=fidNil);
  832. assert(hFreeList);
  833. if (!(qFreeList = _GLOBALLOCK(hFreeList)))
  834. { SetErrCode(lpErrb, E_OUTOFMEMORY);
  835. goto exit0;
  836. }
  837. wMaxBlocks=qFreeList->flh.wMaxBlocks;
  838. wNumBlocks=qFreeList->flh.wNumBlocks;
  839. dwLostBytes=qFreeList->flh.dwLostBytes;
  840. lcbSize = sizeof(FREELISTHDR) + wMaxBlocks * sizeof(FREEITEM);
  841. #ifdef _BIG_E
  842. {
  843. QFREEITEM qCurrent;
  844. WORD wBlock;
  845. HANDLE hMem;
  846. QFREELIST qFreeListMem;
  847. if (!(hMem = _GLOBALALLOC(GMEM_MOVEABLE, lcbSize)))
  848. {
  849. SetErrCode(lpErrb, E_OUTOFMEMORY);
  850. goto exit0;
  851. }
  852. qFreeListMem = (QFREELIST)_GLOBALLOCK(hMem);
  853. qCurrent = qFreeListMem->afreeitem;
  854. qFreeListMem->flh.wNumBlocks = SWAPWORD( qFreeList->flh.wNumBlocks );
  855. qFreeListMem->flh.wMaxBlocks = SWAPWORD( qFreeList->flh.wMaxBlocks );
  856. qFreeListMem->flh.dwLostBytes = SWAPLONG( qFreeList->flh.dwLostBytes );
  857. for (wBlock=0;wBlock<wNumBlocks;wBlock++)
  858. {
  859. qCurrent->foStart.dwOffset = SWAPLONG(qCurrent->foStart.dwOffset);
  860. qCurrent->foStart.dwHigh = SWAPLONG(qCurrent->foStart.dwHigh);
  861. qCurrent->foBlock.dwOffset = SWAPLONG(qCurrent->foBlock.dwOffset);
  862. qCurrent->foBlock.dwHigh = SWAPLONG(qCurrent->foBlock.dwHigh);
  863. }
  864. lcbWritten=LcbWriteFid(fid, qFreeListMem, lcbSize, lpErrb);
  865. _GLOBALUNLOCK(hMem);
  866. _GLOBALFREE(hMem);
  867. }
  868. #else
  869. lcbWritten=LcbWriteFid(fid, qFreeList, lcbSize, lpErrb);
  870. #endif // _BIG_E
  871. _GLOBALUNLOCK(hFreeList);
  872. exit0:
  873. return lcbWritten;
  874. }