Leaked source code of windows server 2003
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.

1372 lines
29 KiB

  1. /*
  2. * fcache.c - File cache ADT module.
  3. */
  4. /*
  5. The file cache ADT may be disabled by #defining NOFCACHE. If NOFCACHE is
  6. #defined, file cache ADT calls are translated into their direct Win32 file
  7. system API equivalents.
  8. */
  9. /* Headers
  10. **********/
  11. #include "project.h"
  12. #pragma hdrstop
  13. /* Constants
  14. ************/
  15. /* last resort default minimum cache size */
  16. #define DEFAULT_MIN_CACHE_SIZE (32)
  17. /* Types
  18. ********/
  19. #ifndef NOFCACHE
  20. /* cached file description structure */
  21. typedef struct _icachedfile
  22. {
  23. /* current position of file pointer in file */
  24. DWORD dwcbCurFilePosition;
  25. /* file handle of cached file */
  26. HANDLE hfile;
  27. /* file open mode */
  28. DWORD dwOpenMode;
  29. /* size of cache in bytes */
  30. DWORD dwcbCacheSize;
  31. /* pointer to base of cache */
  32. PBYTE pbyteCache;
  33. /* size of default cache in bytes */
  34. DWORD dwcbDefaultCacheSize;
  35. /* default cache */
  36. PBYTE pbyteDefaultCache;
  37. /* length of file (including data written to cache) */
  38. DWORD dwcbFileLen;
  39. /* offset of start of cache in file */
  40. DWORD dwcbFileOffsetOfCache;
  41. /* number of valid bytes in cache, starting at beginning of cache */
  42. DWORD dwcbValid;
  43. /* number of uncommitted bytes in cache, starting at beginning of cache */
  44. DWORD dwcbUncommitted;
  45. /* path of cached file */
  46. LPTSTR pszPath;
  47. }
  48. ICACHEDFILE;
  49. DECLARE_STANDARD_TYPES(ICACHEDFILE);
  50. #endif /* NOFCACHE */
  51. /***************************** Private Functions *****************************/
  52. /* Module Prototypes
  53. ********************/
  54. PRIVATE_CODE FCRESULT SetUpCachedFile(PCCACHEDFILE, PHCACHEDFILE);
  55. #ifndef NOFCACHE
  56. PRIVATE_CODE void BreakDownCachedFile(PICACHEDFILE);
  57. PRIVATE_CODE void ResetCacheToEmpty(PICACHEDFILE);
  58. PRIVATE_CODE DWORD ReadFromCache(PICACHEDFILE, PVOID, DWORD);
  59. PRIVATE_CODE DWORD GetValidReadData(PICACHEDFILE, PBYTE *);
  60. PRIVATE_CODE BOOL FillCache(PICACHEDFILE, PDWORD);
  61. PRIVATE_CODE DWORD WriteToCache(PICACHEDFILE, PCVOID, DWORD);
  62. PRIVATE_CODE DWORD GetAvailableWriteSpace(PICACHEDFILE, PBYTE *);
  63. PRIVATE_CODE BOOL CommitCache(PICACHEDFILE);
  64. #ifdef VSTF
  65. PRIVATE_CODE BOOL IsValidPCICACHEDFILE(PCICACHEDFILE);
  66. #endif /* VSTF */
  67. #endif /* NOFCACHE */
  68. #ifdef VSTF
  69. PRIVATE_CODE BOOL IsValidPCCACHEDFILE(PCCACHEDFILE);
  70. #endif /* VSTF */
  71. /*
  72. ** SetUpCachedFile()
  73. **
  74. **
  75. **
  76. ** Arguments:
  77. **
  78. ** Returns:
  79. **
  80. ** Side Effects: none
  81. */
  82. PRIVATE_CODE FCRESULT SetUpCachedFile(PCCACHEDFILE pccf, PHCACHEDFILE phcf)
  83. {
  84. FCRESULT fcr;
  85. HANDLE hfNew;
  86. ASSERT(IS_VALID_STRUCT_PTR(pccf, CCACHEDFILE));
  87. ASSERT(IS_VALID_WRITE_PTR(phcf, HCACHEDFILE));
  88. /* Open the file with the requested open and sharing flags. */
  89. hfNew = CreateFile(pccf->pcszPath, pccf->dwOpenMode, pccf->dwSharingMode,
  90. pccf->psa, pccf->dwCreateMode, pccf->dwAttrsAndFlags,
  91. pccf->hTemplateFile);
  92. if (hfNew != INVALID_HANDLE_VALUE)
  93. {
  94. #ifdef NOFCACHE
  95. *phcf = hfNew;
  96. fcr = FCR_SUCCESS;
  97. #else
  98. PICACHEDFILE picf;
  99. fcr = FCR_OUT_OF_MEMORY;
  100. /* Try to allocate a new cached file structure. */
  101. if (AllocateMemory(sizeof(*picf), &picf))
  102. {
  103. DWORD dwcbDefaultCacheSize;
  104. /* Allocate the default cache for the cached file. */
  105. if (pccf->dwcbDefaultCacheSize > 0)
  106. dwcbDefaultCacheSize = pccf->dwcbDefaultCacheSize;
  107. else
  108. {
  109. dwcbDefaultCacheSize = DEFAULT_MIN_CACHE_SIZE;
  110. WARNING_OUT((TEXT("SetUpCachedFile(): Using minimum cache size of %lu instead of %lu."),
  111. dwcbDefaultCacheSize,
  112. pccf->dwcbDefaultCacheSize));
  113. }
  114. if (AllocateMemory(dwcbDefaultCacheSize, &(picf->pbyteDefaultCache)))
  115. {
  116. if (StringCopy(pccf->pcszPath, &(picf->pszPath)))
  117. {
  118. DWORD dwcbFileLenHigh;
  119. picf->dwcbFileLen = GetFileSize(hfNew, &dwcbFileLenHigh);
  120. if (picf->dwcbFileLen != INVALID_FILE_SIZE && ! dwcbFileLenHigh)
  121. {
  122. /* Success! Fill in cached file structure fields. */
  123. picf->hfile = hfNew;
  124. picf->dwcbCurFilePosition = 0;
  125. picf->dwcbCacheSize = dwcbDefaultCacheSize;
  126. picf->pbyteCache = picf->pbyteDefaultCache;
  127. picf->dwcbDefaultCacheSize = dwcbDefaultCacheSize;
  128. picf->dwOpenMode = pccf->dwOpenMode;
  129. ResetCacheToEmpty(picf);
  130. *phcf = (HCACHEDFILE)picf;
  131. fcr = FCR_SUCCESS;
  132. ASSERT(IS_VALID_HANDLE(*phcf, CACHEDFILE));
  133. TRACE_OUT((TEXT("SetUpCachedFile(): Created %lu byte default cache for file %s."),
  134. picf->dwcbCacheSize,
  135. picf->pszPath));
  136. }
  137. else
  138. {
  139. fcr = FCR_OPEN_FAILED;
  140. SETUPCACHEDFILE_BAIL1:
  141. FreeMemory(picf->pbyteDefaultCache);
  142. SETUPCACHEDFILE_BAIL2:
  143. FreeMemory(picf);
  144. SETUPCACHEDFILE_BAIL3:
  145. /*
  146. * Failing to close the file properly is not a failure
  147. * condition here.
  148. */
  149. CloseHandle(hfNew);
  150. }
  151. }
  152. else
  153. goto SETUPCACHEDFILE_BAIL1;
  154. }
  155. else
  156. goto SETUPCACHEDFILE_BAIL2;
  157. }
  158. else
  159. goto SETUPCACHEDFILE_BAIL3;
  160. #endif /* NOFCACHE */
  161. }
  162. else
  163. {
  164. switch (GetLastError())
  165. {
  166. /* Returned when file opened by local machine. */
  167. case ERROR_SHARING_VIOLATION:
  168. fcr = FCR_FILE_LOCKED;
  169. break;
  170. default:
  171. fcr = FCR_OPEN_FAILED;
  172. break;
  173. }
  174. }
  175. return(fcr);
  176. }
  177. #ifndef NOFCACHE
  178. /*
  179. ** BreakDownCachedFile()
  180. **
  181. **
  182. **
  183. ** Arguments:
  184. **
  185. ** Returns:
  186. **
  187. ** Side Effects: none
  188. */
  189. PRIVATE_CODE void BreakDownCachedFile(PICACHEDFILE picf)
  190. {
  191. ASSERT(IS_VALID_STRUCT_PTR(picf, CICACHEDFILE));
  192. /* Are we using the default cache? */
  193. if (picf->pbyteCache != picf->pbyteDefaultCache)
  194. /* No. Free the cache. */
  195. FreeMemory(picf->pbyteCache);
  196. /* Free the default cache. */
  197. FreeMemory(picf->pbyteDefaultCache);
  198. TRACE_OUT((TEXT("BreakDownCachedFile(): Destroyed cache for file %s."),
  199. picf->pszPath));
  200. FreeMemory(picf->pszPath);
  201. FreeMemory(picf);
  202. return;
  203. }
  204. /*
  205. ** ResetCacheToEmpty()
  206. **
  207. **
  208. **
  209. ** Arguments:
  210. **
  211. ** Returns:
  212. **
  213. ** Side Effects: none
  214. */
  215. PRIVATE_CODE void ResetCacheToEmpty(PICACHEDFILE picf)
  216. {
  217. /*
  218. * Don't fully validate *picf here since we may be called by
  219. * SetUpCachedFile() before *picf has been set up.
  220. */
  221. ASSERT(IS_VALID_WRITE_PTR(picf, ICACHEDFILE));
  222. picf->dwcbFileOffsetOfCache = picf->dwcbCurFilePosition;
  223. picf->dwcbValid = 0;
  224. picf->dwcbUncommitted = 0;
  225. return;
  226. }
  227. /*
  228. ** ReadFromCache()
  229. **
  230. **
  231. **
  232. ** Arguments:
  233. **
  234. ** Returns:
  235. **
  236. ** Side Effects: none
  237. */
  238. PRIVATE_CODE DWORD ReadFromCache(PICACHEDFILE picf, PVOID hpbyteBuffer, DWORD dwcb)
  239. {
  240. DWORD dwcbRead;
  241. PBYTE pbyteStart;
  242. DWORD dwcbValid;
  243. ASSERT(IS_VALID_STRUCT_PTR(picf, CICACHEDFILE));
  244. ASSERT(IS_VALID_WRITE_BUFFER_PTR(hpbyteBuffer, BYTE, (UINT)dwcb));
  245. ASSERT(IS_FLAG_SET(picf->dwOpenMode, GENERIC_READ));
  246. ASSERT(dwcb > 0);
  247. /* Is there any valid data that can be read from the cache? */
  248. dwcbValid = GetValidReadData(picf, &pbyteStart);
  249. if (dwcbValid > 0)
  250. {
  251. /* Yes. Copy it into the buffer. */
  252. dwcbRead = min(dwcbValid, dwcb);
  253. CopyMemory(hpbyteBuffer, pbyteStart, dwcbRead);
  254. picf->dwcbCurFilePosition += dwcbRead;
  255. }
  256. else
  257. dwcbRead = 0;
  258. return(dwcbRead);
  259. }
  260. /*
  261. ** GetValidReadData()
  262. **
  263. **
  264. **
  265. ** Arguments:
  266. **
  267. ** Returns:
  268. **
  269. ** Side Effects: none
  270. */
  271. PRIVATE_CODE DWORD GetValidReadData(PICACHEDFILE picf, PBYTE *ppbyteStart)
  272. {
  273. DWORD dwcbValid;
  274. ASSERT(IS_VALID_STRUCT_PTR(picf, CICACHEDFILE));
  275. ASSERT(IS_VALID_WRITE_PTR(ppbyteStart, PBYTE *));
  276. ASSERT(IS_FLAG_SET(picf->dwOpenMode, GENERIC_READ));
  277. /* Is there any valid read data in the cache? */
  278. /* The current file position must be inside the valid data in the cache. */
  279. /* Watch out for overflow. */
  280. ASSERT(picf->dwcbFileOffsetOfCache <= DWORD_MAX - picf->dwcbValid);
  281. if (picf->dwcbCurFilePosition >= picf->dwcbFileOffsetOfCache &&
  282. picf->dwcbCurFilePosition < picf->dwcbFileOffsetOfCache + picf->dwcbValid)
  283. {
  284. DWORD dwcbStartBias;
  285. /* Yes. */
  286. dwcbStartBias = picf->dwcbCurFilePosition - picf->dwcbFileOffsetOfCache;
  287. *ppbyteStart = picf->pbyteCache + dwcbStartBias;
  288. /* The second clause above protects against underflow here. */
  289. dwcbValid = picf->dwcbValid - dwcbStartBias;
  290. }
  291. else
  292. /* No. */
  293. dwcbValid = 0;
  294. return(dwcbValid);
  295. }
  296. /*
  297. ** FillCache()
  298. **
  299. **
  300. **
  301. ** Arguments:
  302. **
  303. ** Returns:
  304. **
  305. ** Side Effects: none
  306. */
  307. PRIVATE_CODE BOOL FillCache(PICACHEDFILE picf, PDWORD pdwcbNewData)
  308. {
  309. BOOL bResult = FALSE;
  310. ASSERT(IS_VALID_STRUCT_PTR(picf, CICACHEDFILE));
  311. ASSERT(IS_VALID_WRITE_PTR(pdwcbNewData, DWORD));
  312. ASSERT(IS_FLAG_SET(picf->dwOpenMode, GENERIC_READ));
  313. if (CommitCache(picf))
  314. {
  315. DWORD dwcbOffset;
  316. ResetCacheToEmpty(picf);
  317. /* Seek to start position. */
  318. dwcbOffset = SetFilePointer(picf->hfile, picf->dwcbCurFilePosition, NULL, FILE_BEGIN);
  319. if (dwcbOffset != INVALID_SEEK_POSITION)
  320. {
  321. DWORD dwcbRead;
  322. ASSERT(dwcbOffset == picf->dwcbCurFilePosition);
  323. /* Fill cache from file. */
  324. if (ReadFile(picf->hfile, picf->pbyteCache, picf->dwcbCacheSize, &dwcbRead, NULL))
  325. {
  326. picf->dwcbValid = dwcbRead;
  327. *pdwcbNewData = dwcbRead;
  328. bResult = TRUE;
  329. TRACE_OUT((TEXT("FillCache(): Read %lu bytes into cache starting at offset %lu in file %s."),
  330. dwcbRead,
  331. dwcbOffset,
  332. picf->pszPath));
  333. }
  334. }
  335. }
  336. return(bResult);
  337. }
  338. /*
  339. ** WriteToCache()
  340. **
  341. **
  342. **
  343. ** Arguments:
  344. **
  345. ** Returns:
  346. **
  347. ** Side Effects: none
  348. */
  349. PRIVATE_CODE DWORD WriteToCache(PICACHEDFILE picf, PCVOID hpbyteBuffer, DWORD dwcb)
  350. {
  351. DWORD dwcbAvailable;
  352. PBYTE pbyteStart;
  353. DWORD dwcbWritten;
  354. DWORD dwcbNewUncommitted;
  355. ASSERT(IS_VALID_STRUCT_PTR(picf, CICACHEDFILE));
  356. ASSERT(IS_VALID_READ_BUFFER_PTR(hpbyteBuffer, BYTE, (UINT)dwcb));
  357. ASSERT(IS_FLAG_SET(picf->dwOpenMode, GENERIC_WRITE));
  358. ASSERT(dwcb > 0);
  359. /* Is there any room left to write data into the cache? */
  360. dwcbAvailable = GetAvailableWriteSpace(picf, &pbyteStart);
  361. /* Yes. Determine how much to copy into cache. */
  362. dwcbWritten = min(dwcbAvailable, dwcb);
  363. /* Can we write anything into the cache? */
  364. if (dwcbWritten > 0)
  365. {
  366. /* Yes. Write it. */
  367. CopyMemory(pbyteStart, hpbyteBuffer, dwcbWritten);
  368. /* Watch out for overflow. */
  369. ASSERT(picf->dwcbCurFilePosition <= DWORD_MAX - dwcbWritten);
  370. picf->dwcbCurFilePosition += dwcbWritten;
  371. /* Watch out for underflow. */
  372. ASSERT(picf->dwcbCurFilePosition >= picf->dwcbFileOffsetOfCache);
  373. dwcbNewUncommitted = picf->dwcbCurFilePosition - picf->dwcbFileOffsetOfCache;
  374. if (picf->dwcbUncommitted < dwcbNewUncommitted)
  375. picf->dwcbUncommitted = dwcbNewUncommitted;
  376. if (picf->dwcbValid < dwcbNewUncommitted)
  377. {
  378. DWORD dwcbNewFileLen;
  379. picf->dwcbValid = dwcbNewUncommitted;
  380. /* Watch out for overflow. */
  381. ASSERT(picf->dwcbFileOffsetOfCache <= DWORD_MAX - dwcbNewUncommitted);
  382. dwcbNewFileLen = picf->dwcbFileOffsetOfCache + dwcbNewUncommitted;
  383. if (picf->dwcbFileLen < dwcbNewFileLen)
  384. picf->dwcbFileLen = dwcbNewFileLen;
  385. }
  386. }
  387. return(dwcbWritten);
  388. }
  389. /*
  390. ** GetAvailableWriteSpace()
  391. **
  392. **
  393. **
  394. ** Arguments:
  395. **
  396. ** Returns:
  397. **
  398. ** Side Effects: none
  399. */
  400. PRIVATE_CODE DWORD GetAvailableWriteSpace(PICACHEDFILE picf, PBYTE *ppbyteStart)
  401. {
  402. DWORD dwcbAvailable;
  403. ASSERT(IS_VALID_STRUCT_PTR(picf, CICACHEDFILE));
  404. ASSERT(IS_VALID_WRITE_PTR(ppbyteStart, PBYTE *));
  405. ASSERT(IS_FLAG_SET(picf->dwOpenMode, GENERIC_WRITE));
  406. /* Is there room to write data in the cache? */
  407. /*
  408. * The current file position must be inside or just after the end of the
  409. * valid data in the cache, or at the front of the cache when there is no
  410. * valid data in the cache.
  411. */
  412. /* Watch out for overflow. */
  413. ASSERT(picf->dwcbFileOffsetOfCache <= DWORD_MAX - picf->dwcbValid);
  414. if (picf->dwcbCurFilePosition >= picf->dwcbFileOffsetOfCache &&
  415. picf->dwcbCurFilePosition <= picf->dwcbFileOffsetOfCache + picf->dwcbValid)
  416. {
  417. DWORD dwcbStartBias;
  418. /* Yes. */
  419. dwcbStartBias = picf->dwcbCurFilePosition - picf->dwcbFileOffsetOfCache;
  420. *ppbyteStart = picf->pbyteCache + dwcbStartBias;
  421. /* Watch out for underflow. */
  422. ASSERT(picf->dwcbCacheSize >= dwcbStartBias);
  423. dwcbAvailable = picf->dwcbCacheSize - dwcbStartBias;
  424. }
  425. else
  426. /* No. */
  427. dwcbAvailable = 0;
  428. return(dwcbAvailable);
  429. }
  430. /*
  431. ** CommitCache()
  432. **
  433. **
  434. **
  435. ** Arguments:
  436. **
  437. ** Returns:
  438. **
  439. ** Side Effects: none
  440. **
  441. ** Calling CommitCache() on a file opened without write access is a NOP.
  442. */
  443. PRIVATE_CODE BOOL CommitCache(PICACHEDFILE picf)
  444. {
  445. BOOL bResult;
  446. ASSERT(IS_VALID_STRUCT_PTR(picf, CICACHEDFILE));
  447. /* Any data to commit? */
  448. if (IS_FLAG_SET(picf->dwOpenMode, GENERIC_WRITE) &&
  449. picf->dwcbUncommitted > 0)
  450. {
  451. DWORD dwcbOffset;
  452. /* Yes. Seek to start position of cache in file. */
  453. bResult = FALSE;
  454. dwcbOffset = SetFilePointer(picf->hfile, picf->dwcbFileOffsetOfCache, NULL, FILE_BEGIN);
  455. if (dwcbOffset != INVALID_SEEK_POSITION)
  456. {
  457. DWORD dwcbWritten;
  458. ASSERT(dwcbOffset == picf->dwcbFileOffsetOfCache);
  459. /* Write to file from cache. */
  460. if (WriteFile(picf->hfile, picf->pbyteCache, picf->dwcbUncommitted, &dwcbWritten, NULL) &&
  461. dwcbWritten == picf->dwcbUncommitted)
  462. {
  463. TRACE_OUT((TEXT("CommitCache(): Committed %lu uncommitted bytes starting at offset %lu in file %s."),
  464. dwcbWritten,
  465. dwcbOffset,
  466. picf->pszPath));
  467. bResult = TRUE;
  468. }
  469. }
  470. }
  471. else
  472. bResult = TRUE;
  473. return(bResult);
  474. }
  475. #ifdef VSTF
  476. /*
  477. ** IsValidPCICACHEDFILE()
  478. **
  479. **
  480. **
  481. ** Arguments:
  482. **
  483. ** Returns:
  484. **
  485. ** Side Effects: none
  486. */
  487. PRIVATE_CODE BOOL IsValidPCICACHEDFILE(PCICACHEDFILE pcicf)
  488. {
  489. return(IS_VALID_READ_PTR(pcicf, CICACHEDFILE) &&
  490. IS_VALID_HANDLE(pcicf->hfile, FILE) &&
  491. FLAGS_ARE_VALID(pcicf->dwOpenMode, ALL_FILE_ACCESS_FLAGS) &&
  492. EVAL(pcicf->dwcbCacheSize > 0) &&
  493. IS_VALID_WRITE_BUFFER_PTR(pcicf->pbyteCache, BYTE, (UINT)(pcicf->dwcbCacheSize)) &&
  494. IS_VALID_WRITE_BUFFER_PTR(pcicf->pbyteDefaultCache, BYTE, (UINT)(pcicf->dwcbDefaultCacheSize)) &&
  495. EVAL(pcicf->dwcbCacheSize > pcicf->dwcbDefaultCacheSize ||
  496. pcicf->pbyteCache == pcicf->pbyteDefaultCache) &&
  497. IS_VALID_STRING_PTR(pcicf->pszPath, STR) &&
  498. EVAL(IS_FLAG_SET(pcicf->dwOpenMode, GENERIC_WRITE) ||
  499. ! pcicf->dwcbUncommitted) &&
  500. (EVAL(pcicf->dwcbValid <= pcicf->dwcbCacheSize) &&
  501. EVAL(pcicf->dwcbUncommitted <= pcicf->dwcbCacheSize) &&
  502. EVAL(pcicf->dwcbUncommitted <= pcicf->dwcbValid) &&
  503. (EVAL(! pcicf->dwcbValid ||
  504. pcicf->dwcbFileLen >= pcicf->dwcbFileOffsetOfCache + pcicf->dwcbValid) &&
  505. EVAL(! pcicf->dwcbUncommitted ||
  506. pcicf->dwcbFileLen >= pcicf->dwcbFileOffsetOfCache + pcicf->dwcbUncommitted))));
  507. }
  508. #endif /* VSTF */
  509. #endif /* NOFCACHE */
  510. #ifdef VSTF
  511. /*
  512. ** IsValidPCCACHEDFILE()
  513. **
  514. **
  515. **
  516. ** Arguments:
  517. **
  518. ** Returns:
  519. **
  520. ** Side Effects: none
  521. */
  522. PRIVATE_CODE BOOL IsValidPCCACHEDFILE(PCCACHEDFILE pccf)
  523. {
  524. return(IS_VALID_READ_PTR(pccf, CCACHEDFILE) &&
  525. IS_VALID_STRING_PTR(pccf->pcszPath, CSTR) &&
  526. EVAL(pccf->dwcbDefaultCacheSize > 0) &&
  527. FLAGS_ARE_VALID(pccf->dwOpenMode, ALL_FILE_ACCESS_FLAGS) &&
  528. FLAGS_ARE_VALID(pccf->dwSharingMode, ALL_FILE_SHARING_FLAGS) &&
  529. (! pccf->psa ||
  530. IS_VALID_STRUCT_PTR(pccf->psa, CSECURITY_ATTRIBUTES)) &&
  531. IsValidFileCreationMode(pccf->dwCreateMode) &&
  532. FLAGS_ARE_VALID(pccf->dwAttrsAndFlags, ALL_FILE_ATTRIBUTES_AND_FLAGS) &&
  533. IS_VALID_HANDLE(pccf->hTemplateFile, TEMPLATEFILE));
  534. }
  535. #endif /* VSTF */
  536. /****************************** Public Functions *****************************/
  537. /*
  538. ** CreateCachedFile()
  539. **
  540. **
  541. **
  542. ** Arguments:
  543. **
  544. ** Returns:
  545. **
  546. ** Side Effects: none
  547. */
  548. PUBLIC_CODE FCRESULT CreateCachedFile(PCCACHEDFILE pccf, PHCACHEDFILE phcf)
  549. {
  550. ASSERT(IS_VALID_STRUCT_PTR(pccf, CCACHEDFILE));
  551. ASSERT(IS_VALID_WRITE_PTR(phcf, HCACHEDFILE));
  552. return(SetUpCachedFile(pccf, phcf));
  553. }
  554. /*
  555. ** SetCachedFileCacheSize()
  556. **
  557. **
  558. **
  559. ** Arguments:
  560. **
  561. ** Returns:
  562. **
  563. ** Side Effects: Commits the cache, and discards cached data.
  564. */
  565. PUBLIC_CODE FCRESULT SetCachedFileCacheSize(HCACHEDFILE hcf, DWORD dwcbNewCacheSize)
  566. {
  567. FCRESULT fcr;
  568. /* dwcbNewCacheSize may be any value here. */
  569. ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  570. #ifdef NOFCACHE
  571. fcr = FCR_SUCCESS;
  572. #else
  573. /* Use default cache size instead of 0. */
  574. if (! dwcbNewCacheSize)
  575. {
  576. ASSERT(((PICACHEDFILE)hcf)->dwcbDefaultCacheSize > 0);
  577. dwcbNewCacheSize = ((PICACHEDFILE)hcf)->dwcbDefaultCacheSize;
  578. }
  579. /* Is the cache size changing? */
  580. if (dwcbNewCacheSize == ((PICACHEDFILE)hcf)->dwcbCacheSize)
  581. /* No. Whine about it. */
  582. WARNING_OUT((TEXT("SetCachedFileCacheSize(): Cache size is already %lu bytes."),
  583. dwcbNewCacheSize));
  584. /* Commit the cache so we can change its size. */
  585. if (CommitCache((PICACHEDFILE)hcf))
  586. {
  587. PBYTE pbyteNewCache;
  588. /* Throw away cached data. */
  589. ResetCacheToEmpty((PICACHEDFILE)hcf);
  590. /* Do we need to allocate a new cache? */
  591. if (dwcbNewCacheSize <= ((PICACHEDFILE)hcf)->dwcbDefaultCacheSize)
  592. {
  593. /* No. */
  594. pbyteNewCache = ((PICACHEDFILE)hcf)->pbyteDefaultCache;
  595. fcr = FCR_SUCCESS;
  596. TRACE_OUT((TEXT("SetCachedFileCacheSize(): Using %lu bytes of %lu bytes allocated to default cache."),
  597. dwcbNewCacheSize,
  598. ((PICACHEDFILE)hcf)->dwcbDefaultCacheSize));
  599. }
  600. else
  601. {
  602. /* Yes. */
  603. if (AllocateMemory(dwcbNewCacheSize, &pbyteNewCache))
  604. {
  605. fcr = FCR_SUCCESS;
  606. TRACE_OUT((TEXT("SetCachedFileCacheSize(): Allocated %lu bytes for new cache."),
  607. dwcbNewCacheSize));
  608. }
  609. else
  610. fcr = FCR_OUT_OF_MEMORY;
  611. }
  612. if (fcr == FCR_SUCCESS)
  613. {
  614. /* Do we need to free the old cache? */
  615. if (((PICACHEDFILE)hcf)->pbyteCache != ((PICACHEDFILE)hcf)->pbyteDefaultCache)
  616. {
  617. /* Yes. */
  618. ASSERT(((PICACHEDFILE)hcf)->dwcbCacheSize > ((PICACHEDFILE)hcf)->dwcbDefaultCacheSize);
  619. FreeMemory(((PICACHEDFILE)hcf)->pbyteCache);
  620. }
  621. /* Use new cache. */
  622. ((PICACHEDFILE)hcf)->pbyteCache = pbyteNewCache;
  623. ((PICACHEDFILE)hcf)->dwcbCacheSize = dwcbNewCacheSize;
  624. }
  625. }
  626. else
  627. fcr = FCR_WRITE_FAILED;
  628. #endif
  629. return(fcr);
  630. }
  631. /*
  632. ** SeekInCachedFile()
  633. **
  634. **
  635. **
  636. ** Arguments:
  637. **
  638. ** Returns:
  639. **
  640. ** Side Effects: none
  641. */
  642. PUBLIC_CODE DWORD SeekInCachedFile(HCACHEDFILE hcf, DWORD dwcbSeek, DWORD uOrigin)
  643. {
  644. DWORD dwcbResult;
  645. ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  646. ASSERT(uOrigin == FILE_BEGIN || uOrigin == FILE_CURRENT || uOrigin == FILE_END);
  647. #ifdef NOFCACHE
  648. dwcbResult = SetFilePointer(hcf, dwcbSeek, NULL, uOrigin);
  649. #else
  650. {
  651. BOOL bValidTarget = TRUE;
  652. DWORD dwcbWorkingOffset = 0;
  653. /* Determine seek base. */
  654. switch (uOrigin)
  655. {
  656. case SEEK_CUR:
  657. dwcbWorkingOffset = ((PICACHEDFILE)hcf)->dwcbCurFilePosition;
  658. break;
  659. case SEEK_SET:
  660. break;
  661. case SEEK_END:
  662. dwcbWorkingOffset = ((PICACHEDFILE)hcf)->dwcbFileLen;
  663. break;
  664. default:
  665. bValidTarget = FALSE;
  666. break;
  667. }
  668. if (bValidTarget)
  669. {
  670. /* Add bias. */
  671. /* Watch out for overflow. */
  672. ASSERT(dwcbWorkingOffset <= DWORD_MAX - dwcbSeek);
  673. dwcbWorkingOffset += dwcbSeek;
  674. ((PICACHEDFILE)hcf)->dwcbCurFilePosition = dwcbWorkingOffset;
  675. dwcbResult = dwcbWorkingOffset;
  676. }
  677. else
  678. dwcbResult = INVALID_SEEK_POSITION;
  679. }
  680. #endif /* NOFCACHE */
  681. return(dwcbResult);
  682. }
  683. /*
  684. ** SetEndOfCachedFile()
  685. **
  686. **
  687. **
  688. ** Arguments:
  689. **
  690. ** Returns:
  691. **
  692. ** Side Effects: Commits cache.
  693. */
  694. PUBLIC_CODE BOOL SetEndOfCachedFile(HCACHEDFILE hcf)
  695. {
  696. BOOL bResult;
  697. ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  698. bResult = CommitCache((PICACHEDFILE)hcf);
  699. if (bResult)
  700. {
  701. bResult = (SetFilePointer(((PICACHEDFILE)hcf)->hfile,
  702. ((PICACHEDFILE)hcf)->dwcbCurFilePosition, NULL,
  703. FILE_BEGIN) ==
  704. ((PICACHEDFILE)hcf)->dwcbCurFilePosition);
  705. if (bResult)
  706. {
  707. bResult = SetEndOfFile(((PICACHEDFILE)hcf)->hfile);
  708. if (bResult)
  709. {
  710. ResetCacheToEmpty((PICACHEDFILE)hcf);
  711. ((PICACHEDFILE)hcf)->dwcbFileLen = ((PICACHEDFILE)hcf)->dwcbCurFilePosition;
  712. #ifdef DEBUG
  713. {
  714. DWORD dwcbFileSizeHigh;
  715. DWORD dwcbFileSizeLow;
  716. dwcbFileSizeLow = GetFileSize(((PICACHEDFILE)hcf)->hfile, &dwcbFileSizeHigh);
  717. ASSERT(! dwcbFileSizeHigh);
  718. ASSERT(((PICACHEDFILE)hcf)->dwcbFileLen == dwcbFileSizeLow);
  719. ASSERT(((PICACHEDFILE)hcf)->dwcbCurFilePosition == dwcbFileSizeLow);
  720. }
  721. #endif
  722. }
  723. }
  724. }
  725. return(bResult);
  726. }
  727. /*
  728. ** GetCachedFilePointerPosition()
  729. **
  730. **
  731. **
  732. ** Arguments:
  733. **
  734. ** Returns:
  735. **
  736. ** Side Effects: none
  737. */
  738. PUBLIC_CODE DWORD GetCachedFilePointerPosition(HCACHEDFILE hcf)
  739. {
  740. ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  741. return(((PICACHEDFILE)hcf)->dwcbCurFilePosition);
  742. }
  743. /*
  744. ** GetCachedFileSize()
  745. **
  746. **
  747. **
  748. ** Arguments:
  749. **
  750. ** Returns:
  751. **
  752. ** Side Effects: none
  753. */
  754. PUBLIC_CODE DWORD GetCachedFileSize(HCACHEDFILE hcf)
  755. {
  756. ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  757. return(((PICACHEDFILE)hcf)->dwcbFileLen);
  758. }
  759. /*
  760. ** ReadFromCachedFile()
  761. **
  762. **
  763. **
  764. ** Arguments:
  765. **
  766. ** Returns:
  767. **
  768. ** Side Effects: none
  769. */
  770. PUBLIC_CODE BOOL ReadFromCachedFile(HCACHEDFILE hcf, PVOID hpbyteBuffer, DWORD dwcb,
  771. PDWORD pdwcbRead)
  772. {
  773. BOOL bResult;
  774. ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  775. ASSERT(IS_VALID_WRITE_BUFFER_PTR(hpbyteBuffer, BYTE, (UINT)dwcb));
  776. ASSERT(! pdwcbRead || IS_VALID_WRITE_PTR(pdwcbRead, DWORD));
  777. *pdwcbRead = 0;
  778. #ifdef NOFCACHE
  779. bResult = ReadFile(hcf, hpbyteBuffer, dwcb, pdwcbRead, NULL);
  780. #else
  781. /*
  782. * Make sure that the cached file has been set up for read access before
  783. * allowing a read.
  784. */
  785. if (IS_FLAG_SET(((PICACHEDFILE)hcf)->dwOpenMode, GENERIC_READ))
  786. {
  787. DWORD dwcbToRead = dwcb;
  788. /* Read requested data. */
  789. bResult = TRUE;
  790. while (dwcbToRead > 0)
  791. {
  792. DWORD dwcbRead;
  793. dwcbRead = ReadFromCache((PICACHEDFILE)hcf, hpbyteBuffer, dwcbToRead);
  794. /* Watch out for underflow. */
  795. ASSERT(dwcbRead <= dwcbToRead);
  796. dwcbToRead -= dwcbRead;
  797. if (dwcbToRead > 0)
  798. {
  799. DWORD dwcbNewData;
  800. if (FillCache((PICACHEDFILE)hcf, &dwcbNewData))
  801. {
  802. hpbyteBuffer = (PBYTE)hpbyteBuffer + dwcbRead;
  803. if (! dwcbNewData)
  804. break;
  805. }
  806. else
  807. {
  808. bResult = FALSE;
  809. break;
  810. }
  811. }
  812. }
  813. /* Watch out for underflow. */
  814. ASSERT(dwcb >= dwcbToRead);
  815. if (bResult && pdwcbRead)
  816. *pdwcbRead = dwcb - dwcbToRead;
  817. }
  818. else
  819. bResult = FALSE;
  820. #endif /* NOFCACHE */
  821. ASSERT(! pdwcbRead ||
  822. ((bResult && *pdwcbRead <= dwcb) ||
  823. (! bResult && ! *pdwcbRead)));
  824. return(bResult);
  825. }
  826. /*
  827. ** WriteToCachedFile()
  828. **
  829. **
  830. **
  831. ** Arguments:
  832. **
  833. ** Returns:
  834. **
  835. ** Side Effects: none
  836. **
  837. ** N.b., callers don't currently check that *pdwcbWritten == dwcb when
  838. ** WriteToCachedFile() returns TRUE.
  839. */
  840. PUBLIC_CODE BOOL WriteToCachedFile(HCACHEDFILE hcf, PCVOID hpbyteBuffer, DWORD dwcb,
  841. PDWORD pdwcbWritten)
  842. {
  843. BOOL bResult;
  844. ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  845. ASSERT(IS_VALID_READ_BUFFER_PTR(hpbyteBuffer, BYTE, (UINT)dwcb));
  846. ASSERT(dwcb > 0);
  847. #ifdef NOFCACHE
  848. bResult = WriteFile(hcf, hpbyteBuffer, dwcb, pdwcbWritten, NULL);
  849. #else
  850. /*
  851. * Make sure that the cached file has been set up for write access before
  852. * allowing a write.
  853. */
  854. if (IS_FLAG_SET(((PICACHEDFILE)hcf)->dwOpenMode, GENERIC_WRITE))
  855. {
  856. DWORD dwcbToWrite = dwcb;
  857. /* Write requested data. */
  858. bResult = TRUE;
  859. while (dwcbToWrite > 0)
  860. {
  861. DWORD dwcbWritten;
  862. dwcbWritten = WriteToCache((PICACHEDFILE)hcf, hpbyteBuffer, dwcbToWrite);
  863. /* Watch out for underflow. */
  864. ASSERT(dwcbWritten <= dwcbToWrite);
  865. dwcbToWrite -= dwcbWritten;
  866. if (dwcbToWrite > 0)
  867. {
  868. if (CommitCache((PICACHEDFILE)hcf))
  869. {
  870. ResetCacheToEmpty((PICACHEDFILE)hcf);
  871. hpbyteBuffer = (PCBYTE)hpbyteBuffer + dwcbWritten;
  872. }
  873. else
  874. {
  875. bResult = FALSE;
  876. break;
  877. }
  878. }
  879. }
  880. ASSERT(dwcb >= dwcbToWrite);
  881. if (pdwcbWritten)
  882. {
  883. if (bResult)
  884. {
  885. ASSERT(! dwcbToWrite);
  886. *pdwcbWritten = dwcb;
  887. }
  888. else
  889. *pdwcbWritten = 0;
  890. }
  891. }
  892. else
  893. bResult = FALSE;
  894. #endif /* NOFCACHE */
  895. ASSERT(! pdwcbWritten ||
  896. ((bResult && *pdwcbWritten == dwcb) ||
  897. (! bResult && ! *pdwcbWritten)));
  898. return(bResult);
  899. }
  900. /*
  901. ** CommitCachedFile()
  902. **
  903. **
  904. **
  905. ** Arguments:
  906. **
  907. ** Returns:
  908. **
  909. ** Side Effects: none
  910. */
  911. PUBLIC_CODE BOOL CommitCachedFile(HCACHEDFILE hcf)
  912. {
  913. BOOL bResult;
  914. ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  915. #ifdef NOFCACHE
  916. bResult = TRUE;
  917. #else
  918. /*
  919. * Make sure that the cached file has been set up for write access before
  920. * allowing a commit.
  921. */
  922. if (IS_FLAG_SET(((PICACHEDFILE)hcf)->dwOpenMode, GENERIC_WRITE))
  923. bResult = CommitCache((PICACHEDFILE)hcf);
  924. else
  925. bResult = FALSE;
  926. #endif /* NOFCACHE */
  927. return(bResult);
  928. }
  929. /*
  930. ** GetFileHandle()
  931. **
  932. **
  933. **
  934. ** Arguments:
  935. **
  936. ** Returns:
  937. **
  938. ** Side Effects: none
  939. */
  940. PUBLIC_CODE HANDLE GetFileHandle(HCACHEDFILE hcf)
  941. {
  942. HANDLE hfResult;
  943. ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  944. #ifdef NOFCACHE
  945. hfResult = hcf;
  946. #else
  947. hfResult = ((PCICACHEDFILE)hcf)->hfile;
  948. #endif /* NOFCACHE */
  949. return(hfResult);
  950. }
  951. /*
  952. ** CloseCachedFile()
  953. **
  954. **
  955. **
  956. ** Arguments:
  957. **
  958. ** Returns:
  959. **
  960. ** Side Effects: none
  961. */
  962. PUBLIC_CODE BOOL CloseCachedFile(HCACHEDFILE hcf)
  963. {
  964. BOOL bResult;
  965. ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  966. #ifdef NOFCACHE
  967. bResult = CloseHandle(hcf);
  968. #else
  969. {
  970. BOOL bCommit;
  971. BOOL bClose;
  972. bCommit = CommitCache((PICACHEDFILE)hcf);
  973. bClose = CloseHandle(((PCICACHEDFILE)hcf)->hfile);
  974. BreakDownCachedFile((PICACHEDFILE)hcf);
  975. bResult = bCommit && bClose;
  976. }
  977. #endif /* NOFCACHE */
  978. return(bResult);
  979. }
  980. #if defined(DEBUG) || defined(VSTF)
  981. /*
  982. ** IsValidHCACHEDFILE()
  983. **
  984. **
  985. **
  986. ** Arguments:
  987. **
  988. ** Returns:
  989. **
  990. ** Side Effects: none
  991. */
  992. PUBLIC_CODE BOOL IsValidHCACHEDFILE(HCACHEDFILE hcf)
  993. {
  994. BOOL bResult;
  995. #ifdef NOFCACHE
  996. bResult = TRUE;
  997. #else
  998. bResult = IS_VALID_STRUCT_PTR((PCICACHEDFILE)hcf, CICACHEDFILE);
  999. #endif /* NOFCACHE */
  1000. return(bResult);
  1001. }
  1002. #endif /* DEBUG || VSTF */