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.

2859 lines
70 KiB

  1. /*****************************************************************************
  2. * *
  3. * VFILE.C *
  4. * *
  5. * Copyright (C) Microsoft Corporation 1995. *
  6. * All Rights reserved. *
  7. * *
  8. ******************************************************************************
  9. * *
  10. * Module Intent *
  11. * *
  12. * "Virtual File" functions - Actual data may reside in a parent file at *
  13. * any given offset, or in a temp file. *
  14. * *
  15. ******************************************************************************
  16. * *
  17. * Current Owner: davej *
  18. *****************************************************************************
  19. * Notes:
  20. *
  21. * #ifndef ITWRAP added around all calls that have a wrapped implementation
  22. * (wrapstor.lib provides calls into the InfoTech IStorage/IStream
  23. * implementation)
  24. *
  25. *****************************************************************************/
  26. /*****************************************************************************
  27. *
  28. * Created 07/17/95 - davej
  29. *
  30. *****************************************************************************/
  31. static char s_aszModule[] = __FILE__; /* For error report */
  32. #include <mvopsys.h>
  33. #include <iterror.h>
  34. #include <orkin.h>
  35. #include <misc.h>
  36. #include <wrapstor.h>
  37. #include <_mvutil.h>
  38. /*****************************************************************************
  39. * *
  40. * Globals *
  41. * *
  42. *****************************************************************************/
  43. SF FAR * mv_gsfa = NULL; // Subfile headers (better/faster than globalalloc'ing them)
  44. LONG mv_gsfa_count = -1L; // User count, equals number of MV titles opened or -1 for not init
  45. CRITICAL_SECTION mv_gsfa_cs; // Ensure accessing the array is OK in multi-threaded environment
  46. /*****************************************************************************
  47. * *
  48. * Defines *
  49. * *
  50. *****************************************************************************/
  51. /*****************************************************************************
  52. * *
  53. * Prototypes *
  54. * *
  55. *****************************************************************************/
  56. #ifdef _DEBUGMVFS
  57. void DumpMV_GSFA(void);
  58. #endif
  59. /***************************************************************************
  60. * *
  61. * Private Functions *
  62. * *
  63. ***************************************************************************/
  64. /***************************************************************************
  65. *
  66. * @doc PRIVATE
  67. *
  68. * @func int PASCAL NEAR | SFHeaderSize |
  69. * Get the 'extra' header size for a sub file (the part that lives with
  70. * the file data itself)
  71. *
  72. * @parm QSFH | qsfh |
  73. * Pointer to subfile header block (contains file length and flags)
  74. *
  75. * @rdesc Return the number of bytes of header that exist before the
  76. * file data
  77. *
  78. * @comm
  79. * Currently this only returns zero, but if at the file's starting location,
  80. * there exists a header, (check the <p qsfh> <e bFlags> element to determine
  81. * the number of bytes being used for the file header.
  82. *
  83. ***************************************************************************/
  84. int PASCAL NEAR SFHeaderSize(QSFH qsfh)
  85. {
  86. return 0; // based on the qsfh->bFlags value, determine header size, or
  87. // if other header info exists before the file data
  88. }
  89. /***************************************************************************
  90. *
  91. * @doc PRIVATE
  92. *
  93. * @func FILEOFFSET PASCAL NEAR | GetFreeBlock |
  94. * Get the file offset of a free block of the given size
  95. *
  96. * @parm QFSHR | qfshr |
  97. * Pointer to file system header
  98. *
  99. * @parm FILEOFFSET | foBlockSize |
  100. * Size of block to retrieve offset to
  101. *
  102. * @parm PHRESULT | phr |
  103. * Error return
  104. *
  105. * @rdesc Returns valid file offset, or foNil if an error occurs
  106. *
  107. * @comm
  108. * state IN:
  109. * state OUT: Free list no longer contains the given block
  110. * Notes:
  111. *
  112. ***************************************************************************/
  113. FILEOFFSET PASCAL NEAR GetFreeBlock(QFSHR qfshr,FILEOFFSET foBlock,PHRESULT phr)
  114. {
  115. HRESULT errb;
  116. FILEOFFSET foStart;
  117. assert(qfshr->hfl);
  118. foStart = FreeListGetBestFit(qfshr->hfl,foBlock,&errb);
  119. if (errb!=S_OK)
  120. {
  121. FILEOFFSET foLastBlock;
  122. FILEOFFSET foLastBlockSize;
  123. // If last free list block goes to end of file, start there
  124. // Last block is automatically removed in the GetLastBlock call
  125. if (FreeListGetLastBlock(qfshr->hfl,&foLastBlock,&foLastBlockSize,qfshr->fsh.foEof)==S_OK)
  126. {
  127. foStart=foLastBlock;
  128. qfshr->fsh.foEof=FoAddFo(foLastBlock,foBlock);
  129. }
  130. else
  131. {
  132. // otherwise allocate it from end
  133. foStart=qfshr->fsh.foEof;
  134. qfshr->fsh.foEof=FoAddFo(qfshr->fsh.foEof,foBlock);
  135. }
  136. }
  137. return foStart;
  138. }
  139. /***************************************************************************
  140. *
  141. * @doc PRIVATE
  142. *
  143. * @func short PASCAL NEAR | GetNewHf |
  144. * Get a new handle to a subfile. These handles are actually
  145. * indices into the mv_gsfa global array.
  146. *
  147. * @parm LPCSTR | szFilename |
  148. * Filename to use for hashing an Hf index
  149. *
  150. * @rdesc Returns valid index of a subfile, or hfNil for error
  151. *
  152. * @comm
  153. * Array is not modified, so calling twice will give same index
  154. *
  155. ***************************************************************************/
  156. static int giMaxSubFiles=MAXSUBFILES;
  157. short PASCAL NEAR GetNewHf(LPCSTR szFilename)
  158. {
  159. int iLen;
  160. unsigned short i,uiStart=0;
  161. int iMaxFilled;
  162. iMaxFilled=giMaxSubFiles-1;
  163. _ENTERCRITICALSECTION(&mv_gsfa_cs);
  164. assert(mv_gsfa);
  165. assert(mv_gsfa_count);
  166. iLen=(szFilename)?min(8,lstrlen(szFilename)):0;
  167. while (iLen--)
  168. {
  169. uiStart=(uiStart<<1)^(*(szFilename++));
  170. }
  171. i=uiStart%=giMaxSubFiles;
  172. while (mv_gsfa[i].hsfb)
  173. {
  174. i=(i+1)%giMaxSubFiles;
  175. if (!(--iMaxFilled))
  176. {
  177. // Increase our space!
  178. HANDLE hNew;
  179. giMaxSubFiles+=64;
  180. _GLOBALUNLOCK(GlobalHandle(mv_gsfa));
  181. if ((hNew=_GLOBALREALLOC(GlobalHandle(mv_gsfa),sizeof(SF)*giMaxSubFiles,GMEM_MOVEABLE|GMEM_ZEROINIT))==NULL)
  182. {
  183. giMaxSubFiles-=64;
  184. i=0;
  185. break;
  186. }
  187. mv_gsfa=(SF FAR *)_GLOBALLOCK(hNew);
  188. i=uiStart%giMaxSubFiles;
  189. iMaxFilled=giMaxSubFiles-1;
  190. }
  191. }
  192. _LEAVECRITICALSECTION(&mv_gsfa_cs);
  193. #ifdef _DEBUGMVFS
  194. DPF2("GetNewHf: subfile '%s' is hf %d\n", (szFilename) ? szFilename : "NULL", i);
  195. DumpMV_GSFA();
  196. #endif
  197. return i;
  198. }
  199. /***************************************************************************
  200. *
  201. * @doc PRIVATE
  202. *
  203. * @func KEY PASCAL FAR | NewKeyFromSz |
  204. * Convert a filename to a Key type for the file system btree. Currently
  205. * a key type is a variable byte length size followed by the chars.
  206. *
  207. * @parm LPCSTR | szName |
  208. * Name to convert
  209. *
  210. * @rdesc Returns valid KEY.
  211. *
  212. * @comm
  213. * state IN:
  214. * state OUT: String is allocated in the global string memory area
  215. * Notes: Must call DisposeMemory((LPSTR)key) when finished using.
  216. *
  217. ***************************************************************************/
  218. KEY PASCAL FAR EXPORT_API NewKeyFromSz(LPCSTR sz)
  219. {
  220. int iLLen;
  221. LPSTR szKey;
  222. FILEOFFSET foLen;
  223. foLen.dwHigh=0;
  224. foLen.dwOffset=lstrlen(sz);
  225. szKey=NewMemory((WORD)(foLen.dwOffset+5));
  226. iLLen=FoToSz(foLen, szKey);
  227. lstrcpy(szKey+iLLen,sz);
  228. return (KEY)szKey;
  229. }
  230. // Returns number of bytes used in the fr struct
  231. // Sets fr.szData to the File Offset, Length, and status byte
  232. /***************************************************************************
  233. *
  234. * @doc PRIVATE
  235. *
  236. * @func WORD PASCAL NEAR | SetFrData |
  237. * Set the szData field of pfr to the start, size, and byte values.
  238. *
  239. * @parm FILE_REC FAR * | pfr |
  240. * Pointer to FILE_REC structure
  241. *
  242. * @parm FILEOFFSET | foStart |
  243. * Starting address of a file
  244. *
  245. * @parm FILEOFFSET | foSize |
  246. * Size of a file
  247. *
  248. * @parm BYTE | bFlags |
  249. * The file flags (not used at the moment)
  250. *
  251. * @rdesc Returns the number of bytes used in the fr struct after FILEOFFSETs
  252. * are converted to their equivalent variable-length byte values. This is
  253. * the amount of space the filerec takes in the system btree.
  254. *
  255. * @comm
  256. * <p pfr> is set to the foStart, foSize, and bFlags values. The
  257. * <e szData> field of <p pfr> is set to the compressed version of the
  258. * data (3 to 19 bytes in size for the three fields).
  259. *
  260. ***************************************************************************/
  261. WORD PASCAL NEAR SetFrData(FILE_REC FAR * pfr, FILEOFFSET foStart, FILEOFFSET foSize, BYTE bFlags)
  262. {
  263. WORD wTotalLen;
  264. assert(pfr);
  265. wTotalLen=FoToSz(foStart, pfr->szData);
  266. wTotalLen+=FoToSz(foSize, pfr->szData+wTotalLen);
  267. pfr->szData[wTotalLen++]=(char)bFlags;
  268. pfr->foStart=foStart;
  269. pfr->foSize=foSize;
  270. pfr->bFlags=bFlags;
  271. return wTotalLen;
  272. }
  273. /***************************************************************************
  274. *
  275. * @doc PRIVATE
  276. *
  277. * @func WORD PASCAL NEAR | GetFrData |
  278. * Get the size, start, and flags fields from the szData field of the
  279. * FILE_REC.
  280. *
  281. * @parm FILE_REC FAR * | pfr |
  282. * Pointer to FILE_REC structure
  283. *
  284. * @rdesc nothing.
  285. *
  286. * @comm
  287. * All the fields are set based on the szData compressed
  288. * version of the offset, size, and flags from the <p pfr> <e szData> field.
  289. *
  290. ***************************************************************************/
  291. void PASCAL FAR EXPORT_API GetFrData(FILE_REC FAR *pfr)
  292. {
  293. LPSTR szCursor;
  294. assert(pfr);
  295. szCursor=pfr->szData;
  296. pfr->foStart=FoFromSz(szCursor);
  297. ADVANCE_FO(szCursor);
  298. pfr->foSize=FoFromSz(szCursor);
  299. ADVANCE_FO(szCursor);
  300. pfr->bFlags=*szCursor;
  301. }
  302. /***************************************************************************
  303. *
  304. * @doc PRIVATE
  305. *
  306. * @func HF PASCAL NEAR | HfOpenFileHfsInternal |
  307. * Open or Create a non-system subfile. Use the public HfOpenHfs,
  308. * HfCreateFileHfs, and HfOpenHfsReserve functions, not this one.
  309. *
  310. * @parm HFS | hfs|
  311. * File system for this sub file.
  312. *
  313. * @parm LPCSTR | szFilename |
  314. * Name of file
  315. *
  316. * @parm BYTE | bFlags |
  317. * Any of the following HFOPEN_ flags (except for HFOPEN_SYSTEM)
  318. * @flag HFOPEN_READWRITE | (0x01) Open a file for reading and writing.
  319. * @flag HFOPEN_READ | (0x02) Open a file for reading only.
  320. * @flag HFOPEN_CREATE | (0x04) Create a new file, or truncate an
  321. * existing file.
  322. * @flag HFOPEN_NOTEMP | (0x10) If file is opened for read/write, do
  323. * not make a temporary file if possible,
  324. * so edits to the file are made directly
  325. * in the file system.
  326. * @flag HFOPEN_FORCETEMP | (0x20) A temp file is always created (space
  327. * permitting) in read-only mode.
  328. * @flag HFOPEN_ENABLELOGGING| (0x40) Logging usage of this file will be
  329. * enabled.
  330. *
  331. * @parm FILEOFFSET | foReserve |
  332. * When creating or opening a r/w file, reserve this amount of space
  333. * for the file in the file system.
  334. *
  335. * @parm PHRESULT | phr |
  336. * Error return
  337. *
  338. * @rdesc Returns a valid HF, or hfNil if an error.
  339. *
  340. * @comm
  341. * state IN:
  342. * state OUT: Valid HF
  343. *
  344. ***************************************************************************/
  345. #ifndef ITWRAP
  346. HF PASCAL NEAR HfOpenFileHfsInternal(HFS hfs, LPCSTR sz,
  347. BYTE bFlags, FILEOFFSET foReserve, PHRESULT phr)
  348. {
  349. #ifdef MOSMAP // {
  350. // Disable function
  351. if (bFlags & (HFOPEN_CREATE|HFOPEN_READWRITE))
  352. {
  353. SetErrCode (phr, ERR_NOTSUPPORTED);
  354. return hfNil ;
  355. }
  356. #else // } {
  357. DWORD hf;
  358. QSFB qsfb;
  359. QFSHR qfshr;
  360. HRESULT rc;
  361. FILE_REC fr;
  362. BOOL bShouldInsert=FALSE;
  363. HSFB hsfbFound=NULL;
  364. KEY key;
  365. if (hfs == NULL || (qfshr = _GLOBALLOCK(hfs)) == NULL)
  366. {
  367. SetErrCode (phr, E_INVALIDARG);
  368. return hfNil;
  369. }
  370. _ENTERCRITICALSECTION(&qfshr->cs);
  371. key = NewKeyFromSz(sz);
  372. if (bFlags&HFOPEN_CREATE)
  373. { bFlags|=HFOPEN_READWRITE;
  374. if (bFlags&HFOPEN_READ)
  375. {
  376. SetErrCode(phr, E_INVALIDARG);
  377. goto error_return;
  378. }
  379. }
  380. // Reserving space implies no temporary file if possible
  381. if (!FoIsNil(foReserve))
  382. {
  383. bFlags|=HFOPEN_NOTEMP;
  384. }
  385. else // Conversly, reserving NO space implies a temporary file
  386. {
  387. bFlags&=~HFOPEN_NOTEMP;
  388. }
  389. assert(!(bFlags&HFOPEN_SYSTEM));
  390. // make sure file system is writable
  391. if ((bFlags&(HFOPEN_CREATE|HFOPEN_READWRITE)) && (qfshr->fsh.bFlags&FSH_READONLY))
  392. {
  393. SetErrCode (phr, E_NOPERMISSION);
  394. goto error_return;
  395. }
  396. rc = RcLookupByKey(qfshr->hbt, key, NULL, &fr);
  397. // File already opened and being written to for first time
  398. // or file locked, then we exit with E_NOPERMISSION
  399. if (rc==S_OK)
  400. {
  401. GetFrData(&fr);
  402. if ((fr.bFlags&SFH_INVALID) || ((fr.bFlags&SFH_LOCKED) && (bFlags&HFOPEN_READWRITE)))
  403. {
  404. SetErrCode(phr, E_NOPERMISSION);
  405. goto error_return;
  406. }
  407. }
  408. if (bFlags&HFOPEN_CREATE)
  409. {
  410. if (rc == S_OK)
  411. {
  412. // Already exists, let's truncate to zero!!!
  413. assert(!FoIsNil(fr.foStart));
  414. //SetErrCode(phr,ERR_EXIST);
  415. //goto error_return;
  416. }
  417. else
  418. {
  419. // *** OK, Create node with '-1' for 'exclusive'
  420. SetFrData(&fr,foNil,foNil,SFH_INVALID);
  421. bShouldInsert = TRUE;
  422. }
  423. }
  424. else
  425. {
  426. if (rc!=S_OK)
  427. {
  428. SetErrCode(phr, rc);
  429. goto error_return;
  430. }
  431. }
  432. if ((hf=(DWORD)GetNewHf(sz))== hfNil)
  433. {
  434. SetErrCode(phr, ERR_NOHANDLE); // Out of file handles
  435. goto error_return;
  436. }
  437. mv_gsfa[hf].foCurrent=foNil;
  438. // Look for file block in opened file list
  439. if (!(fr.bFlags&SFH_INVALID))
  440. {
  441. HSFB hsfb = qfshr->hsfbFirst;
  442. QSFB qsfb;
  443. HSFB hsfbNext;
  444. while ((hsfb) && (!hsfbFound))
  445. {
  446. qsfb=(QSFB)_GLOBALLOCK(hsfb);
  447. if (FoEquals(qsfb->foHeader,fr.foStart))
  448. {
  449. hsfbFound=hsfb;
  450. }
  451. hsfbNext=qsfb->hsfbNext;
  452. _GLOBALUNLOCK(hsfb);
  453. hsfb=hsfbNext;
  454. }
  455. }
  456. if (!hsfbFound)
  457. {
  458. // Create new subfile block
  459. FILEOFFSET foExtraSize=foNil;
  460. mv_gsfa[hf].hsfb = _GLOBALALLOC(GMEM_ZEROINIT|GMEM_SHARE| GMEM_MOVEABLE,
  461. (ULONG)sizeof(SFB) + ( sz == NULL ? 0 : lstrlen(sz)));
  462. qsfb = (QSFB)_GLOBALLOCK(mv_gsfa[hf].hsfb);
  463. if (mv_gsfa[hf].hsfb == NULL)
  464. {
  465. SetErrCode (phr, E_OUTOFMEMORY);
  466. goto error_return;
  467. }
  468. lstrcpy(qsfb->rgchKey, sz);
  469. qsfb->bOpenFlags=bFlags;
  470. qsfb->foHeader=fr.foStart;
  471. if (bFlags&HFOPEN_ENABLELOGGING)
  472. qsfb->sfh.bFlags|=SFH_LOGGING;
  473. qsfb->hfs = hfs;
  474. qsfb->wLockCount=1;
  475. if (!FoIsNil(qsfb->foHeader))
  476. {
  477. qsfb->sfh.foBlockSize=fr.foSize;
  478. qsfb->sfh.bFlags=fr.bFlags;
  479. }
  480. // If given foReserve, try to reserve space if file already lives in fs,
  481. // or allocate space now for all of reserve, and give it to file
  482. // if we can't reserve, then even though notemp is specified, a temp will
  483. // be created at write time, so force it to temp here in that case.
  484. if (!FoIsNil(foReserve))
  485. {
  486. assert(qfshr->hfl);
  487. if (FoCompare(foReserve,qsfb->sfh.foBlockSize)>0)
  488. {
  489. if (!(FoIsNil(qsfb->foHeader)))
  490. {
  491. // If file exists already, try to extend file
  492. foExtraSize = FreeListGetBlockAt(qfshr->hfl,FoAddFo(qsfb->foHeader,qsfb->sfh.foBlockSize),phr);
  493. // VFileOpen will handle things properly if file fits or not
  494. if (FoCompare(FoAddFo(qsfb->sfh.foBlockSize,foExtraSize),foReserve)<0)
  495. {
  496. bFlags&=(~HFOPEN_NOTEMP);
  497. }
  498. }
  499. else
  500. {
  501. // New file, try to get free space for file
  502. // We reserve amount we want plus subfile file header size
  503. qsfb->foHeader=GetFreeBlock(qfshr,FoAddDw(foReserve,SFHeaderSize(&qsfb->sfh)),NULL);
  504. foExtraSize=foReserve;
  505. }
  506. }
  507. }
  508. if ((bFlags&HFOPEN_READ) || (bFlags&HFOPEN_NOTEMP))
  509. {
  510. if (bFlags&HFOPEN_CREATE)
  511. {
  512. qsfb->hvf=VFileOpen(qfshr->fid,FoAddDw(qsfb->foHeader,SFHeaderSize(&qsfb->sfh)),
  513. foNil,FoAddFo(qsfb->sfh.foBlockSize,foExtraSize),
  514. ((bFlags&HFOPEN_READWRITE)?VFOPEN_READWRITE:VFOPEN_READ)|VFOPEN_ASFID,&qfshr->sb,phr);
  515. }
  516. else
  517. {
  518. qsfb->hvf=VFileOpen(qfshr->fid,FoAddDw(qsfb->foHeader,SFHeaderSize(&qsfb->sfh)),
  519. qsfb->sfh.foBlockSize,foExtraSize,
  520. ((bFlags&HFOPEN_READWRITE)?VFOPEN_READWRITE:VFOPEN_READ)|VFOPEN_ASFID,&qfshr->sb,phr);
  521. }
  522. }
  523. else
  524. {
  525. if (bFlags&HFOPEN_CREATE)
  526. {
  527. qsfb->hvf=VFileOpen(qfshr->fid,FoAddDw(qsfb->foHeader,SFHeaderSize(&qsfb->sfh)),
  528. foNil,FoAddFo(qsfb->sfh.foBlockSize,foExtraSize),VFOPEN_ASTEMP|VFOPEN_READWRITE,&qfshr->sb,phr);
  529. }
  530. else
  531. {
  532. qsfb->hvf=VFileOpen(qfshr->fid,FoAddDw(qsfb->foHeader,SFHeaderSize(&qsfb->sfh)),
  533. qsfb->sfh.foBlockSize,foExtraSize,VFOPEN_ASTEMP|VFOPEN_READWRITE,&qfshr->sb,phr);
  534. }
  535. }
  536. if (!qsfb->hvf)
  537. {
  538. SetErrCode(phr, ERR_NOHANDLE);
  539. exit1:
  540. _GLOBALUNLOCK(mv_gsfa[hf].hsfb);
  541. _GLOBALFREE(mv_gsfa[hf].hsfb);
  542. mv_gsfa[hf].hsfb=NULL;
  543. goto error_return;
  544. }
  545. // Extend block size to account for any extra allocation we did
  546. qsfb->sfh.foBlockSize=FoAddFo(qsfb->sfh.foBlockSize,foExtraSize);
  547. qsfb->hsfbNext = qfshr->hsfbFirst;
  548. qfshr->hsfbFirst = mv_gsfa[hf].hsfb;
  549. if (bShouldInsert)
  550. {
  551. SetFrData(&fr,foNil,foNil,SFH_INVALID);
  552. //fr.lifBase=lifNil;
  553. if ((rc = RcInsertHbt(qfshr->hbt, key, &fr))!=S_OK)
  554. { // some other error!
  555. VFileAbandon(qsfb->hvf);
  556. VFileClose(qsfb->hvf);
  557. goto exit1;
  558. }
  559. }
  560. }
  561. else
  562. {
  563. // Ignoring reserve if found, we could call VFileSetEOF though ?!?
  564. if (bFlags & HFOPEN_READWRITE)
  565. {
  566. // Trying to write to a file that's already opened for read
  567. SetErrCode(phr, E_NOPERMISSION);
  568. goto error_return;
  569. }
  570. mv_gsfa[hf].hsfb=hsfbFound;
  571. qsfb = (QSFB)_GLOBALLOCK(mv_gsfa[hf].hsfb);
  572. qsfb->wLockCount++;
  573. }
  574. _GLOBALUNLOCK(mv_gsfa[hf].hsfb);
  575. // File header always in RAM, so we never place it into the temp file
  576. DisposeMemory((LPSTR)key);
  577. _LEAVECRITICALSECTION(&qfshr->cs);
  578. _GLOBALUNLOCK(hfs);
  579. #ifdef _DEBUGMVFS
  580. DPF2("HfOpenInternal: hf=%d, sz='%s'\n", hf, sz);
  581. DumpMV_GSFA();
  582. #endif
  583. return (HF)hf;
  584. error_return:
  585. DisposeMemory((LPSTR)key);
  586. _LEAVECRITICALSECTION(&qfshr->cs);
  587. _GLOBALUNLOCK(hfs);
  588. return hfNil;
  589. #endif //}
  590. }
  591. #endif
  592. /***************************************************************************
  593. *
  594. * @doc PRIVATE
  595. *
  596. * @func HF PASCAL NEAR | HfOpenSystemFileHfsInternal |
  597. * Open or Create a system subfile. Not for civilians.
  598. *
  599. * @parm HFS | hfs|
  600. * File system for this sub file.
  601. *
  602. * @parm BYTE | bFlags |
  603. * Any of the following HFOPEN_ flags (HFOPEN_SYSTEM required)
  604. * @flag HFOPEN_READWRITE | (0x01) Open a file for reading and writing.
  605. * @flag HFOPEN_READ | (0x02) Open a file for reading only.
  606. * @flag HFOPEN_CREATE | (0x04) Create a new file, or truncate an
  607. * existing file.
  608. * @flag HFOPEN_SYSTEM | (0x08) Open or create a system file. Only one
  609. * system file is permitted per file system,
  610. * and it is the system directory btree.
  611. * @flag HFOPEN_NOTEMP | (0x10) If file is opened for read/write, do
  612. * not make a temporary file if possible,
  613. * so edits to the file are made directly
  614. * in the file system.
  615. * @flag HFOPEN_FORCETEMP | (0x20) A temp file is always created (space
  616. * permitting) in read-only mode.
  617. *
  618. * @parm PHRESULT | phr |
  619. * Error return
  620. *
  621. * @rdesc Returns a valid HF, or hfNil if an error.
  622. *
  623. ***************************************************************************/
  624. #ifndef ITWRAP
  625. HF PASCAL NEAR HfOpenSystemFileHfsInternal(HFS hfs, BYTE bFlags, PHRESULT phr)
  626. {
  627. #ifdef MOSMAP // {
  628. // Disable function
  629. if (bFlags & (HFOPEN_CREATE|HFOPEN_READWRITE))
  630. {
  631. SetErrCode (phr, ERR_NOTSUPPORTED);
  632. return hfNil ;
  633. }
  634. #else // } {
  635. DWORD hf;
  636. QSFB qsfb;
  637. QFSHR qfshr;
  638. //BOOL bShouldInsert=FALSE;
  639. HSFB hsfbFound=NULL; // when valid, use this instead of new one
  640. if (hfs == NULL || (qfshr = _GLOBALLOCK(hfs)) == NULL)
  641. {
  642. SetErrCode (phr, E_INVALIDARG);
  643. return hfNil;
  644. }
  645. _ENTERCRITICALSECTION(&qfshr->cs);
  646. if (bFlags&HFOPEN_CREATE)
  647. { bFlags|=HFOPEN_READWRITE;
  648. if (bFlags&HFOPEN_READ)
  649. {
  650. SetErrCode(phr, E_INVALIDARG);
  651. goto error_return;
  652. }
  653. }
  654. assert(bFlags&HFOPEN_SYSTEM);
  655. if ((bFlags&(HFOPEN_CREATE|HFOPEN_READWRITE)) && (qfshr->fsh.bFlags & FSH_READONLY))
  656. {
  657. SetErrCode (phr, E_NOPERMISSION);
  658. goto error_return;
  659. }
  660. if ((hf=GetNewHf(NULL))== hfNil)
  661. {
  662. SetErrCode(phr, ERR_NOHANDLE); // Out of file handles
  663. goto error_return;
  664. }
  665. // qfshr->fsh.foDirectory is used for system file offset
  666. // Only one system file allowed
  667. if (bFlags&HFOPEN_CREATE)
  668. { if (!FoIsNil(qfshr->fsh.foDirectory))
  669. {
  670. SetErrCode(phr, ERR_EXIST);
  671. goto error_return;
  672. }
  673. }
  674. else if (FoIsNil(qfshr->fsh.foDirectory))
  675. {
  676. SetErrCode(phr, E_NOTEXIST);
  677. goto error_return;
  678. }
  679. if (qfshr->hsfbSystem)
  680. {
  681. if (bFlags&HFOPEN_READWRITE)
  682. {
  683. SetErrCode (phr, E_NOPERMISSION);
  684. goto error_return;
  685. }
  686. qsfb = (QSFB)_GLOBALLOCK(qfshr->hsfbSystem);
  687. qsfb->wLockCount++;
  688. }
  689. else
  690. {
  691. qfshr->hsfbSystem = _GLOBALALLOC(GMEM_ZEROINIT|GMEM_SHARE| GMEM_MOVEABLE,
  692. (ULONG)sizeof(SFB) );
  693. if (qfshr->hsfbSystem == NULL)
  694. {
  695. SetErrCode (phr, E_OUTOFMEMORY);
  696. goto error_return;
  697. }
  698. qsfb = (QSFB)_GLOBALLOCK(qfshr->hsfbSystem);
  699. qsfb->bOpenFlags=bFlags;
  700. qsfb->foHeader = qfshr->fsh.foDirectory;
  701. qsfb->hfs = hfs;
  702. qsfb->wLockCount=1;
  703. qsfb->hsfbNext=NULL; // always since only one sys file
  704. if (!FoIsNil(qsfb->foHeader))
  705. {
  706. qsfb->sfh=qfshr->fsh.sfhSystem;
  707. }
  708. // System file, only time we open it to Tempfile is if READWRITE & !NOTEMP
  709. if ((bFlags&HFOPEN_READWRITE) && (!(bFlags&HFOPEN_NOTEMP)))
  710. qsfb->hvf=VFileOpen(qfshr->fid,FoAddDw(qsfb->foHeader,SFHeaderSize(&qsfb->sfh)),qsfb->sfh.foBlockSize,foNil,
  711. VFOPEN_ASTEMP|VFOPEN_READWRITE,&qfshr->sb,phr);
  712. else
  713. qsfb->hvf=VFileOpen(qfshr->fid,FoAddDw(qsfb->foHeader,SFHeaderSize(&qsfb->sfh)),qsfb->sfh.foBlockSize,foNil,
  714. ((bFlags&HFOPEN_READWRITE)?VFOPEN_READWRITE:VFOPEN_READ)|((bFlags&HFOPEN_FORCETEMP)?VFOPEN_ASTEMP:VFOPEN_ASFID),
  715. &qfshr->sb,phr);
  716. }
  717. _GLOBALUNLOCK(qfshr->hsfbSystem);
  718. mv_gsfa[hf].foCurrent=foNil;
  719. mv_gsfa[(DWORD)hf].hsfb = qfshr->hsfbSystem;
  720. // File header always in RAM, so we never place it into the temp file
  721. _LEAVECRITICALSECTION(&qfshr->cs);
  722. _GLOBALUNLOCK(hfs);
  723. #ifdef _DEBUGMVFS
  724. DPF2("HfOpenSystemInternal: hf=%d, bflags=%d\n", hf, bFlags);
  725. DumpMV_GSFA();
  726. #endif
  727. return (HF)hf;
  728. error_return:
  729. _LEAVECRITICALSECTION(&qfshr->cs);
  730. _GLOBALUNLOCK(hfs);
  731. return hfNil;
  732. #endif //}
  733. }
  734. #endif
  735. /***************************************************************************
  736. *
  737. * @doc INTERNAL API
  738. *
  739. * @func HF PASCAL FAR | HfOpenHfs |
  740. * Open (or create) a subfile that lives in the file system.
  741. *
  742. * @parm HFS | hfs|
  743. * File system.
  744. *
  745. * @parm LPCSTR | szFilename |
  746. * Name of file (length limited to 1/2 the block size given when creating
  747. * the file system)
  748. *
  749. * @parm BYTE | bFlags |
  750. * Any of the following HFOPEN_ flags
  751. * @flag HFOPEN_READWRITE | (0x01) Open a file for reading and writing.
  752. * @flag HFOPEN_READ | (0x02) Open a file for reading only.
  753. * @flag HFOPEN_CREATE | (0x04) Create a new file, or truncate an
  754. * existing file.
  755. * @flag HFOPEN_NOTEMP | (0x10) If file is opened for read/write, do
  756. * not make a temporary file if possible,
  757. * so edits to the file are made directly
  758. * in the file system.
  759. * @flag HFOPEN_FORCETEMP | (0x20) A temp file is always created (space
  760. * permitting) in read-only mode.
  761. *
  762. * @parm PHRESULT | phr |
  763. * Error return
  764. *
  765. * @rdesc Returns a valid HF, or hfNil if an error.
  766. *
  767. ***************************************************************************/
  768. #ifndef ITWRAP
  769. PUBLIC HF PASCAL FAR EXPORT_API HfOpenHfs(HFS hfs, LPCSTR sz,
  770. BYTE bFlags, PHRESULT phr)
  771. {
  772. if (!(bFlags&HFOPEN_SYSTEM))
  773. {
  774. return HfOpenFileHfsInternal(hfs,sz,bFlags,foNil,phr);
  775. }
  776. else
  777. {
  778. return HfOpenSystemFileHfsInternal(hfs,bFlags,phr);
  779. }
  780. }
  781. #endif
  782. /***************************************************************************
  783. *
  784. * @doc INTERNAL API
  785. *
  786. * @func HF PASCAL FAR | HfCreateFileHfs |
  787. * Create a subfile that lives in the file system. If file already
  788. * exists, it will be truncated to zero first. This API is left in
  789. * for compatibility - HfOpenHfs may be called with the HFOPEN_CREATE
  790. * flag instead.
  791. *
  792. * @parm HFS | hfs |
  793. * File system.
  794. *
  795. * @parm LPCSTR | szFilename |
  796. * Name of file (length limited to 1/2 the block size given when creating
  797. * the file system)
  798. *
  799. * @parm BYTE | bFlags |
  800. * Any of the following HFOPEN_ flags (HFOPEN_CREATE implied)
  801. * @flag HFOPEN_READWRITE | (0x01) Open a file for reading and writing.
  802. * @flag HFOPEN_READ | (0x02) Open a file for reading only.
  803. * @flag HFOPEN_CREATE | (0x04) Create file (implied)
  804. * @flag HFOPEN_NOTEMP | (0x10) If file is opened for read/write, do
  805. * not make a temporary file if possible,
  806. * so edits to the file are made directly
  807. * in the file system.
  808. * @flag HFOPEN_FORCETEMP | (0x20) A temp file is always created (space
  809. * permitting) in read-only mode.
  810. * @flag HFOPEN_ENABLELOGGING| (0x40) Logging usage of this file will be
  811. * enabled.
  812. *
  813. * @parm PHRESULT | phr |
  814. * Error return
  815. *
  816. * @rdesc Returns a valid HF, or hfNil if an error.
  817. *
  818. ***************************************************************************/
  819. #ifndef ITWRAP
  820. PUBLIC HF PASCAL FAR EXPORT_API HfCreateFileHfs(HFS hfs, LPCSTR sz,
  821. BYTE bFlags, PHRESULT phr)
  822. {
  823. bFlags|=HFOPEN_CREATE;
  824. if (!(bFlags&HFOPEN_SYSTEM))
  825. {
  826. return HfOpenFileHfsInternal(hfs,sz,bFlags,foNil,phr);
  827. }
  828. else
  829. {
  830. return HfOpenSystemFileHfsInternal(hfs,bFlags,phr);
  831. }
  832. }
  833. #endif
  834. /***************************************************************************
  835. *
  836. * @doc INTERNAL API
  837. *
  838. * @func HF PASCAL FAR | HfOpenHfsReserve |
  839. * Create or open a subfile that lives in the file system, and reserve
  840. * some space for the file. If creating a file, the space is reserved
  841. * directly in the file system, and all data is written directly to the
  842. * file system.
  843. *
  844. * @parm HFS | hfs |
  845. * File system.
  846. *
  847. * @parm LPCSTR | szFilename |
  848. * Name of file (length limited to 1/2 the block size given when creating
  849. * the file system)
  850. *
  851. * @parm BYTE | bFlags |
  852. * Any of the following HFOPEN_ flags:
  853. * @flag HFOPEN_READWRITE | (0x01) Open a file for reading and writing.
  854. * @flag HFOPEN_READ | (0x02) Open a file for reading only.
  855. * @flag HFOPEN_CREATE | (0x04) Create a new file, or truncate an
  856. * existing file.
  857. * @flag HFOPEN_NOTEMP | (0x10) If file is opened for read/write, do
  858. * not make a temporary file if possible,
  859. * so edits to the file are made directly
  860. * in the file system.
  861. * @flag HFOPEN_FORCETEMP | (0x20) A temp file is always created (space
  862. * permitting) in read-only mode.
  863. *
  864. * @parm FILEOFFSET | foReserve |
  865. * Number of bytes to reserve in the file system. If opening a file
  866. * in r/w mode, and the requested space cannot be reserved, the file
  867. * will be copied to a temp file transparently.
  868. *
  869. * @parm PHRESULT | phr |
  870. * Error return
  871. *
  872. * @rdesc Returns a valid HF, or hfNil if an error.
  873. *
  874. * @comm
  875. * Just leave the HFOPEN_NOTEMP and HFOPEN_FORCETEMP flags alone for
  876. * the default behavior.
  877. *
  878. *
  879. ***************************************************************************/
  880. #ifndef ITWRAP
  881. PUBLIC HF PASCAL FAR EXPORT_API HfOpenHfsReserve(HFS hfs, LPCSTR sz,
  882. BYTE bFlags, FILEOFFSET foReserve, PHRESULT phr)
  883. {
  884. if (!(bFlags&HFOPEN_SYSTEM))
  885. {
  886. return HfOpenFileHfsInternal(hfs,sz,bFlags,foReserve,phr);
  887. }
  888. else
  889. {
  890. SetErrCode(phr, E_INVALIDARG);
  891. return hfNil;
  892. }
  893. }
  894. #endif
  895. /***************************************************************************
  896. *
  897. * @doc INTERNAL API
  898. *
  899. * @func HRESULT PASCAL FAR | RcCopyDosFileHfs |
  900. * Create or open a subfile that lives in the file system, and reserve
  901. * some space for the file. If creating a file, the space is reserved
  902. * directly in the file system, and all data is written directly to the
  903. * file system.
  904. *
  905. * @parm HFS | hfs |
  906. * File system to receive file.
  907. *
  908. * @parm LPCSTR | szFsFilename |
  909. * Name of file used in the file system (any length is OK -- name does not
  910. * have to match the DOS filename). Max length of filename is 64K.
  911. *
  912. * @parm LPCSTR | szDosFilename |
  913. * Pathname of file to copy.
  914. *
  915. * @parm BYTE | bExtraFlags |
  916. * Set to zero for normal files. Use HFOPEN_ENABLELOGGING to enable file
  917. * for logging.
  918. *
  919. * @parm PROGFUNC | lpfnProg |
  920. * Progress callback function (parameter passed to function is always zero).
  921. * Function returns non-zero to interrupt and cancel copy operation.
  922. *
  923. * @rdesc Returns S_OK if all is OK, else the error code.
  924. *
  925. ***************************************************************************/
  926. PUBLIC HRESULT PASCAL FAR EXPORT_API RcCopyDosFileHfs(HFS hfs, LPCSTR szFsFilename, LPCSTR szDosFilename, BYTE bExtraFlags, PROGFUNC lpfnProg)
  927. {
  928. #ifdef MOSMAP // {
  929. // Disable function
  930. return ERR_NOTSUPPORTED;
  931. #else // } {
  932. FID fidSource;
  933. HRESULT errb;
  934. FILEOFFSET foSize;
  935. FILEOFFSET foTemp;
  936. DWORD dwT;
  937. HF hfDest;
  938. QFSHR qfshr;
  939. HRESULT rc=S_OK;
  940. if (szDosFilename==NULL || hfs == NULL || (qfshr = _GLOBALLOCK(hfs)) == NULL)
  941. {
  942. return E_INVALIDARG;
  943. }
  944. if ((fidSource=FidOpenFm((FM)szDosFilename,wReadOnly,&errb))==fidNil)
  945. {
  946. rc=errb;
  947. exit0:
  948. _GLOBALUNLOCK(hfs);
  949. return rc;
  950. }
  951. foSize=FoSeekFid(fidSource,foNil,wSeekEnd,&errb);
  952. FoSeekFid(fidSource,foNil,wSeekSet,&errb);
  953. // insert only the extra flags that we allow here...
  954. bExtraFlags&=HFOPEN_ENABLELOGGING;
  955. #ifndef ITWRAP
  956. if ((hfDest=HfOpenFileHfsInternal(hfs,(szFsFilename)?szFsFilename:szDosFilename,
  957. (BYTE)(HFOPEN_READWRITE|HFOPEN_CREATE|bExtraFlags),
  958. foSize,&errb))==(HF)hfNil)
  959. #else
  960. // erinfox: I'm not sure if this is going to work!
  961. if ((hfDest=HfOpenHfsReserve(hfs,(szFsFilename)?szFsFilename:szDosFilename,
  962. (BYTE)(HFOPEN_READWRITE|HFOPEN_CREATE|bExtraFlags),
  963. foSize,&errb))==(HF)hfNil)
  964. #endif
  965. {
  966. rc=errb;
  967. exit1:
  968. RcCloseFid(fidSource);
  969. goto exit0;
  970. }
  971. _ENTERCRITICALSECTION(&qfshr->sb.cs);
  972. foTemp.dwHigh=0;
  973. do
  974. {
  975. // perform a progress callback
  976. if (lpfnProg)
  977. {
  978. if ((*lpfnProg)(0)!=0)
  979. {
  980. rc=E_INTERRUPT;
  981. exit2:
  982. _LEAVECRITICALSECTION(&qfshr->sb.cs);
  983. RcCloseHf(hfDest);
  984. goto exit1;
  985. }
  986. }
  987. if (!foSize.dwHigh)
  988. dwT = min((DWORD)qfshr->sb.lcbBuffer, foSize.dwOffset);
  989. else
  990. dwT=qfshr->sb.lcbBuffer;
  991. if (LcbReadFid( fidSource, qfshr->sb.lpvBuffer, (LONG)dwT, &errb) != (LONG)dwT )
  992. {
  993. rc=errb;
  994. break;
  995. }
  996. if (LcbWriteHf( hfDest, qfshr->sb.lpvBuffer, (LONG)dwT, &errb) != (LONG)dwT )
  997. {
  998. rc=errb;
  999. break;
  1000. }
  1001. foTemp.dwOffset=dwT;
  1002. foSize=FoSubFo(foSize,foTemp);
  1003. }
  1004. while (!FoIsNil(foSize));
  1005. goto exit2;
  1006. #endif // } MOSMAP
  1007. }
  1008. /***************************************************************************
  1009. *
  1010. * @doc INTERNAL API
  1011. *
  1012. * @func LONG PASCAL FAR | LcbReadHf |
  1013. * Read data from a subfile.
  1014. *
  1015. * @parm HF | hf |
  1016. * Handle to a valid subfile.
  1017. *
  1018. * @parm LPVOID | lpvBuffer |
  1019. * Buffer to receive data (>64K OK)
  1020. *
  1021. * @parm LONG | lcb |
  1022. * Number of bytes to read
  1023. *
  1024. * @parm PHRESULT | phr |
  1025. * Error return
  1026. *
  1027. * @rdesc Returns the number of bytes read. If not lcb, an error occurred.
  1028. *
  1029. * @comm
  1030. * The file pointer is incremented by the number of bytes read. Files
  1031. * may be larger than 4 gigs, but only 2 gigs at a time maximum can be read.
  1032. *
  1033. ***************************************************************************/
  1034. #ifndef ITWRAP
  1035. PUBLIC LONG PASCAL FAR EXPORT_API LcbReadHf(HF hf, LPVOID lpvBuffer,
  1036. LONG lcb, PHRESULT phr)
  1037. {
  1038. QSFB qsfb;
  1039. LONG lRead=0L;
  1040. QFSHR qfshr;
  1041. assert(mv_gsfa);
  1042. assert(mv_gsfa_count);
  1043. if (!FHfValid(hf))
  1044. {
  1045. SetErrCode(phr, E_INVALIDARG);
  1046. return 0L;
  1047. }
  1048. if (mv_gsfa[(DWORD)hf].hsfb == NULL || (qsfb = _GLOBALLOCK(mv_gsfa[(DWORD)hf].hsfb)) == NULL)
  1049. {
  1050. SetErrCode (phr, E_INVALIDARG);
  1051. return 0L;
  1052. }
  1053. assert(qsfb->hvf);
  1054. if (qsfb->hfs == NULL || (qfshr = _GLOBALLOCK(qsfb->hfs)) == NULL)
  1055. {
  1056. SetErrCode (phr, E_INVALIDARG);
  1057. goto exit1;
  1058. }
  1059. _ENTERCRITICALSECTION(&qfshr->cs);
  1060. lRead = VFileSeekRead(qsfb->hvf, mv_gsfa[(DWORD)hf].foCurrent, lpvBuffer, lcb, phr);
  1061. mv_gsfa[(DWORD)hf].foCurrent=FoAddDw(mv_gsfa[(DWORD)hf].foCurrent,lRead);
  1062. _LEAVECRITICALSECTION(&qfshr->cs);
  1063. _GLOBALUNLOCK(qsfb->hfs);
  1064. exit1:
  1065. _GLOBALUNLOCK(mv_gsfa[(DWORD)hf].hsfb);
  1066. return lRead;
  1067. }
  1068. #endif
  1069. /***************************************************************************
  1070. *
  1071. * @doc INTERNAL API
  1072. *
  1073. * @func LONG PASCAL FAR | LcbWriteHf |
  1074. * Write data to a subfile
  1075. *
  1076. * @parm HF | hf |
  1077. * Handle to a valid subfile.
  1078. *
  1079. * @parm LPVOID | lpvBuffer |
  1080. * Buffer to receive data (>64K OK)
  1081. *
  1082. * @parm LONG | lcb |
  1083. * Number of bytes to write
  1084. *
  1085. * @parm PHRESULT | phr |
  1086. * Error return
  1087. *
  1088. * @rdesc Returns the number of bytes written. If not lcb, an error occurred.
  1089. *
  1090. * @comm
  1091. * File pointer is incremented by the number of bytes written. Only 2 gigs
  1092. * maximum at one time can be read, but files can be larger than 4 gigs.
  1093. *
  1094. ***************************************************************************/
  1095. #ifndef ITWRAP
  1096. PUBLIC LONG PASCAL FAR EXPORT_API LcbWriteHf(HF hf, LPVOID lpvBuffer,
  1097. LONG lcb, PHRESULT phr)
  1098. {
  1099. QSFB qsfb;
  1100. LONG lWrote=0L;
  1101. QFSHR qfshr;
  1102. assert(mv_gsfa);
  1103. assert(mv_gsfa_count);
  1104. if (!FHfValid(hf))
  1105. {
  1106. SetErrCode(phr, E_INVALIDARG);
  1107. return 0L;
  1108. }
  1109. if (mv_gsfa[(DWORD)hf].hsfb == NULL || (qsfb = _GLOBALLOCK(mv_gsfa[(DWORD)hf].hsfb)) == NULL)
  1110. {
  1111. SetErrCode (phr, E_INVALIDARG);
  1112. return 0L;
  1113. }
  1114. if (qsfb->bOpenFlags&HFOPEN_READ)
  1115. {
  1116. SetErrCode(phr, E_NOPERMISSION);
  1117. goto exit1;
  1118. }
  1119. if (qsfb->hfs == NULL || (qfshr = _GLOBALLOCK(qsfb->hfs)) == NULL)
  1120. {
  1121. SetErrCode (phr, E_INVALIDARG);
  1122. goto exit1;
  1123. }
  1124. assert(qsfb->hvf);
  1125. _ENTERCRITICALSECTION(&qfshr->cs);
  1126. lWrote = VFileSeekWrite(qsfb->hvf, mv_gsfa[(DWORD)hf].foCurrent, lpvBuffer, lcb, phr);
  1127. mv_gsfa[(DWORD)hf].foCurrent=FoAddDw(mv_gsfa[(DWORD)hf].foCurrent,lWrote);
  1128. _LEAVECRITICALSECTION(&qfshr->cs);
  1129. _GLOBALUNLOCK(qsfb->hfs);
  1130. exit1:
  1131. _GLOBALUNLOCK(mv_gsfa[(DWORD)hf].hsfb);
  1132. return lWrote;
  1133. }
  1134. #endif
  1135. /***************************************************************************
  1136. *
  1137. * @doc INTERNAL API
  1138. *
  1139. * @func FILEOFFSET PASCAL FAR | FoSeekHf |
  1140. * Seeks to a location in the subfile (replaces LSeekHf). To seek
  1141. * beyond 4 gigs, use pdwHigh.
  1142. *
  1143. * @parm HF | hf |
  1144. * Handle to a valid subfile.
  1145. *
  1146. * @parm FILEOFFSET | foOffset |
  1147. * File offset to seek to. For standard 4-byte offsets, the .dwHigh
  1148. * member of foOffset should be zero. When seeking from current
  1149. * position, and the seek is negative, remember that dwHigh should
  1150. * also be 0xffff. Just treat the dwHigh and dwOffset members of
  1151. * foOffset as the High and Low DWORDS of a quad word.
  1152. *
  1153. * @parm WORD | wOrigin |
  1154. * wFSSeekSet (0), wFSSeekCur (1), or wFSSeekEnd (2). When Cur or End,
  1155. * dwOffset is treated as signed.
  1156. *
  1157. * @parm PHRESULT | phr |
  1158. * Error return
  1159. *
  1160. * @rdesc Returns the offset actually pointed to in the file after seeking.
  1161. *
  1162. * @comm
  1163. * The file pointer moved to the given offset, and pdwHigh is
  1164. * set to the high dword if not NULL.
  1165. *
  1166. ***************************************************************************/
  1167. #ifndef ITWRAP
  1168. PUBLIC FILEOFFSET PASCAL FAR EXPORT_API FoSeekHf(HF hf, FILEOFFSET foOffset,
  1169. WORD wOrigin, PHRESULT phr)
  1170. {
  1171. assert(mv_gsfa);
  1172. assert(mv_gsfa_count);
  1173. if (phr)
  1174. phr->err=S_OK;
  1175. switch (wOrigin)
  1176. {
  1177. case wFSSeekSet:
  1178. mv_gsfa[(DWORD)hf].foCurrent=foOffset;
  1179. break;
  1180. case wFSSeekCur:
  1181. mv_gsfa[(DWORD)hf].foCurrent=FoAddFo(mv_gsfa[(DWORD)hf].foCurrent,foOffset);
  1182. break;
  1183. case wFSSeekEnd:
  1184. {
  1185. QSFB qsfb;
  1186. if (mv_gsfa[(DWORD)hf].hsfb == NULL)
  1187. {
  1188. SetErrCode (phr, E_INVALIDARG);
  1189. return mv_gsfa[(DWORD)hf].foCurrent;
  1190. }
  1191. if ((qsfb = _GLOBALLOCK(mv_gsfa[(DWORD)hf].hsfb)) == NULL)
  1192. { SetErrCode (phr, E_OUTOFMEMORY);
  1193. return mv_gsfa[(DWORD)hf].foCurrent;
  1194. }
  1195. assert(qsfb->hvf);
  1196. mv_gsfa[(DWORD)hf].foCurrent=FoAddFo(VFileGetSize(qsfb->hvf,phr),foOffset);
  1197. _GLOBALUNLOCK(mv_gsfa[(DWORD)hf].hsfb);
  1198. break;
  1199. }
  1200. default:
  1201. SetErrCode(phr,E_INVALIDARG);
  1202. }
  1203. return mv_gsfa[(DWORD)hf].foCurrent;
  1204. }
  1205. #endif
  1206. /***************************************************************************
  1207. *
  1208. * @doc INTERNAL API
  1209. *
  1210. * @func FILEOFFSET PASCAL FAR | FoTellHf |
  1211. * Returns position of file pointer. Replaces LTellHf. This function
  1212. * just looks up the file pointer value, so it is fast and can be
  1213. * called any time.
  1214. *
  1215. * @parm HF | hf |
  1216. * Handle to a valid subfile.
  1217. *
  1218. * @parm PHRESULT | phr |
  1219. * Error return
  1220. *
  1221. * @rdesc Returns the file pointer for the given subfile.
  1222. *
  1223. ***************************************************************************/
  1224. PUBLIC FILEOFFSET PASCAL FAR EXPORT_API FoTellHf(HF hf, PHRESULT phr)
  1225. {
  1226. assert(mv_gsfa);
  1227. assert(mv_gsfa_count);
  1228. return mv_gsfa[(DWORD_PTR)hf].foCurrent;
  1229. }
  1230. /***************************************************************************
  1231. *
  1232. * @doc INTERNAL API
  1233. *
  1234. * @func FILEOFFSET PASCAL FAR | FoSizeHf |
  1235. * Returns size of the subfile. Replaces LSizeHf.
  1236. *
  1237. * @parm HF | hf |
  1238. * Handle to a valid subfile.
  1239. *
  1240. * @parm PHRESULT | phr |
  1241. * Error return
  1242. *
  1243. * @rdesc Returns the size of a subfile.
  1244. *
  1245. ***************************************************************************/
  1246. #ifndef ITWRAP
  1247. PUBLIC FILEOFFSET PASCAL FAR EXPORT_API FoSizeHf(HF hf, PHRESULT phr)
  1248. {
  1249. QSFB qsfb;
  1250. FILEOFFSET foSize=foNil;
  1251. assert(mv_gsfa);
  1252. assert(mv_gsfa_count);
  1253. if (mv_gsfa[(DWORD)hf].hsfb == NULL || (qsfb = _GLOBALLOCK(mv_gsfa[(DWORD)hf].hsfb)) == NULL)
  1254. {
  1255. SetErrCode (phr, E_INVALIDARG);
  1256. return foNil;
  1257. }
  1258. assert(qsfb->hvf);
  1259. foSize = VFileGetSize(qsfb->hvf, phr);
  1260. _GLOBALUNLOCK(mv_gsfa[(DWORD)hf].hsfb);
  1261. return foSize;
  1262. }
  1263. #endif
  1264. /***************************************************************************
  1265. *
  1266. * @doc INTERNAL API
  1267. *
  1268. * @func FILEOFFSET PASCAL FAR | FoOffsetHf |
  1269. * Returns offset into the M20 of the subfile.
  1270. *
  1271. * @parm HF | hf |
  1272. * Handle to a valid subfile.
  1273. *
  1274. * @parm PHRESULT | phr |
  1275. * Error return
  1276. *
  1277. * @rdesc Returns the size of a subfile.
  1278. *
  1279. ***************************************************************************/
  1280. PUBLIC FILEOFFSET PASCAL FAR EXPORT_API FoOffsetHf(HF hf, PHRESULT phr)
  1281. {
  1282. QSFB qsfb;
  1283. FILEOFFSET foOffset=foNil;
  1284. assert(mv_gsfa);
  1285. assert(mv_gsfa_count);
  1286. if (mv_gsfa[(DWORD_PTR)hf].hsfb == NULL || (qsfb = _GLOBALLOCK(mv_gsfa[(DWORD_PTR)hf].hsfb)) == NULL)
  1287. {
  1288. SetErrCode (phr, E_INVALIDARG);
  1289. return foNil;
  1290. }
  1291. assert(qsfb->hvf);
  1292. foOffset = qsfb->foHeader;
  1293. _GLOBALUNLOCK(mv_gsfa[(DWORD_PTR)hf].hsfb);
  1294. return foOffset;
  1295. }
  1296. /***************************************************************************
  1297. *
  1298. * @doc INTERNAL API
  1299. *
  1300. * @func BOOL PASCAL FAR | FEofHf |
  1301. * Checks the file pointer for End Of File.
  1302. *
  1303. * @parm HF | hf |
  1304. * Handle to a valid subfile.
  1305. *
  1306. * @parm PHRESULT | phr |
  1307. * Error return
  1308. *
  1309. * @rdesc Returns TRUE if the file pointer is at or beyond the size of
  1310. * the file, else FALSE.
  1311. *
  1312. ***************************************************************************/
  1313. PUBLIC BOOL PASCAL FAR EXPORT_API FEofHf(HF hf, PHRESULT phr)
  1314. {
  1315. QSFB qsfb;
  1316. FILEOFFSET foSize=foNil;
  1317. assert(mv_gsfa);
  1318. assert(mv_gsfa_count);
  1319. if (mv_gsfa[(DWORD_PTR)hf].hsfb == NULL || (qsfb = _GLOBALLOCK(mv_gsfa[(DWORD_PTR)hf].hsfb)) == NULL)
  1320. {
  1321. SetErrCode (phr, E_INVALIDARG);
  1322. return FALSE;
  1323. }
  1324. assert(qsfb->hvf);
  1325. foSize = VFileGetSize(qsfb->hvf, phr);
  1326. _GLOBALUNLOCK(mv_gsfa[(DWORD_PTR)hf].hsfb);
  1327. return (FoCompare(mv_gsfa[(DWORD_PTR)hf].foCurrent,foSize)>=0);
  1328. }
  1329. // Returns TRUE if size changed OK
  1330. /***************************************************************************
  1331. *
  1332. * @doc INTERNAL API
  1333. *
  1334. * @func BOOL PASCAL FAR | FChSizeHf |
  1335. * Change the size of the subfile
  1336. *
  1337. * @parm HF | hf |
  1338. * Handle to a valid subfile.
  1339. *
  1340. * @parm FILEOFFSET | foNewSize |
  1341. * New size of file
  1342. *
  1343. * @parm PHRESULT | phr |
  1344. * Error return
  1345. *
  1346. * @rdesc Returns TRUE if file size changed OK, FALSE otherwise.
  1347. *
  1348. * @comm
  1349. * File pointer is not adjusted if size falls below current
  1350. * current file position.
  1351. *
  1352. ***************************************************************************/
  1353. PUBLIC BOOL PASCAL FAR EXPORT_API FChSizeHf(HF hf, FILEOFFSET foSize, PHRESULT phr)
  1354. {
  1355. QSFB qsfb;
  1356. HRESULT rc;
  1357. QFSHR qfshr;
  1358. assert(mv_gsfa);
  1359. assert(mv_gsfa_count);
  1360. if (mv_gsfa[(DWORD_PTR)hf].hsfb == NULL || (qsfb = _GLOBALLOCK(mv_gsfa[(DWORD_PTR)hf].hsfb)) == NULL)
  1361. {
  1362. SetErrCode (phr, E_INVALIDARG);
  1363. return FALSE;
  1364. }
  1365. assert(qsfb->hvf);
  1366. if (qsfb->hfs == NULL || (qfshr = _GLOBALLOCK(qsfb->hfs)) == NULL)
  1367. {
  1368. SetErrCode (phr, E_INVALIDARG);
  1369. goto exit1;
  1370. }
  1371. _ENTERCRITICALSECTION(&qfshr->cs);
  1372. rc=VFileSetEOF(qsfb->hvf, foSize);
  1373. _LEAVECRITICALSECTION(&qfshr->cs);
  1374. _GLOBALUNLOCK(qsfb->hfs);
  1375. if (rc!=S_OK)
  1376. SetErrCode(phr, rc);
  1377. exit1:
  1378. _GLOBALUNLOCK(mv_gsfa[(DWORD_PTR)hf].hsfb);
  1379. return (rc==S_OK);
  1380. }
  1381. /***************************************************************************
  1382. *
  1383. * @doc PRIVATE
  1384. *
  1385. * @func HRESULT PASCAL NEAR | HsfbRemove |
  1386. * Remove the subfile header block. Multiple HFs can reference a single
  1387. * subfile block, so the block should not be removed unless the lock
  1388. * count has been decremented to zero.
  1389. *
  1390. * @parm HSFB | hsfb |
  1391. * Handle to a valid subfile block
  1392. *
  1393. * @rdesc Returns S_OK if block removed OK.
  1394. *
  1395. * @comm
  1396. * hsfb is removed from linked list
  1397. *
  1398. ***************************************************************************/
  1399. HRESULT PASCAL NEAR EXPORT_API HsfbRemove(HSFB hsfb)
  1400. {
  1401. QSFB qsfb;
  1402. QFSHR qfshr;
  1403. HRESULT rc=S_OK;
  1404. if (hsfb == NULL || (qsfb = _GLOBALLOCK(hsfb)) == NULL)
  1405. {
  1406. return E_INVALIDARG;
  1407. }
  1408. if (qsfb->hvf)
  1409. {
  1410. return E_NOPERMISSION;
  1411. }
  1412. if (!(qsfb->bOpenFlags&HFOPEN_SYSTEM))
  1413. {
  1414. HFS hfs;
  1415. HSFB hsfbNext;
  1416. hfs=qsfb->hfs;
  1417. if (hfs == NULL || (qfshr = _GLOBALLOCK(hfs)) == NULL)
  1418. {
  1419. _GLOBALUNLOCK(hsfb);
  1420. return E_INVALIDARG;
  1421. }
  1422. _ENTERCRITICALSECTION(&qfshr->cs);
  1423. hsfbNext=qsfb->hsfbNext;
  1424. if (qfshr->hsfbFirst==hsfb)
  1425. {
  1426. qfshr->hsfbFirst=hsfbNext;
  1427. }
  1428. else
  1429. {
  1430. HSFB hsfbCursor = qfshr->hsfbFirst;
  1431. QSFB qsfbCursor;
  1432. while (hsfbCursor)
  1433. { HSFB hsfbTemp;
  1434. qsfbCursor=(QSFB)_GLOBALLOCK(hsfbCursor);
  1435. if (qsfbCursor->hsfbNext==hsfb)
  1436. {
  1437. qsfbCursor->hsfbNext=hsfbNext;
  1438. _GLOBALUNLOCK(hsfbCursor);
  1439. break;
  1440. }
  1441. hsfbTemp=qsfbCursor->hsfbNext;
  1442. _GLOBALUNLOCK(hsfbCursor);
  1443. hsfbCursor=hsfbTemp;
  1444. }
  1445. // The block should always be in the list!
  1446. assert(hsfbCursor);
  1447. }
  1448. _LEAVECRITICALSECTION(&qfshr->cs);
  1449. _GLOBALUNLOCK(hfs);
  1450. }
  1451. _GLOBALUNLOCK(hsfb);
  1452. _GLOBALFREE(hsfb);
  1453. return rc;
  1454. }
  1455. /***************************************************************************
  1456. *
  1457. * @doc PRIVATE
  1458. *
  1459. * @func HSFB PASCAL NEAR | HsfbCloseHsfb |
  1460. * Close the actual file associated with this block. This should only
  1461. * be done once the reference count reaches zero.
  1462. *
  1463. * @parm HSFB hsfb
  1464. * Handle to a valid subfile.
  1465. *
  1466. * @parm PHRESULT | phr |
  1467. * Error return
  1468. *
  1469. * @rdesc Returns the next subfile block in the linked list of subfile
  1470. * blocks.
  1471. *
  1472. ***************************************************************************/
  1473. HSFB PASCAL NEAR EXPORT_API HsfbCloseHsfb(HSFB hsfbFirst, PHRESULT phr)
  1474. {
  1475. QSFB qsfb;
  1476. HRESULT errb;
  1477. HRESULT rc=S_OK;
  1478. HSFB hsfbNext=NULL;
  1479. if (hsfbFirst == NULL || (qsfb = _GLOBALLOCK(hsfbFirst)) == NULL)
  1480. {
  1481. SetErrCode(phr,E_OUTOFMEMORY);
  1482. return NULL;
  1483. }
  1484. if (qsfb->hvf==NULL)
  1485. {
  1486. SetErrCode(phr,E_INVALIDARG);
  1487. exit1:
  1488. _GLOBALUNLOCK(hsfbFirst);
  1489. return NULL;
  1490. }
  1491. hsfbNext=qsfb->hsfbNext;
  1492. // If Read Only, the close is easy
  1493. if (qsfb->bOpenFlags&HFOPEN_READ)
  1494. {
  1495. if ((rc=VFileClose(qsfb->hvf))!=S_OK)
  1496. {
  1497. VFileAbandon(qsfb->hvf);
  1498. if ((rc=VFileClose(qsfb->hvf))!=S_OK)
  1499. {
  1500. SetErrCode(phr,rc);
  1501. goto exit1;
  1502. }
  1503. }
  1504. qsfb->hvf=NULL;
  1505. }
  1506. else
  1507. {
  1508. FILEOFFSET foSize=VFileGetSize(qsfb->hvf,&errb);
  1509. HFS hfs;
  1510. QFSHR qfshr;
  1511. hfs=qsfb->hfs;
  1512. if (hfs == NULL || (qfshr = _GLOBALLOCK(hfs)) == NULL)
  1513. {
  1514. SetErrCode(phr,E_OUTOFMEMORY);
  1515. goto exit1;
  1516. }
  1517. _ENTERCRITICALSECTION(&qfshr->cs);
  1518. // Closing a read/write file...
  1519. if (VFileGetFlags(qsfb->hvf,&errb)&VFF_FID)
  1520. {
  1521. FILEOFFSET foLeftOver;
  1522. // If file lives in FS,
  1523. if ((rc=VFileClose(qsfb->hvf))!=S_OK)
  1524. {
  1525. SetErrCode(phr,rc);
  1526. _GLOBALUNLOCK(hfs);
  1527. _LEAVECRITICALSECTION(&qfshr->cs);
  1528. goto exit1;
  1529. }
  1530. qsfb->hvf=NULL;
  1531. foLeftOver=FoSubFo(qsfb->sfh.foBlockSize,foSize);
  1532. assert(qfshr->hfl);
  1533. // Send left over to free list
  1534. if (!FoEquals(foLeftOver,foNil))
  1535. {
  1536. FreeListAdd(qfshr->hfl,FoAddDw(FoAddFo(qsfb->foHeader,foSize),SFHeaderSize(&qsfb->sfh)),
  1537. foLeftOver);
  1538. }
  1539. }
  1540. else
  1541. {
  1542. // If file lives in temp file
  1543. // Find free spot for file
  1544. if (qsfb->bOpenFlags&HFOPEN_READWRITE)
  1545. {
  1546. assert(qfshr->hfl);
  1547. if (!FoIsNil(qsfb->foHeader)) // File already lives in FS
  1548. {
  1549. if (FoCompare(foSize,qsfb->sfh.foBlockSize)<=0)
  1550. {
  1551. // It fits back into old slot!!!
  1552. FILEOFFSET foLeftOver=FoSubFo(qsfb->sfh.foBlockSize,foSize);
  1553. if (!FoIsNil(foLeftOver))
  1554. {
  1555. FreeListAdd(qfshr->hfl,
  1556. FoAddDw(FoAddFo(qsfb->foHeader,foSize),SFHeaderSize(&qsfb->sfh)),
  1557. foLeftOver);
  1558. }
  1559. }
  1560. else
  1561. {
  1562. FreeListAdd(qfshr->hfl,qsfb->foHeader,
  1563. FoAddDw(qsfb->sfh.foBlockSize,SFHeaderSize(&qsfb->sfh)));
  1564. qsfb->foHeader=GetFreeBlock(qfshr,FoAddDw(foSize,SFHeaderSize(&qsfb->sfh)),NULL);
  1565. }
  1566. }
  1567. else
  1568. {
  1569. qsfb->foHeader=GetFreeBlock(qfshr,FoAddDw(foSize,SFHeaderSize(&qsfb->sfh)),NULL);
  1570. }
  1571. VFileSetBase(qsfb->hvf,qfshr->fid,FoAddDw(qsfb->foHeader,SFHeaderSize(&qsfb->sfh)),foSize);
  1572. }
  1573. else
  1574. VFileAbandon(qsfb->hvf);
  1575. VFileClose(qsfb->hvf);
  1576. qsfb->hvf=NULL;
  1577. }
  1578. // Update structs
  1579. qsfb->sfh.foBlockSize=foSize;
  1580. // Update btree if necessary (always for now)
  1581. if (!(qsfb->bOpenFlags&HFOPEN_SYSTEM))
  1582. {
  1583. FILE_REC fr;
  1584. KEY key = NewKeyFromSz(qsfb->rgchKey);
  1585. qsfb->sfh.bFlags&=(~SFH_INVALID);
  1586. SetFrData(&fr,qsfb->foHeader,qsfb->sfh.foBlockSize,qsfb->sfh.bFlags);
  1587. //fr.lifBase=qsfb->foHeader.lOffset;
  1588. if ((rc = RcUpdateHbt(qfshr->hbt, key, &fr))!=S_OK)
  1589. {
  1590. // Can't update btree??? What now???
  1591. if ((rc = RcUpdateHbt(qfshr->hbt, key, &fr))!=S_OK)
  1592. {
  1593. // Place breakpoint above... this should never happen.
  1594. }
  1595. }
  1596. DisposeMemory((LPSTR)key);
  1597. }
  1598. else
  1599. {
  1600. qfshr->fsh.foDirectory=qsfb->foHeader;
  1601. qfshr->fsh.sfhSystem=qsfb->sfh;
  1602. }
  1603. _LEAVECRITICALSECTION(&qfshr->cs);
  1604. _GLOBALUNLOCK(hfs);
  1605. }
  1606. _GLOBALUNLOCK(hsfbFirst);
  1607. return hsfbNext;
  1608. }
  1609. /***************************************************************************
  1610. *
  1611. * @doc PRIVATE
  1612. *
  1613. * @func HRESULT PASCAL NEAR | RcFlushHsfb |
  1614. * Flush the subfile block by ensuring the file it refers to is copied
  1615. * into the file system, and the btree entry is up to date with the
  1616. * current file size.
  1617. *
  1618. * @parm HF | hsfb |
  1619. * Handle to a valid subfile block.
  1620. *
  1621. * @rdesc Returns S_OK if subfile flushed OK.
  1622. *
  1623. ***************************************************************************/
  1624. HRESULT PASCAL NEAR EXPORT_API RcFlushHsfb(HSFB hsfbFirst)
  1625. {
  1626. QSFB qsfb;
  1627. HRESULT errb;
  1628. HRESULT rc=S_OK;
  1629. if (hsfbFirst == NULL || (qsfb = _GLOBALLOCK(hsfbFirst)) == NULL)
  1630. {
  1631. rc=E_OUTOFMEMORY;
  1632. return rc;
  1633. }
  1634. if (qsfb->hvf==NULL)
  1635. {
  1636. rc=E_INVALIDARG;
  1637. exit1:
  1638. _GLOBALUNLOCK(hsfbFirst);
  1639. return rc;
  1640. }
  1641. // If Read Only, the flush is easy
  1642. if (qsfb->bOpenFlags&HFOPEN_READ)
  1643. {
  1644. goto exit1;
  1645. }
  1646. else
  1647. {
  1648. FILEOFFSET foSize=VFileGetSize(qsfb->hvf,&errb);
  1649. HFS hfs;
  1650. QFSHR qfshr;
  1651. hfs=qsfb->hfs;
  1652. if (hfs == NULL || (qfshr = _GLOBALLOCK(hfs)) == NULL)
  1653. {
  1654. rc=E_OUTOFMEMORY;
  1655. goto exit1;
  1656. }
  1657. _ENTERCRITICALSECTION(&qfshr->cs);
  1658. // Copy r/w temp file to file system if needed
  1659. // Closing a read/write file...
  1660. if (VFileGetFlags(qsfb->hvf,&errb)&VFF_FID)
  1661. {
  1662. // Leave extra large block allocated to this file if there already
  1663. }
  1664. else
  1665. {
  1666. // If file lives in temp file
  1667. // Find free spot for file
  1668. assert(qfshr->hfl);
  1669. if (!FoIsNil(qsfb->foHeader)) // File already lives in FS
  1670. {
  1671. if (FoCompare(foSize,qsfb->sfh.foBlockSize)<=0)
  1672. {
  1673. // It fits back into old slot!!!
  1674. }
  1675. else
  1676. {
  1677. FILEOFFSET foExtraBytes;
  1678. FreeListAdd(qfshr->hfl,qsfb->foHeader,
  1679. FoAddDw(qsfb->sfh.foBlockSize,SFHeaderSize(&qsfb->sfh)));
  1680. qsfb->foHeader=GetFreeBlock(qfshr,FoAddDw(foSize,SFHeaderSize(&qsfb->sfh)),NULL);
  1681. foExtraBytes=FreeListGetBlockAt(qfshr->hfl,FoAddFo(qsfb->foHeader,foSize),NULL);
  1682. qsfb->sfh.foBlockSize=FoAddFo(foSize,foExtraBytes);
  1683. }
  1684. }
  1685. else
  1686. {
  1687. qsfb->foHeader=GetFreeBlock(qfshr,FoAddDw(foSize,SFHeaderSize(&qsfb->sfh)),NULL);
  1688. if (!FoIsNil(qsfb->foHeader))
  1689. qsfb->sfh.foBlockSize=foSize;
  1690. }
  1691. VFileSetBase(qsfb->hvf,qfshr->fid,FoAddDw(qsfb->foHeader,SFHeaderSize(&qsfb->sfh)),qsfb->sfh.foBlockSize);
  1692. }
  1693. // Update btree if necessary (always for now)
  1694. if (!(qsfb->bOpenFlags&HFOPEN_SYSTEM))
  1695. {
  1696. FILE_REC fr;
  1697. KEY key = NewKeyFromSz(qsfb->rgchKey);
  1698. // Update with proper file size instead of allocated size, in case we crash,
  1699. // then this is the true file size at this moment.
  1700. qsfb->sfh.bFlags&=(~SFH_INVALID);
  1701. SetFrData(&fr,qsfb->foHeader,foSize,qsfb->sfh.bFlags); // 0 flag now, since file is no longer invalid
  1702. rc = RcUpdateHbt(qfshr->hbt, key, &fr);
  1703. DisposeMemory((LPSTR)key);
  1704. }
  1705. else
  1706. {
  1707. qfshr->fsh.foDirectory=qsfb->foHeader;
  1708. qfshr->fsh.sfhSystem=qsfb->sfh;
  1709. // Update with proper file size instead of allocated size, in case we crash,
  1710. // then this is the true file size at this moment.
  1711. qfshr->fsh.sfhSystem.foBlockSize=foSize;
  1712. }
  1713. FidFlush(qfshr->fid);
  1714. _LEAVECRITICALSECTION(&qfshr->cs);
  1715. _GLOBALUNLOCK(hfs);
  1716. }
  1717. _GLOBALUNLOCK(hsfbFirst);
  1718. return rc;
  1719. }
  1720. /***************************************************************************
  1721. *
  1722. * @doc INTERNAL API
  1723. *
  1724. * @func HRESULT PASCAL FAR | RcAbandonHf |
  1725. * Abandon the creation of a new subfile.
  1726. *
  1727. * @parm HF | hf |
  1728. * Handle to a valid subfile.
  1729. *
  1730. * @rdesc Returns S_OK if file creation abandonded OK.
  1731. *
  1732. ***************************************************************************/
  1733. PUBLIC HRESULT PASCAL FAR EXPORT_API RcAbandonHf(HF hf)
  1734. {
  1735. QSFB qsfb;
  1736. HFS hfs;
  1737. QFSHR qfshr;
  1738. assert(mv_gsfa);
  1739. assert(mv_gsfa_count);
  1740. if (mv_gsfa[(DWORD_PTR)hf].hsfb == NULL || (qsfb = _GLOBALLOCK(mv_gsfa[(DWORD_PTR)hf].hsfb)) == NULL)
  1741. {
  1742. return E_OUTOFMEMORY;
  1743. }
  1744. hfs=qsfb->hfs;
  1745. if (hfs == NULL || (qfshr = _GLOBALLOCK(hfs)) == NULL)
  1746. {
  1747. _GLOBALUNLOCK(mv_gsfa[(DWORD_PTR)hf].hsfb);
  1748. return E_OUTOFMEMORY;
  1749. }
  1750. _ENTERCRITICALSECTION(&qfshr->cs);
  1751. assert(qsfb->hvf);
  1752. qsfb->wLockCount--;
  1753. if (!qsfb->wLockCount)
  1754. {
  1755. // We should free the hsfb
  1756. if(qsfb->bOpenFlags&HFOPEN_READWRITE)
  1757. {
  1758. FILE_REC fr;
  1759. KEY key;
  1760. assert(qsfb->hvf);
  1761. VFileAbandon(qsfb->hvf); // Should abandon automatically do close too?
  1762. VFileClose(qsfb->hvf);
  1763. qsfb->hvf=NULL;
  1764. key = NewKeyFromSz(qsfb->rgchKey);
  1765. // Do error checking here to signal if Abandon fails???
  1766. // Remove from btree if we just now inserted it
  1767. RcLookupByKey(qfshr->hbt, key, NULL, &fr);
  1768. GetFrData(&fr);
  1769. if (fr.bFlags&SFH_INVALID)
  1770. {
  1771. RcDeleteHbt(qfshr->hbt, key);
  1772. }
  1773. DisposeMemory((LPSTR)key);
  1774. _GLOBALUNLOCK(mv_gsfa[(DWORD_PTR)hf].hsfb);
  1775. HsfbRemove(mv_gsfa[(DWORD_PTR)hf].hsfb);
  1776. }
  1777. else
  1778. {
  1779. _GLOBALUNLOCK(mv_gsfa[(DWORD_PTR)hf].hsfb);
  1780. _GLOBALFREE(mv_gsfa[(DWORD_PTR)hf].hsfb);
  1781. }
  1782. }
  1783. else
  1784. {
  1785. // subfile block still valid, since it has a lock count
  1786. _GLOBALUNLOCK(mv_gsfa[(DWORD_PTR)hf].hsfb);
  1787. }
  1788. _LEAVECRITICALSECTION(&qfshr->cs);
  1789. _GLOBALUNLOCK(hfs);
  1790. // This hf is no longer valid
  1791. mv_gsfa[(DWORD_PTR)hf].hsfb=NULL;
  1792. #ifdef _DEBUGMVFS
  1793. DPF2("HfAbandon: hf=%d, %d\n", hf, 0);
  1794. DumpMV_GSFA();
  1795. #endif
  1796. return S_OK;
  1797. }
  1798. /***************************************************************************
  1799. *
  1800. * @doc INTERNAL API
  1801. *
  1802. * @func HRESULT PASCAL FAR | RcFlushHf |
  1803. * Flush the subfile by ensuring it is written in the file system
  1804. *
  1805. * @parm HF | hf |
  1806. * Handle to a valid subfile.
  1807. *
  1808. * @rdesc Returns S_OK if flushed OK.
  1809. *
  1810. ***************************************************************************/
  1811. PUBLIC HRESULT PASCAL FAR EXPORT_API RcFlushHf(HF hf)
  1812. {
  1813. QSFB qsfb;
  1814. HRESULT rc=S_OK;
  1815. assert(mv_gsfa);
  1816. assert(mv_gsfa_count);
  1817. if (mv_gsfa[(DWORD_PTR)hf].hsfb == NULL || (qsfb = _GLOBALLOCK(mv_gsfa[(DWORD_PTR)hf].hsfb)) == NULL)
  1818. {
  1819. return E_INVALIDARG;
  1820. }
  1821. if (qsfb->bOpenFlags&HFOPEN_READWRITE)
  1822. {
  1823. // Copy back to M20 file if necessary
  1824. // Update btree info
  1825. rc=RcFlushHsfb(mv_gsfa[(DWORD_PTR)hf].hsfb);
  1826. }
  1827. _GLOBALUNLOCK(mv_gsfa[(DWORD_PTR)hf].hsfb);
  1828. return (rc);
  1829. }
  1830. /***************************************************************************
  1831. *
  1832. * @doc INTERNAL API
  1833. *
  1834. * @func HRESULT PASCAL FAR | RcCloseEveryHf |
  1835. * Close every opened subfile. This should only be used in emergency
  1836. * cases to safely close all subfiles. Ideally, the calling application
  1837. * should close the subfiles as necessary, and never call this function.
  1838. *
  1839. * @parm HFS | hfs |
  1840. * Handle to a valid file system
  1841. *
  1842. * @rdesc Returns S_OK if all files closed OK.
  1843. *
  1844. ***************************************************************************/
  1845. PUBLIC HRESULT PASCAL FAR EXPORT_API RcCloseEveryHf(HFS hfs)
  1846. {
  1847. QFSHR qfshr;
  1848. HRESULT errb;
  1849. HRESULT rc = S_OK;
  1850. if (hfs == NULL || (qfshr = _GLOBALLOCK(hfs)) == NULL)
  1851. {
  1852. return(E_INVALIDARG);
  1853. }
  1854. _ENTERCRITICALSECTION(&qfshr->cs);
  1855. while (qfshr->hsfbFirst)
  1856. {
  1857. HSFB hsfbNext;
  1858. errb=S_OK;
  1859. hsfbNext=HsfbCloseHsfb(qfshr->hsfbFirst, &errb);
  1860. if (errb==S_OK)
  1861. {
  1862. int q;
  1863. rc=HsfbRemove(qfshr->hsfbFirst); // destroys handle too
  1864. // now remove from our global array any left over references
  1865. for (q=1;q<giMaxSubFiles;q++)
  1866. if (mv_gsfa[q].hsfb==qfshr->hsfbFirst)
  1867. {
  1868. mv_gsfa[q].hsfb=NULL;
  1869. mv_gsfa[q].foCurrent=foNil;
  1870. }
  1871. }
  1872. qfshr->hsfbFirst=hsfbNext;
  1873. }
  1874. _LEAVECRITICALSECTION(&qfshr->cs);
  1875. _GLOBALUNLOCK(hfs);
  1876. #ifdef _DEBUGMVFS
  1877. DPF2("RcCloseEveryHf: hfs=%d, %d\n", hfs, 0);
  1878. DumpMV_GSFA();
  1879. #endif
  1880. return S_OK;
  1881. }
  1882. #ifdef _DEBUGMVFS
  1883. void DumpMV_GSFA(void)
  1884. {
  1885. int q;
  1886. QSFB qsfb;
  1887. HANDLE h;
  1888. QFSHR qfshr;
  1889. if (mv_gsfa == NULL)
  1890. {
  1891. DPF2("mv_gsfa is EMPTY (%d, %d)\n",0,0);
  1892. return;
  1893. }
  1894. DPF2("mv_gsfa_count=%ld, giMaxSubfiles=%ld\n", mv_gsfa_count, giMaxSubFiles);
  1895. for (q=1;q<giMaxSubFiles;q++)
  1896. if ((h = mv_gsfa[q].hsfb) && (qsfb = _GLOBALLOCK(h)))
  1897. {
  1898. if (qfshr = _GLOBALLOCK(qsfb->hfs))
  1899. {
  1900. DPF4("mv_gsfa[%d]: qsfb->hfs=%ld ,qfshr->fid=%ld, wLock=%ld\n", \
  1901. q, qsfb->hfs, qfshr->fid, qsfb->wLockCount);
  1902. _GLOBALUNLOCK(qsfb->hfs);
  1903. }
  1904. _GLOBALUNLOCK(h);
  1905. }
  1906. }
  1907. #endif
  1908. /***************************************************************************
  1909. *
  1910. * @doc INTERNAL API
  1911. *
  1912. * @func HRESULT PASCAL FAR | RcFlushEveryHf |
  1913. * Flush every opened subfile. This should only be used in emergency
  1914. * cases to flush all subfiles.
  1915. *
  1916. * @parm HFS | hfs |
  1917. * Handle to a valid file system
  1918. *
  1919. * @rdesc Returns S_OK if all files flushed OK.
  1920. *
  1921. ***************************************************************************/
  1922. PUBLIC HRESULT PASCAL FAR EXPORT_API RcFlushEveryHf(HFS hfs)
  1923. {
  1924. QFSHR qfshr;
  1925. HSFB hsfbCursor;
  1926. HRESULT rc = S_OK;
  1927. if (hfs == NULL || (qfshr = _GLOBALLOCK(hfs)) == NULL)
  1928. {
  1929. return(E_INVALIDARG);
  1930. }
  1931. _ENTERCRITICALSECTION(&qfshr->cs);
  1932. hsfbCursor=qfshr->hsfbFirst;
  1933. while (hsfbCursor)
  1934. {
  1935. HSFB hsfbNext=NULL;
  1936. QSFB qsfb;
  1937. if (!(qsfb = _GLOBALLOCK(hsfbCursor)))
  1938. {
  1939. rc=E_OUTOFMEMORY;
  1940. exit1:
  1941. _LEAVECRITICALSECTION(&qfshr->cs);
  1942. _GLOBALUNLOCK(hfs);
  1943. return rc;
  1944. }
  1945. hsfbNext=qsfb->hsfbNext;
  1946. if ((rc=RcFlushHsfb(hsfbCursor))!=S_OK)
  1947. {
  1948. _GLOBALUNLOCK(hsfbCursor);
  1949. goto exit1;
  1950. }
  1951. _GLOBALUNLOCK(hsfbCursor);
  1952. hsfbCursor=hsfbNext;
  1953. }
  1954. goto exit1;
  1955. }
  1956. /***************************************************************************
  1957. *
  1958. * @doc INTERNAL API
  1959. *
  1960. * @func HRESULT PASCAL FAR | RcCloseHf |
  1961. * Close the subfile. All data is written back into the file system
  1962. * and the directory btree is updated with the file's size.
  1963. *
  1964. * @parm HF | hf |
  1965. * Handle to a valid subfile
  1966. *
  1967. * @rdesc Returns S_OK if all files closed OK.
  1968. *
  1969. ***************************************************************************/
  1970. #ifndef ITWRAP
  1971. PUBLIC HRESULT PASCAL FAR EXPORT_API RcCloseHf(HF hf)
  1972. {
  1973. QSFB qsfb;
  1974. QFSHR qfshr;
  1975. FILEOFFSET foSize=foNil;
  1976. HRESULT rc=S_OK;
  1977. BOOL bFreeBlock=FALSE;
  1978. HFS hfs;
  1979. assert(mv_gsfa);
  1980. assert(mv_gsfa_count);
  1981. if (mv_gsfa[(DWORD)hf].hsfb == NULL || (qsfb = _GLOBALLOCK(mv_gsfa[(DWORD)hf].hsfb)) == NULL)
  1982. {
  1983. return E_INVALIDARG;
  1984. }
  1985. hfs=qsfb->hfs;
  1986. if (hfs == NULL || (qfshr = _GLOBALLOCK(hfs)) == NULL)
  1987. {
  1988. _GLOBALUNLOCK(mv_gsfa[(DWORD)hf].hsfb);
  1989. return E_INVALIDARG;
  1990. }
  1991. _ENTERCRITICALSECTION(&qfshr->cs);
  1992. assert(qsfb->hvf);
  1993. qsfb->wLockCount--;
  1994. if (!qsfb->wLockCount)
  1995. {
  1996. HRESULT errb;
  1997. _GLOBALUNLOCK(mv_gsfa[(DWORD)hf].hsfb);
  1998. errb.err=S_OK;
  1999. HsfbCloseHsfb(mv_gsfa[(DWORD)hf].hsfb, &errb);
  2000. rc=errb.err;
  2001. if (rc==S_OK)
  2002. {
  2003. rc=HsfbRemove(mv_gsfa[(DWORD)hf].hsfb); // destroys handle too
  2004. mv_gsfa[(DWORD)hf].hsfb=NULL;
  2005. }
  2006. }
  2007. else
  2008. {
  2009. _GLOBALUNLOCK(mv_gsfa[(DWORD)hf].hsfb);
  2010. mv_gsfa[(DWORD)hf].hsfb=NULL;
  2011. }
  2012. _LEAVECRITICALSECTION(&qfshr->cs);
  2013. _GLOBALUNLOCK(hfs);
  2014. #ifdef _DEBUGMVFS
  2015. DPF2("RcCloseHf: hfs=%d, hf=%d\n", hfs, hf);
  2016. DumpMV_GSFA();
  2017. #endif
  2018. return (rc);
  2019. }
  2020. #endif
  2021. /***************************************************************************
  2022. *
  2023. * @doc INTERNAL API
  2024. *
  2025. * @func HRESULT PASCAL FAR | RcUnlinkFileHfs |
  2026. * Remove a subfile from the file system. The file should not be opened
  2027. * by any other processes when it is removed.
  2028. *
  2029. * @parm HFS | hfs |
  2030. * Handle to a valid file system
  2031. *
  2032. * @parm LPCSTR | szFileName |
  2033. * Name of file in file system to remove
  2034. *
  2035. * @rdesc Returns S_OK if file deleted OK.
  2036. *
  2037. ***************************************************************************/
  2038. PUBLIC HRESULT PASCAL FAR EXPORT_API RcUnlinkFileHfs(HFS hfs, LPCSTR sz)
  2039. {
  2040. #ifdef MOSMAP // {
  2041. // Disable function
  2042. return (ERR_NOTSUPPORTED);
  2043. #else // } {
  2044. QFSHR qfshr;
  2045. FILE_REC fr;
  2046. HRESULT errb;
  2047. KEY key;
  2048. HRESULT rc=S_OK;
  2049. if (hfs == NULL || (qfshr = _GLOBALLOCK(hfs)) == NULL)
  2050. {
  2051. return SetErrCode (&errb, E_INVALIDARG);
  2052. }
  2053. key = NewKeyFromSz(sz);
  2054. if (qfshr->fsh.bFlags & FSH_READONLY)
  2055. {
  2056. rc=SetErrCode (&errb, E_NOPERMISSION);
  2057. exit0:
  2058. DisposeMemory((LPSTR)key);
  2059. _GLOBALUNLOCK(hfs);
  2060. return rc;
  2061. }
  2062. _ENTERCRITICALSECTION(&qfshr->cs);
  2063. // check for File In Use ???
  2064. /* look it up to get the file base offset */
  2065. if ((rc = RcLookupByKey (qfshr->hbt, key, NULL, &fr)) != S_OK)
  2066. {
  2067. exit1:
  2068. _LEAVECRITICALSECTION(&qfshr->cs);
  2069. goto exit0;
  2070. }
  2071. GetFrData(&fr);
  2072. if (fr.bFlags&SFH_LOCKED)
  2073. { rc=SetErrCode(&errb, E_NOPERMISSION);
  2074. goto exit1;
  2075. }
  2076. assert(qfshr->hfl);
  2077. if ((rc = RcDeleteHbt (qfshr->hbt, key)) == S_OK)
  2078. {
  2079. /* put the file block on the free list */
  2080. //SFH sfh;
  2081. FreeListAdd(qfshr->hfl,fr.foStart,fr.foSize);
  2082. //if ((FoEquals(FoSeekFid(qfshr->fid, fr.fo, wSeekSet, &errb),fr.fo)) &&
  2083. // (LcbWriteFid(qfshr->fid, &sfh,sizeof(SFH),&errb)==sizeof(SFH)))
  2084. //{
  2085. // FreeListAdd(qfshr->hfl,fr.fo,(LONG)sfh.foBlockSize);
  2086. //}
  2087. }
  2088. DisposeMemory((LPSTR)key);
  2089. _LEAVECRITICALSECTION(&qfshr->cs);
  2090. _GLOBALUNLOCK(hfs);
  2091. return rc;
  2092. #endif //}
  2093. }
  2094. /***************************************************************************
  2095. *
  2096. * @doc INTERNAL API
  2097. *
  2098. * @func HRESULT PASCAL FAR | SetFileFlags |
  2099. * Set the Logging or Locking state of a file
  2100. *
  2101. * @parm HFS | hfs |
  2102. * Handle to a valid file system
  2103. *
  2104. * @parm LPCSTR | szFileName |
  2105. * Name of file in file system to set bits of
  2106. *
  2107. * @parm BYTE | bFlags |
  2108. * SFH_LOGGING or SFH_LOCKED
  2109. *
  2110. * @rdesc Returns S_OK if flags set OK
  2111. *
  2112. ***************************************************************************/
  2113. PUBLIC HRESULT PASCAL FAR EXPORT_API SetFileFlags(HFS hfs, LPCSTR sz, BYTE bFlags)
  2114. {
  2115. #ifdef MOSMAP // {
  2116. // Disable function
  2117. return (ERR_NOTSUPPORTED);
  2118. #else // } {
  2119. QFSHR qfshr;
  2120. FILE_REC fr;
  2121. HRESULT errb;
  2122. KEY key;
  2123. HRESULT rc=S_OK;
  2124. if (hfs == NULL || (qfshr = _GLOBALLOCK(hfs)) == NULL)
  2125. {
  2126. return SetErrCode (&errb, E_INVALIDARG);
  2127. }
  2128. key = NewKeyFromSz(sz);
  2129. if (qfshr->fsh.bFlags & FSH_READONLY)
  2130. {
  2131. rc=SetErrCode (&errb, E_NOPERMISSION);
  2132. exit0:
  2133. DisposeMemory((LPSTR)key);
  2134. _GLOBALUNLOCK(hfs);
  2135. return rc;
  2136. }
  2137. _ENTERCRITICALSECTION(&qfshr->cs);
  2138. // check for File In Use ???
  2139. /* look it up to get the file base offset */
  2140. if ((rc = RcLookupByKey (qfshr->hbt, key, NULL, &fr)) != S_OK)
  2141. {
  2142. _LEAVECRITICALSECTION(&qfshr->cs);
  2143. goto exit0;
  2144. }
  2145. GetFrData(&fr);
  2146. fr.bFlags=fr.bFlags&(~SFH_FILEFLAGS);
  2147. bFlags&=SFH_FILEFLAGS;
  2148. fr.bFlags|=bFlags;
  2149. SetFrData(&fr,fr.foStart,fr.foSize,fr.bFlags);
  2150. //fr.lifBase=qsfb->foHeader.lOffset;
  2151. if ((rc = RcUpdateHbt(qfshr->hbt, key, &fr))!=S_OK)
  2152. {
  2153. // Can't update btree??? What now???
  2154. }
  2155. DisposeMemory((LPSTR)key);
  2156. _LEAVECRITICALSECTION(&qfshr->cs);
  2157. _GLOBALUNLOCK(hfs);
  2158. return rc;
  2159. #endif //}
  2160. }
  2161. /***************************************************************************
  2162. *
  2163. * @doc INTERNAL API
  2164. *
  2165. * @func BYTE PASCAL FAR | GetFileFlags |
  2166. * Get the Logging or Locking state of a file
  2167. *
  2168. * @parm HFS | hfs |
  2169. * Handle to a valid file system
  2170. *
  2171. * @parm LPCSTR | szFileName |
  2172. * Name of file in file system to set bits of
  2173. *
  2174. * @parm PHRESULT | phr |
  2175. * Error return code
  2176. *
  2177. * @rdesc Returns zero or any combination of SFH_LOGGING and SFH_LOCKED
  2178. *
  2179. ***************************************************************************/
  2180. PUBLIC BYTE PASCAL FAR EXPORT_API GetFileFlags(HFS hfs, LPCSTR sz, PHRESULT phr)
  2181. {
  2182. #ifdef MOSMAP // {
  2183. // Disable function
  2184. return (ERR_NOTSUPPORTED);
  2185. #else // } {
  2186. QFSHR qfshr;
  2187. FILE_REC fr;
  2188. KEY key;
  2189. HRESULT rc;
  2190. *phr=S_OK;
  2191. if (hfs == NULL || (qfshr = _GLOBALLOCK(hfs)) == NULL)
  2192. {
  2193. SetErrCode (phr, E_INVALIDARG);
  2194. return 0;
  2195. }
  2196. key = NewKeyFromSz(sz);
  2197. if (qfshr->fsh.bFlags & FSH_READONLY)
  2198. {
  2199. SetErrCode (phr, E_NOPERMISSION);
  2200. exit0:
  2201. DisposeMemory((LPSTR)key);
  2202. _GLOBALUNLOCK(hfs);
  2203. return 0;
  2204. }
  2205. _ENTERCRITICALSECTION(&qfshr->cs);
  2206. // check for File In Use ???
  2207. /* look it up to get the file base offset */
  2208. if ((rc = RcLookupByKey (qfshr->hbt, key, NULL, &fr)) != S_OK)
  2209. {
  2210. _LEAVECRITICALSECTION(&qfshr->cs);
  2211. SetErrCode(phr,rc);
  2212. goto exit0;
  2213. }
  2214. GetFrData(&fr);
  2215. fr.bFlags=fr.bFlags&(~SFH_FILEFLAGS);
  2216. DisposeMemory((LPSTR)key);
  2217. _LEAVECRITICALSECTION(&qfshr->cs);
  2218. _GLOBALUNLOCK(hfs);
  2219. return fr.bFlags;
  2220. #endif //}
  2221. }
  2222. /***************************************************************************
  2223. *
  2224. * @doc INTERNAL API
  2225. *
  2226. * @func BOOL PASCAL FAR | FAccessHfs |
  2227. * Check whether a sub file has specific attributes.
  2228. *
  2229. * @parm HFS | hfs |
  2230. * Handle to a valid file system
  2231. *
  2232. * @parm LPCSTR | szFileName |
  2233. * Name of subfile to check
  2234. *
  2235. * @parm BYTE | bFlags |
  2236. * Any one of the following attributes:
  2237. * @flag FACCESS_EXISTS | Does the file exist?
  2238. * @flag FACCESS_READWRITE | Can we open the file for read/write?
  2239. * @flag FACCESS_READ | Can we open the file for reading?
  2240. * @flag FACCESS_LIVESINFS | Does the file live in the file system now?
  2241. * @flag FACCESS_LIVESINTEMP | Does the file live in a temporary file on th HD now?
  2242. *
  2243. * @parm PHRESULT | phr |
  2244. * Error return
  2245. *
  2246. * @rdesc Returns TRUE if the file has the given attribute. Error code
  2247. * will not be S_OK if an error occurred.
  2248. *
  2249. ***************************************************************************/
  2250. #ifndef ITWRAP
  2251. PUBLIC BOOL PASCAL FAR EXPORT_API FAccessHfs( HFS hfs, LPCSTR szName, BYTE bFlags, PHRESULT phr)
  2252. {
  2253. QFSHR qfshr;
  2254. FILE_REC fr;
  2255. KEY key;
  2256. BOOL bSuccess=FALSE;
  2257. HRESULT rc;
  2258. //SetErrCode (phr, S_OK);
  2259. if (hfs == NULL || (qfshr = _GLOBALLOCK(hfs)) == NULL)
  2260. {
  2261. SetErrCode (phr, E_INVALIDARG);
  2262. return bSuccess;
  2263. }
  2264. key = NewKeyFromSz(szName);
  2265. _ENTERCRITICALSECTION(&qfshr->cs);
  2266. rc = RcLookupByKey (qfshr->hbt, key, NULL, &fr);
  2267. _LEAVECRITICALSECTION(&qfshr->cs);
  2268. if (rc==S_OK)
  2269. {
  2270. if (bFlags&FACCESS_EXISTS)
  2271. bSuccess=TRUE;
  2272. else
  2273. {
  2274. HSFB hsfbCursor;
  2275. // Look up subfile block and check for permissions
  2276. hsfbCursor = qfshr->hsfbFirst;
  2277. while (hsfbCursor)
  2278. {
  2279. HSFB hsfbNext;
  2280. QSFB qsfb;
  2281. if (!(qsfb = _GLOBALLOCK(hsfbCursor)))
  2282. {
  2283. SetErrCode(phr,E_OUTOFMEMORY);
  2284. goto exit1;
  2285. }
  2286. hsfbNext=qsfb->hsfbNext;
  2287. if (FoEquals(qsfb->foHeader,fr.foStart))
  2288. {
  2289. // Cannot open for read/write...
  2290. if ((!(qsfb->bOpenFlags&HFOPEN_READWRITE)) && (bFlags&FACCESS_READ))
  2291. {
  2292. // Can open for read
  2293. bSuccess=TRUE;
  2294. }
  2295. else if (bFlags&(FACCESS_LIVESINFS|FACCESS_LIVESINTEMP))
  2296. {
  2297. // find out where this opened file lives
  2298. DWORD dwVFileFlags = VFileGetFlags(qsfb->hvf,NULL);
  2299. if (((dwVFileFlags&VFF_TEMP) && (bFlags&FACCESS_LIVESINTEMP)) ||
  2300. ((dwVFileFlags&VFF_FID) && (bFlags&FACCESS_LIVESINFS)))
  2301. bSuccess=TRUE;
  2302. else
  2303. {
  2304. if (phr)
  2305. phr->err=E_NOPERMISSION; // reason for no access
  2306. }
  2307. }
  2308. else
  2309. { if (phr)
  2310. phr->err=E_NOPERMISSION;
  2311. }
  2312. _GLOBALUNLOCK(hsfbCursor);
  2313. goto exit1;
  2314. }
  2315. _GLOBALUNLOCK(hsfbCursor);
  2316. hsfbCursor=hsfbNext;
  2317. }
  2318. // File is not currently opened
  2319. if (bFlags&(FACCESS_READ|FACCESS_READWRITE))
  2320. bSuccess=TRUE;
  2321. else
  2322. {
  2323. if (phr)
  2324. phr->err=E_NOPERMISSION;
  2325. }
  2326. }
  2327. }
  2328. else
  2329. {
  2330. if (phr)
  2331. phr->err=E_NOTEXIST;
  2332. }
  2333. exit1:
  2334. DisposeMemory((LPSTR)key);
  2335. _GLOBALUNLOCK(hfs);
  2336. return bSuccess;
  2337. }
  2338. #endif
  2339. /***************************************************************************
  2340. *
  2341. * @doc INTERNAL API
  2342. *
  2343. * @func HRESULT PASCAL FAR | RcRenameFileHfs |
  2344. * Rename a subfile in the file system. The subfile must not currently
  2345. * be in use.
  2346. *
  2347. * @parm HFS | hfs |
  2348. * Handle to a valid file system
  2349. *
  2350. * @parm LPCSTR | szOld |
  2351. * Current file name
  2352. *
  2353. * @parm LPCSTR | szNew |
  2354. * New file name
  2355. *
  2356. * @rdesc Returns S_OK if the file was renamed OK.
  2357. * E_NOPERMISSION if file is in use, or file system is read-only.
  2358. * rcExists if file named szOld already exists in FS
  2359. * rcNoExists if file named szNew doesn't exist in FS
  2360. *
  2361. ***************************************************************************/
  2362. PUBLIC HRESULT PASCAL PASCAL EXPORT_API RcRenameFileHfs(HFS hfs, LPCSTR szOld, LPCSTR szNew)
  2363. {
  2364. #ifdef MOSMAP // {
  2365. // Disable function
  2366. return ERR_NOTSUPPORTED;
  2367. #else // } {
  2368. QFSHR qfshr;
  2369. FILE_REC fr;
  2370. HRESULT rc;
  2371. HSFB hsfbCursor;
  2372. KEY keyOld,keyNew;
  2373. if (hfs == NULL || (qfshr = _GLOBALLOCK(hfs)) == NULL)
  2374. {
  2375. return(E_INVALIDARG);
  2376. }
  2377. if (qfshr->fsh.bFlags & FSH_READONLY)
  2378. {
  2379. rc=E_NOPERMISSION;
  2380. exit0:
  2381. _GLOBALUNLOCK(hfs);
  2382. return rc;
  2383. }
  2384. keyOld = NewKeyFromSz(szOld);
  2385. keyNew = NewKeyFromSz(szNew);
  2386. _ENTERCRITICALSECTION(&qfshr->cs);
  2387. if ((rc = RcLookupByKey (qfshr->hbt, keyOld, NULL, &fr))
  2388. != S_OK)
  2389. {
  2390. goto exit1;
  2391. }
  2392. // Make sure file is not already opened by anyone
  2393. hsfbCursor = qfshr->hsfbFirst;
  2394. while (hsfbCursor)
  2395. {
  2396. HSFB hsfbNext;
  2397. QSFB qsfb;
  2398. if (!(qsfb = _GLOBALLOCK(hsfbCursor)))
  2399. {
  2400. rc=E_OUTOFMEMORY;
  2401. RcDeleteHbt( qfshr->hbt, keyNew);
  2402. goto exit1;
  2403. }
  2404. hsfbNext=qsfb->hsfbNext;
  2405. if (FoEquals(qsfb->foHeader,fr.foStart))
  2406. {
  2407. rc = E_NOPERMISSION;
  2408. _GLOBALUNLOCK(hsfbCursor);
  2409. goto exit1;
  2410. }
  2411. _GLOBALUNLOCK(hsfbCursor);
  2412. hsfbCursor=hsfbNext;
  2413. }
  2414. if ((rc = RcInsertHbt( qfshr->hbt, keyNew, &fr)) != S_OK )
  2415. {
  2416. goto exit1;
  2417. }
  2418. if ((rc = RcDeleteHbt(qfshr->hbt, keyOld) != S_OK))
  2419. {
  2420. // can't delete the old, so just delete the new and hope for
  2421. // the best!
  2422. if ((rc = RcDeleteHbt( qfshr->hbt, keyNew)) == S_OK)
  2423. rc = E_FAIL;
  2424. }
  2425. exit1:
  2426. DisposeMemory((LPSTR)keyOld);
  2427. DisposeMemory((LPSTR)keyNew);
  2428. _LEAVECRITICALSECTION(&qfshr->cs);
  2429. goto exit0;
  2430. #endif // } MOSMAP
  2431. }
  2432. /***************************************************************************
  2433. *
  2434. * @doc INTERNAL API
  2435. *
  2436. * @func BOOL PASCAL FAR | FHfValid |
  2437. * Check for validity of a subfile handle
  2438. *
  2439. * @parm HF | hf |
  2440. * Handle to a subfile
  2441. *
  2442. * @rdesc Returns TRUE if the subfile is valid.
  2443. *
  2444. ***************************************************************************/
  2445. #ifndef ITWRAP
  2446. BOOL PASCAL FAR EXPORT_API FHfValid( HF hf)
  2447. {
  2448. return ((mv_gsfa) && (mv_gsfa_count) && ((WORD)hf<giMaxSubFiles) && (hf) && (mv_gsfa[(DWORD)hf].hsfb))?TRUE:FALSE;
  2449. }
  2450. #endif // !ITWRAP
  2451. /***************************************************************************
  2452. *
  2453. * @doc INTERNAL API
  2454. *
  2455. * @func HFS PASCAL FAR | HfsGetFromHf |
  2456. * Get the file system handle of a given subfile.
  2457. *
  2458. * @parm HF | hf |
  2459. * Handle to a subfile
  2460. *
  2461. * @rdesc Returns the subfile's parent file system handle, or NULL.
  2462. *
  2463. ***************************************************************************/
  2464. HFS PASCAL FAR EXPORT_API HfsGetFromHf( HF hf )
  2465. {
  2466. HFS hfs=NULL;
  2467. QSFB qsfb;
  2468. assert(mv_gsfa);
  2469. assert(mv_gsfa_count);
  2470. if ((mv_gsfa[(DWORD_PTR)hf].hsfb) && (qsfb = _GLOBALLOCK(mv_gsfa[(DWORD_PTR)hf].hsfb)))
  2471. {
  2472. hfs=qsfb->hfs;
  2473. _GLOBALUNLOCK(mv_gsfa[(DWORD_PTR)hf].hsfb);
  2474. }
  2475. return hfs;
  2476. }