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.

959 lines
22 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. /*****************************************************************************
  20. *
  21. * Created 07/17/95 - davej
  22. *
  23. *****************************************************************************/
  24. static char s_aszModule[] = __FILE__; /* For error report */
  25. #include <mvopsys.h>
  26. #include <iterror.h>
  27. #include <orkin.h>
  28. #include <misc.h>
  29. #include <wrapstor.h>
  30. #include <_mvutil.h>
  31. /*****************************************************************************
  32. * *
  33. * Defines *
  34. * *
  35. *****************************************************************************/
  36. /*****************************************************************************
  37. * *
  38. * Prototypes *
  39. * *
  40. *****************************************************************************/
  41. HRESULT PASCAL NEAR RcCopyFileBuf(FID fidDst, FID fidSrc, FILEOFFSET foSize, PROGFUNC lpfnProg,
  42. LPVOID lpvMem, LONG lBufSize);
  43. /***************************************************************************
  44. * *
  45. * Private Functions *
  46. * *
  47. ***************************************************************************/
  48. /***************************************************************************
  49. *
  50. * @doc INTERNAL
  51. *
  52. * @func HVF PASCAL FAR | VFileOpen |
  53. * Open a virtual file
  54. *
  55. * @parm FID | fidParent |
  56. * Parent file where virtual file may live
  57. *
  58. * @parm FILEOFFSET | foBase |
  59. * Base location in parent file
  60. *
  61. * @parm FILEOFFSET | foBlock |
  62. * Size of file in parent file
  63. *
  64. * @parm FILEOFFSET | foExtra |
  65. * Extra amount file may grow before no more room in parent file
  66. *
  67. * @parm DWORD | dwFlags |
  68. * Any VFOPEN_ flags
  69. *
  70. * @parm LPSHAREDBUFFER | lpsb |
  71. * Buffer to use when copying temp files around
  72. *
  73. * @parm PHRESULT | phr |
  74. * Error return
  75. *
  76. * @rdesc Returns a HVF or NULL
  77. *
  78. ***************************************************************************/
  79. PUBLIC HVF FAR EXPORT_API VFileOpen( FID fidParent,
  80. FILEOFFSET foBase, FILEOFFSET foBlock, FILEOFFSET foExtra, DWORD dwFlags,
  81. LPSHAREDBUFFER lpsb, PHRESULT phr )
  82. {
  83. HVF hvf=NULL;
  84. QVFILE qvf;
  85. assert(dwFlags&(VFOPEN_READ|VFOPEN_READWRITE));
  86. assert(dwFlags&(VFOPEN_ASFID|VFOPEN_ASTEMP));
  87. assert((dwFlags&(VFOPEN_READ|VFOPEN_READWRITE))!=(VFOPEN_READ|VFOPEN_READWRITE));
  88. assert((dwFlags&(VFOPEN_ASFID|VFOPEN_ASTEMP))!=(VFOPEN_ASFID|VFOPEN_ASTEMP));
  89. if (!(hvf=_GLOBALALLOC(GMEM_ZEROINIT| GMEM_MOVEABLE,
  90. sizeof(VFILE))))
  91. {
  92. SetErrCode(phr, E_OUTOFMEMORY);
  93. goto exit0;
  94. }
  95. if (!(qvf=_GLOBALLOCK(hvf)))
  96. {
  97. SetErrCode(phr, E_OUTOFMEMORY);
  98. goto exit1;
  99. }
  100. _INITIALIZECRITICALSECTION(&qvf->cs);
  101. qvf->fidParent=fidNil;
  102. qvf->fidTemp=fidNil;
  103. qvf->fmTemp=fmNil;
  104. qvf->lpsb=lpsb;
  105. if ( (fidParent!=fidNil) && (!FoEquals(FoAddFo(foBlock,foExtra),foNil)) )
  106. {
  107. qvf->foEof=foBlock;
  108. qvf->foCurrent=foNil;
  109. qvf->fidParent=fidParent;
  110. qvf->foBase=foBase;
  111. qvf->foBlock=FoAddFo(foBlock,foExtra);
  112. qvf->fidTemp=fidNil;
  113. qvf->fmTemp=fmNil;
  114. qvf->dwFlags=VFF_FID;
  115. if (dwFlags&VFOPEN_READWRITE)
  116. qvf->dwFlags|=VFF_READWRITE;
  117. else
  118. qvf->dwFlags|=VFF_READ;
  119. if (dwFlags&VFOPEN_ASTEMP)
  120. {
  121. // Convert to temp file
  122. VFileSetTemp(hvf);
  123. }
  124. }
  125. else
  126. {
  127. if (dwFlags&VFOPEN_ASTEMP)
  128. {
  129. if (dwFlags&VFOPEN_READ)
  130. {
  131. SetErrCode(phr, E_INVALIDARG);
  132. goto exit2;
  133. }
  134. // Opening as temp, no parent
  135. if ((qvf->fmTemp=FmNewTemp(NULL, phr))!=fmNil)
  136. {
  137. if ((qvf->fidTemp=FidCreateFm(qvf->fmTemp,wReadWrite,wReadWrite,phr))!=fidNil)
  138. {
  139. qvf->dwFlags=VFF_TEMP|VFF_READWRITE;
  140. }
  141. else
  142. {
  143. DisposeFm(qvf->fmTemp);
  144. qvf->fmTemp=fmNil;
  145. SetErrCode(phr, E_HANDLE);
  146. goto exit2;
  147. }
  148. }
  149. else
  150. {
  151. SetErrCode(phr, E_OUTOFMEMORY);
  152. goto exit2;
  153. }
  154. }
  155. else
  156. {
  157. SetErrCode(phr, E_INVALIDARG);
  158. goto exit2;
  159. }
  160. }
  161. _GLOBALUNLOCK(hvf);
  162. return hvf;
  163. exit2:
  164. _DELETECRITICALSECTION(&qvf->cs);
  165. _GLOBALUNLOCK(hvf);
  166. exit1:
  167. _GLOBALFREE(hvf);
  168. exit0:
  169. return NULL;
  170. }
  171. /***************************************************************************
  172. *
  173. * @doc INTERNAL
  174. *
  175. * @func HRESULT PASCAL FAR | VFileSetTemp |
  176. * Force vfile's data to reside in a temp file
  177. *
  178. * @parm HVF | hvf |
  179. * Handle to virtual file
  180. *
  181. * @rdesc Returns various ERR_ messages, or S_OK
  182. *
  183. ***************************************************************************/
  184. PUBLIC HRESULT PASCAL FAR EXPORT_API VFileSetTemp( HVF hvf )
  185. {
  186. QVFILE qvf;
  187. HRESULT errb;
  188. errb=S_OK;
  189. assert(hvf);
  190. if (!(qvf=_GLOBALLOCK(hvf)))
  191. {
  192. SetErrCode(&errb, E_OUTOFMEMORY);
  193. goto exit0;
  194. }
  195. _ENTERCRITICALSECTION(&qvf->cs);
  196. if (qvf->dwFlags&VFF_FID)
  197. {
  198. assert(qvf->fmTemp==fmNil);
  199. if ((qvf->fmTemp=FmNewTemp(NULL, &errb))!=fmNil)
  200. {
  201. if ((qvf->fidTemp=FidCreateFm(qvf->fmTemp,wReadWrite,wReadWrite,&errb))!=fidNil)
  202. {
  203. // Transfer qvf->foEof bytes from parent to temp
  204. _ENTERCRITICALSECTION(&qvf->lpsb->cs);
  205. if (!FoEquals(FoSeekFid(qvf->fidParent,qvf->foBase,wSeekSet,&errb),qvf->foBase))
  206. {
  207. exit2:
  208. _LEAVECRITICALSECTION(&qvf->lpsb->cs);
  209. RcCloseFid(qvf->fidTemp);
  210. qvf->fidTemp=fidNil;
  211. RcUnlinkFm(qvf->fmTemp);
  212. DisposeFm(qvf->fmTemp);
  213. qvf->fmTemp=fmNil;
  214. goto exit1;
  215. }
  216. if (RcCopyFileBuf(qvf->fidTemp,qvf->fidParent, qvf->foEof, NULL,
  217. qvf->lpsb->lpvBuffer,qvf->lpsb->lcbBuffer)==S_OK)
  218. {
  219. qvf->dwFlags=(qvf->dwFlags&(~VFF_FID))|VFF_TEMP;
  220. qvf->foCurrent=qvf->foEof;
  221. }
  222. else
  223. {
  224. goto exit2;
  225. }
  226. _LEAVECRITICALSECTION(&qvf->lpsb->cs);
  227. }
  228. else
  229. {
  230. DisposeFm(qvf->fmTemp);
  231. qvf->fmTemp=fmNil;
  232. goto exit1;
  233. }
  234. }
  235. else
  236. {
  237. goto exit1;
  238. }
  239. }
  240. exit1:
  241. _LEAVECRITICALSECTION(&qvf->cs);
  242. _GLOBALUNLOCK(hvf);
  243. exit0:
  244. return errb;
  245. }
  246. /***************************************************************************
  247. *
  248. * @doc INTERNAL
  249. *
  250. * @func HRESULT PASCAL FAR | VFileSetBase |
  251. * Moves file's data from temporary file into parent's file
  252. *
  253. * @parm HVF | hvf |
  254. * Handle to virtual file
  255. *
  256. * @parm FID | fidParent |
  257. * Parent file to move data into
  258. *
  259. * @parm FILEOFFSET | foBase |
  260. * Base location in parent file
  261. *
  262. * @parm FILEOFFSET | foBlock |
  263. * Largest area in parent file we are allowed to write to
  264. *
  265. * @rdesc Returns a S_OK or error
  266. *
  267. ***************************************************************************/
  268. PUBLIC HRESULT PASCAL FAR EXPORT_API VFileSetBase( HVF hvf, FID fid, FILEOFFSET foBase, FILEOFFSET foBlock)
  269. {
  270. QVFILE qvf;
  271. HRESULT errb;
  272. errb=S_OK;
  273. assert(hvf);
  274. if (!(qvf=_GLOBALLOCK(hvf)))
  275. {
  276. SetErrCode(&errb, E_OUTOFMEMORY);
  277. goto exit0;
  278. }
  279. _ENTERCRITICALSECTION(&qvf->cs);
  280. if (qvf->dwFlags&VFF_TEMP)
  281. {
  282. if (FoCompare(qvf->foEof,foBlock)<=0)
  283. {
  284. // Transfer file
  285. if (!FoEquals((qvf->foCurrent=FoSeekFid(qvf->fidTemp, foNil, wSeekSet, &errb)),foNil))
  286. {
  287. goto exit1;
  288. }
  289. qvf->foBase=foBase;
  290. qvf->foBlock=foBlock;
  291. qvf->fidParent=fid;
  292. _ENTERCRITICALSECTION(&qvf->lpsb->cs);
  293. if (!FoEquals(FoSeekFid(qvf->fidParent,qvf->foBase,wSeekSet,&errb),qvf->foBase))
  294. {
  295. exit2:
  296. _LEAVECRITICALSECTION(&qvf->lpsb->cs);
  297. goto exit1;
  298. }
  299. if (RcCopyFileBuf(qvf->fidParent, qvf->fidTemp, qvf->foEof, NULL,
  300. qvf->lpsb->lpvBuffer,qvf->lpsb->lcbBuffer)==S_OK)
  301. {
  302. qvf->dwFlags=(qvf->dwFlags&(~VFF_TEMP))|VFF_FID;
  303. RcCloseFid(qvf->fidTemp);
  304. qvf->fidTemp=fidNil;
  305. RcUnlinkFm(qvf->fmTemp);
  306. DisposeFm(qvf->fmTemp);
  307. qvf->fmTemp=fmNil;
  308. qvf->foCurrent=qvf->foEof;
  309. }
  310. else
  311. {
  312. goto exit2;
  313. }
  314. _LEAVECRITICALSECTION(&qvf->lpsb->cs);
  315. }
  316. else
  317. {
  318. // Parent Filespace too small for temp file
  319. SetErrCode(&errb, E_OUTOFRANGE);
  320. }
  321. }
  322. else
  323. // Can only set the base of a temp file
  324. SetErrCode(&errb, E_ASSERT);
  325. exit1:
  326. _LEAVECRITICALSECTION(&qvf->cs);
  327. _GLOBALUNLOCK(hvf);
  328. exit0:
  329. return errb;
  330. }
  331. /***************************************************************************
  332. *
  333. * @doc INTERNAL
  334. *
  335. * @func HRESULT PASCAL FAR | VFileSetEOF |
  336. * Sets the size of the virtual file (and moves it into a temp file if
  337. * necessary)
  338. *
  339. * @parm HVF | hvf |
  340. * Handle to virtual file
  341. *
  342. * @parm FILEOFFSET | foEof |
  343. * New End Of File position
  344. *
  345. * @rdesc Returns a S_OK or error
  346. *
  347. * @comm
  348. * May write out as far as foEof without causing a transfer
  349. * from Parent file to Temp file
  350. *
  351. ***************************************************************************/
  352. PUBLIC HRESULT PASCAL FAR EXPORT_API VFileSetEOF( HVF hvf, FILEOFFSET foEof )
  353. {
  354. QVFILE qvf;
  355. HRESULT rc = S_OK;
  356. assert(hvf);
  357. if (!(qvf=_GLOBALLOCK(hvf)))
  358. {
  359. rc=E_OUTOFMEMORY;
  360. goto exit0;
  361. }
  362. if (qvf->dwFlags&VFF_FID)
  363. {
  364. if (FoCompare(foEof,qvf->foBlock)>0)
  365. {
  366. // Must transfer to temp file first
  367. if ((rc=VFileSetTemp(hvf))!=S_OK)
  368. goto exit1;
  369. }
  370. else
  371. {
  372. // Just update pointer
  373. qvf->foEof = foEof;
  374. }
  375. }
  376. if (qvf->dwFlags&VFF_TEMP)
  377. {
  378. if (foEof.dwHigh==0)
  379. {
  380. if ((rc=RcChSizeFid(qvf->fidTemp, foEof.dwOffset)) == S_OK)
  381. {
  382. qvf->foEof=foEof;
  383. }
  384. }
  385. else
  386. {
  387. // There is not ChSizeFid for super long files
  388. qvf->foEof=foEof;
  389. }
  390. }
  391. exit1:
  392. _GLOBALUNLOCK(hvf);
  393. exit0:
  394. return rc;
  395. }
  396. /***************************************************************************
  397. *
  398. * @doc INTERNAL
  399. *
  400. * @func FILEOFFSET PASCAL FAR | VFileGetSize |
  401. * Get the file size
  402. *
  403. * @parm HVF | hvf |
  404. * Handle to virtual file
  405. *
  406. * @parm PHRESULT | phr |
  407. * Error return
  408. *
  409. * @rdesc File Size in bytes, if zero, check phr
  410. *
  411. ***************************************************************************/
  412. PUBLIC FILEOFFSET PASCAL FAR EXPORT_API VFileGetSize( HVF hvf, PHRESULT phr )
  413. {
  414. QVFILE qvf;
  415. FILEOFFSET foSize=foNil;
  416. assert(hvf);
  417. if (!(qvf=_GLOBALLOCK(hvf)))
  418. {
  419. SetErrCode(phr, E_OUTOFMEMORY);
  420. goto exit0;
  421. }
  422. foSize=qvf->foEof;
  423. _GLOBALUNLOCK(hvf);
  424. exit0:
  425. return foSize;
  426. }
  427. /***************************************************************************
  428. *
  429. * @doc INTERNAL
  430. *
  431. * @func DWORD PASCAL FAR | VFileGetFlags |
  432. * Get the file VFF_ flags
  433. *
  434. * @parm HVF | hvf |
  435. * Handle to virtual file
  436. *
  437. * @parm PHRESULT | phr |
  438. * Error return
  439. *
  440. * @rdesc Any combination of VFF_ flags
  441. *
  442. ***************************************************************************/
  443. PUBLIC DWORD PASCAL FAR EXPORT_API VFileGetFlags( HVF hvf, PHRESULT phr )
  444. {
  445. QVFILE qvf;
  446. DWORD dwFlags=0L;
  447. assert(hvf);
  448. if (!(qvf=_GLOBALLOCK(hvf)))
  449. {
  450. SetErrCode(phr, E_OUTOFMEMORY);
  451. goto exit0;
  452. }
  453. dwFlags=qvf->dwFlags;
  454. _GLOBALUNLOCK(hvf);
  455. exit0:
  456. return dwFlags;
  457. }
  458. /***************************************************************************
  459. *
  460. * @doc INTERNAL
  461. *
  462. * @func LONG PASCAL FAR | VFileSeekRead |
  463. * Read data from a location in the file
  464. *
  465. * @parm HVF | hvf |
  466. * Handle to virtual file
  467. *
  468. * @parm FILEOFFSET | foSeek |
  469. * Seek location before read
  470. *
  471. * @parm LPVOID | lpvBuffer |
  472. * Buffer for read data
  473. *
  474. * @parm DWORD | dwcb |
  475. * Number of bytes to read
  476. *
  477. * @parm PHRESULT | phr |
  478. * Error return
  479. *
  480. * @rdesc Number of bytes read. If != dwcb, check phr
  481. *
  482. ***************************************************************************/
  483. PUBLIC LONG PASCAL FAR EXPORT_API VFileSeekRead( HVF hvf, FILEOFFSET foSeek, LPVOID lpvBuffer,
  484. DWORD dwcb, PHRESULT phr )
  485. {
  486. QVFILE qvf;
  487. LONG lTotalRead=0L;
  488. assert(hvf);
  489. if (!(qvf=_GLOBALLOCK(hvf)))
  490. {
  491. SetErrCode(phr, E_OUTOFMEMORY);
  492. goto exit0;
  493. }
  494. _ENTERCRITICALSECTION(&qvf->cs);
  495. if (qvf->dwFlags&VFF_FID)
  496. {
  497. if (FoCompare(foSeek,qvf->foBlock)< 0)
  498. {
  499. DWORD dwCanRead;
  500. FILEOFFSET foSeeked;
  501. if (qvf->dwFlags&VFF_FID)
  502. {
  503. if (FoCompare(FoAddDw(foSeek,dwcb),qvf->foBlock)<0)
  504. dwCanRead=FoSubFo(FoAddDw(foSeek,dwcb),foSeek).dwOffset;
  505. else
  506. dwCanRead=FoSubFo(qvf->foBlock,foSeek).dwOffset;
  507. }
  508. else
  509. {
  510. dwCanRead = dwcb;
  511. }
  512. if (dwCanRead!=dwcb)
  513. SetErrCode(phr, E_FILEREAD);
  514. foSeeked=FoAddFo(qvf->foBase,foSeek);
  515. if (!FoEquals(FoSeekFid(qvf->fidParent, foSeeked, wSeekSet, phr),foSeeked))
  516. {
  517. goto exit1;
  518. }
  519. lTotalRead=LcbReadFid(qvf->fidParent,lpvBuffer,dwCanRead,phr);
  520. // Try twice to read, in case it's a simple error that reading a second time
  521. // will help
  522. if (lTotalRead!=(long)dwCanRead)
  523. {
  524. if (!FoEquals(FoSeekFid(qvf->fidParent, foSeeked, wSeekSet, phr),foSeeked))
  525. {
  526. goto exit1;
  527. }
  528. lTotalRead=LcbReadFid(qvf->fidParent,lpvBuffer,dwCanRead,phr);
  529. }
  530. }
  531. else
  532. {
  533. SetErrCode(phr, E_FILESEEK);
  534. goto exit1;
  535. }
  536. }
  537. else
  538. {
  539. // Seek and read from temp file
  540. if (!FoEquals(qvf->foCurrent,foSeek))
  541. {
  542. if ( (FoCompare(foSeek,qvf->foCurrent)<0) && (qvf->dwFlags&VFF_DIRTY))
  543. {
  544. qvf->dwFlags&=(~VFF_DIRTY);
  545. // call DOS file commit to correct DOS bug?
  546. }
  547. if (!FoEquals((qvf->foCurrent=FoSeekFid(qvf->fidTemp, foSeek, wSeekSet, phr)),foSeek))
  548. {
  549. goto exit1;
  550. }
  551. }
  552. lTotalRead=LcbReadFid(qvf->fidTemp,lpvBuffer,dwcb,phr);
  553. qvf->foCurrent=FoAddDw(qvf->foCurrent,lTotalRead);
  554. }
  555. exit1:
  556. _LEAVECRITICALSECTION(&qvf->cs);
  557. _GLOBALUNLOCK(hvf);
  558. exit0:
  559. return lTotalRead;
  560. }
  561. /***************************************************************************
  562. *
  563. * @doc INTERNAL
  564. *
  565. * @func LONG PASCAL FAR | VFileSeekWrite |
  566. * Write data to a location in the file
  567. *
  568. * @parm HVF | hvf |
  569. * Handle to virtual file
  570. *
  571. * @parm FILEOFFSET | foSeek |
  572. * Seek location before write
  573. *
  574. * @parm LPVOID | lpvBuffer |
  575. * Buffer to write
  576. *
  577. * @parm DWORD | dwcb |
  578. * Number of bytes to write
  579. *
  580. * @parm PHRESULT | phr |
  581. * Error return
  582. *
  583. * @rdesc Number of bytes written. If != lcb, check phr
  584. *
  585. ***************************************************************************/
  586. PUBLIC LONG PASCAL FAR EXPORT_API VFileSeekWrite( HVF hvf, FILEOFFSET foSeek, LPVOID lpvBuffer,
  587. DWORD dwcb, PHRESULT phr )
  588. {
  589. QVFILE qvf;
  590. LONG lWritten=0L;
  591. assert(hvf);
  592. if (!(qvf=_GLOBALLOCK(hvf)))
  593. {
  594. SetErrCode(phr, E_OUTOFMEMORY);
  595. goto exit0;
  596. }
  597. _ENTERCRITICALSECTION(&qvf->cs);
  598. if (qvf->dwFlags&VFF_READWRITE)
  599. {
  600. DWORD dwCanWrite;
  601. if (qvf->dwFlags&VFF_FID)
  602. {
  603. if (FoCompare(FoAddDw(foSeek,dwcb),qvf->foBlock)<0)
  604. dwCanWrite=FoSubFo(FoAddDw(foSeek,dwcb),foSeek).dwOffset;
  605. else
  606. dwCanWrite=FoSubFo(qvf->foBlock,foSeek).dwOffset;
  607. }
  608. else
  609. {
  610. dwCanWrite=dwcb;
  611. }
  612. if ((qvf->dwFlags&VFF_FID) && ((long)dwCanWrite < (long)dwcb))
  613. {
  614. // Transfer to temp file first
  615. if ((*phr=VFileSetTemp(hvf))!=S_OK)
  616. goto exit1;
  617. dwCanWrite=dwcb;
  618. }
  619. if (qvf->dwFlags&VFF_FID)
  620. {
  621. FILEOFFSET foSeeked;
  622. assert(FoCompare(foSeek,qvf->foBlock) < 0);
  623. foSeeked=FoAddFo(qvf->foBase,foSeek);
  624. if (!FoEquals(FoSeekFid(qvf->fidParent, foSeeked, wSeekSet, phr),foSeeked))
  625. {
  626. goto exit1;
  627. }
  628. lWritten=LcbWriteFid(qvf->fidParent,lpvBuffer,dwCanWrite,phr);
  629. foSeek=FoAddDw(foSeek,lWritten);
  630. if (FoCompare(foSeek,qvf->foEof)>0)
  631. qvf->foEof=foSeek;
  632. }
  633. else
  634. {
  635. // Seek and write to temp file
  636. if (!FoEquals(qvf->foCurrent,foSeek))
  637. {
  638. if ((FoCompare(foSeek,qvf->foCurrent)<0) && (qvf->dwFlags&VFF_DIRTY))
  639. {
  640. qvf->dwFlags&=(~VFF_DIRTY);
  641. // call DOS file commit to correct DOS bug?
  642. }
  643. if (!FoEquals((qvf->foCurrent=FoSeekFid(qvf->fidTemp, foSeek, wSeekSet, phr)),foSeek))
  644. {
  645. goto exit1;
  646. }
  647. }
  648. lWritten=LcbWriteFid(qvf->fidTemp,lpvBuffer,dwcb,phr);
  649. qvf->foCurrent=FoAddDw(qvf->foCurrent,lWritten);
  650. if (FoCompare(qvf->foCurrent,qvf->foEof)>0)
  651. qvf->foEof=qvf->foCurrent;
  652. // Just used in case of DOS non-flushing bug
  653. qvf->dwFlags|=VFF_DIRTY;
  654. }
  655. }
  656. else
  657. {
  658. SetErrCode(phr, E_NOPERMISSION);
  659. }
  660. exit1:
  661. _LEAVECRITICALSECTION(&qvf->cs);
  662. _GLOBALUNLOCK(hvf);
  663. exit0:
  664. return lWritten;
  665. }
  666. /***************************************************************************
  667. *
  668. * @doc INTERNAL
  669. *
  670. * @func LONG PASCAL FAR | VFileClose |
  671. * Close a virtual file (file should reside in parent before closing)
  672. *
  673. * @parm HVF | hvf |
  674. * Handle to virtual file
  675. *
  676. * @rdesc S_OK or E_FILECLOSE if data resides in temp file
  677. *
  678. * @comm
  679. * <p hvf> Invalid if successful
  680. *
  681. ***************************************************************************/
  682. PUBLIC HRESULT PASCAL FAR EXPORT_API VFileClose( HVF hvf )
  683. {
  684. QVFILE qvf;
  685. HRESULT rc = S_OK;
  686. assert(hvf);
  687. if (!(qvf=_GLOBALLOCK(hvf)))
  688. {
  689. rc=E_OUTOFMEMORY;
  690. goto exit0;
  691. }
  692. if (qvf->dwFlags&VFF_FID)
  693. {
  694. assert(qvf->fmTemp==fmNil);
  695. assert(qvf->fidTemp==fidNil);
  696. _DELETECRITICALSECTION(&qvf->cs);
  697. _GLOBALUNLOCK(hvf);
  698. _GLOBALFREE(hvf);
  699. return rc;
  700. }
  701. else
  702. {
  703. // Call VFileSetBase to place file back into parent, or
  704. // Call VFileAbandon first, then close since we are trying to close a
  705. // vfile that still resides in a temp file, and not in a valid parent
  706. rc=E_FILECLOSE;
  707. goto exit1;
  708. }
  709. exit1:
  710. _GLOBALUNLOCK(hvf);
  711. exit0:
  712. return rc;
  713. }
  714. /***************************************************************************
  715. *
  716. * @doc INTERNAL
  717. *
  718. * @func LONG PASCAL FAR | VFileAbandon |
  719. * Removes temporary file, and sets file's data to be in old parent
  720. * file location. Should only call if hvf needs closing, but the data
  721. * is not to be transferred back into a parent file
  722. *
  723. * @parm HVF | hvf |
  724. * Handle to virtual file
  725. *
  726. * @rdesc S_OK or E_ASSERT if data already resides in parent
  727. *
  728. ***************************************************************************/
  729. PUBLIC HRESULT PASCAL FAR EXPORT_API VFileAbandon( HVF hvf )
  730. {
  731. QVFILE qvf;
  732. HRESULT rc = S_OK;
  733. assert(hvf);
  734. if (!(qvf=_GLOBALLOCK(hvf)))
  735. {
  736. rc=E_OUTOFMEMORY;
  737. goto exit0;
  738. }
  739. if (qvf->dwFlags&VFF_TEMP)
  740. {
  741. RcCloseFid(qvf->fidTemp);
  742. qvf->fidTemp=fidNil;
  743. RcUnlinkFm(qvf->fmTemp);
  744. DisposeFm(qvf->fmTemp);
  745. qvf->fmTemp=fmNil;
  746. qvf->dwFlags=(qvf->dwFlags&(~VFF_TEMP))|VFF_FID;
  747. }
  748. else
  749. {
  750. // Can't abandon an Fid, since Abandon means to abondon
  751. // the Temp file
  752. rc=E_ASSERT;
  753. }
  754. _GLOBALUNLOCK(hvf);
  755. exit0:
  756. return rc;
  757. }
  758. /***************************************************************************
  759. *
  760. * @doc INTERNAL
  761. *
  762. * @func HRESULT PASCAL FAR | RcCopyFileBuf |
  763. * Copy a file using buffer that must be passed in by user
  764. *
  765. * @parm FID | fidDst |
  766. * Destination file fid
  767. *
  768. * @parm FID | fidSrc |
  769. * Source file fid
  770. *
  771. * @parm FILEOFFSET | foSize |
  772. * Number of bytes to copy
  773. *
  774. * @parm PROGFUNC | lpfnProg |
  775. * Progress callback function (may be NULL). Callback should return non-zero
  776. * to cancel copy operation.
  777. *
  778. * @parm LPVOID | lpvBuf |
  779. * Buffer to use during copy
  780. *
  781. * @parm LONG | lcbBuf |
  782. * Size of lpvBuf
  783. *
  784. * @rdesc S_OK, ERR_INTERRUPT or any file error. File pointers in
  785. * fidDst and fidSrc must be pre-positioned before calling.
  786. *
  787. ***************************************************************************/
  788. HRESULT PASCAL NEAR RcCopyFileBuf(FID fidDst, FID fidSrc, FILEOFFSET foSize, PROGFUNC lpfnProg, LPVOID lpvBuf, LONG lcbBuf)
  789. {
  790. #ifdef MOSMAP // {
  791. // Disable function
  792. return ERR_NOTSUPPORTED;
  793. #else // } {
  794. QB qb = (QB)lpvBuf;
  795. DWORD dwT, dwChunk=(DWORD)lcbBuf;
  796. HRESULT errb;
  797. FILEOFFSET foTemp;
  798. assert(lpvBuf);
  799. assert(lcbBuf);
  800. errb = S_OK;
  801. foTemp.dwHigh=0;
  802. do
  803. {
  804. // perform a progress callback
  805. if (lpfnProg != NULL)
  806. {
  807. if ((*lpfnProg)(0)!=0)
  808. {
  809. return E_INTERRUPT;
  810. }
  811. }
  812. if (!foSize.dwHigh)
  813. dwT = min(dwChunk, foSize.dwOffset);
  814. else
  815. dwT=dwChunk;
  816. if (LcbReadFid( fidSrc, qb, (LONG)dwT, &errb) != (LONG)dwT )
  817. {
  818. dwT = (DWORD)-1L;
  819. break;
  820. }
  821. if (LcbWriteFid( fidDst, qb, (LONG)dwT, &errb) != (LONG)dwT )
  822. {
  823. dwT = (DWORD)-1L;
  824. break;
  825. }
  826. foTemp.dwOffset=dwT;
  827. foSize=FoSubFo(foSize,foTemp);
  828. }
  829. while (!FoIsNil(foSize));
  830. return errb;
  831. #endif //}
  832. }