|
|
/*
* fcache.c - File cache ADT module. */
/*
The file cache ADT may be disabled by #defining NOFCACHE. If NOFCACHE is #defined, file cache ADT calls are translated into their direct Win32 file
system API equivalents.
*/
/* Headers
**********/
#include "project.h"
#pragma hdrstop
/* Constants
************/
/* last resort default minimum cache size */
#define DEFAULT_MIN_CACHE_SIZE (32)
/* Types
********/
#ifndef NOFCACHE
/* cached file description structure */
typedef struct _icachedfile { /* current position of file pointer in file */
DWORD dwcbCurFilePosition;
/* file handle of cached file */
HANDLE hfile;
/* file open mode */
DWORD dwOpenMode;
/* size of cache in bytes */
DWORD dwcbCacheSize;
/* pointer to base of cache */
PBYTE pbyteCache;
/* size of default cache in bytes */
DWORD dwcbDefaultCacheSize;
/* default cache */
PBYTE pbyteDefaultCache;
/* length of file (including data written to cache) */
DWORD dwcbFileLen;
/* offset of start of cache in file */
DWORD dwcbFileOffsetOfCache;
/* number of valid bytes in cache, starting at beginning of cache */
DWORD dwcbValid;
/* number of uncommitted bytes in cache, starting at beginning of cache */
DWORD dwcbUncommitted;
/* path of cached file */
LPTSTR pszPath; } ICACHEDFILE; DECLARE_STANDARD_TYPES(ICACHEDFILE);
#endif /* NOFCACHE */
/***************************** Private Functions *****************************/
/* Module Prototypes
********************/
PRIVATE_CODE FCRESULT SetUpCachedFile(PCCACHEDFILE, PHCACHEDFILE);
#ifndef NOFCACHE
PRIVATE_CODE void BreakDownCachedFile(PICACHEDFILE); PRIVATE_CODE void ResetCacheToEmpty(PICACHEDFILE); PRIVATE_CODE DWORD ReadFromCache(PICACHEDFILE, PVOID, DWORD); PRIVATE_CODE DWORD GetValidReadData(PICACHEDFILE, PBYTE *); PRIVATE_CODE BOOL FillCache(PICACHEDFILE, PDWORD); PRIVATE_CODE DWORD WriteToCache(PICACHEDFILE, PCVOID, DWORD); PRIVATE_CODE DWORD GetAvailableWriteSpace(PICACHEDFILE, PBYTE *); PRIVATE_CODE BOOL CommitCache(PICACHEDFILE);
#ifdef VSTF
PRIVATE_CODE BOOL IsValidPCICACHEDFILE(PCICACHEDFILE);
#endif /* VSTF */
#endif /* NOFCACHE */
#ifdef VSTF
PRIVATE_CODE BOOL IsValidPCCACHEDFILE(PCCACHEDFILE);
#endif /* VSTF */
/*
** SetUpCachedFile() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE FCRESULT SetUpCachedFile(PCCACHEDFILE pccf, PHCACHEDFILE phcf) { FCRESULT fcr; HANDLE hfNew;
ASSERT(IS_VALID_STRUCT_PTR(pccf, CCACHEDFILE)); ASSERT(IS_VALID_WRITE_PTR(phcf, HCACHEDFILE));
/* Open the file with the requested open and sharing flags. */
hfNew = CreateFile(pccf->pcszPath, pccf->dwOpenMode, pccf->dwSharingMode, pccf->psa, pccf->dwCreateMode, pccf->dwAttrsAndFlags, pccf->hTemplateFile);
if (hfNew != INVALID_HANDLE_VALUE) {
#ifdef NOFCACHE
*phcf = hfNew;
fcr = FCR_SUCCESS;
#else
PICACHEDFILE picf;
fcr = FCR_OUT_OF_MEMORY;
/* Try to allocate a new cached file structure. */
if (AllocateMemory(sizeof(*picf), &picf)) { DWORD dwcbDefaultCacheSize;
/* Allocate the default cache for the cached file. */
if (pccf->dwcbDefaultCacheSize > 0) dwcbDefaultCacheSize = pccf->dwcbDefaultCacheSize; else { dwcbDefaultCacheSize = DEFAULT_MIN_CACHE_SIZE;
WARNING_OUT((TEXT("SetUpCachedFile(): Using minimum cache size of %lu instead of %lu."), dwcbDefaultCacheSize, pccf->dwcbDefaultCacheSize)); }
if (AllocateMemory(dwcbDefaultCacheSize, &(picf->pbyteDefaultCache))) { if (StringCopy(pccf->pcszPath, &(picf->pszPath))) { DWORD dwcbFileLenHigh;
picf->dwcbFileLen = GetFileSize(hfNew, &dwcbFileLenHigh);
if (picf->dwcbFileLen != INVALID_FILE_SIZE && ! dwcbFileLenHigh) { /* Success! Fill in cached file structure fields. */
picf->hfile = hfNew; picf->dwcbCurFilePosition = 0; picf->dwcbCacheSize = dwcbDefaultCacheSize; picf->pbyteCache = picf->pbyteDefaultCache; picf->dwcbDefaultCacheSize = dwcbDefaultCacheSize; picf->dwOpenMode = pccf->dwOpenMode;
ResetCacheToEmpty(picf);
*phcf = (HCACHEDFILE)picf; fcr = FCR_SUCCESS;
ASSERT(IS_VALID_HANDLE(*phcf, CACHEDFILE));
TRACE_OUT((TEXT("SetUpCachedFile(): Created %lu byte default cache for file %s."), picf->dwcbCacheSize, picf->pszPath)); } else { fcr = FCR_OPEN_FAILED;
SETUPCACHEDFILE_BAIL1: FreeMemory(picf->pbyteDefaultCache); SETUPCACHEDFILE_BAIL2: FreeMemory(picf); SETUPCACHEDFILE_BAIL3: /*
* Failing to close the file properly is not a failure * condition here. */ CloseHandle(hfNew); } } else goto SETUPCACHEDFILE_BAIL1; } else goto SETUPCACHEDFILE_BAIL2; } else goto SETUPCACHEDFILE_BAIL3;
#endif /* NOFCACHE */
} else { switch (GetLastError()) { /* Returned when file opened by local machine. */ case ERROR_SHARING_VIOLATION: fcr = FCR_FILE_LOCKED; break;
default: fcr = FCR_OPEN_FAILED; break; } }
return(fcr); }
#ifndef NOFCACHE
/*
** BreakDownCachedFile() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE void BreakDownCachedFile(PICACHEDFILE picf) { ASSERT(IS_VALID_STRUCT_PTR(picf, CICACHEDFILE));
/* Are we using the default cache? */
if (picf->pbyteCache != picf->pbyteDefaultCache) /* No. Free the cache. */ FreeMemory(picf->pbyteCache);
/* Free the default cache. */
FreeMemory(picf->pbyteDefaultCache);
TRACE_OUT((TEXT("BreakDownCachedFile(): Destroyed cache for file %s."), picf->pszPath));
FreeMemory(picf->pszPath); FreeMemory(picf);
return; }
/*
** ResetCacheToEmpty() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE void ResetCacheToEmpty(PICACHEDFILE picf) { /*
* Don't fully validate *picf here since we may be called by * SetUpCachedFile() before *picf has been set up. */
ASSERT(IS_VALID_WRITE_PTR(picf, ICACHEDFILE));
picf->dwcbFileOffsetOfCache = picf->dwcbCurFilePosition; picf->dwcbValid = 0; picf->dwcbUncommitted = 0;
return; }
/*
** ReadFromCache() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE DWORD ReadFromCache(PICACHEDFILE picf, PVOID hpbyteBuffer, DWORD dwcb) { DWORD dwcbRead; PBYTE pbyteStart; DWORD dwcbValid;
ASSERT(IS_VALID_STRUCT_PTR(picf, CICACHEDFILE)); ASSERT(IS_VALID_WRITE_BUFFER_PTR(hpbyteBuffer, BYTE, (UINT)dwcb));
ASSERT(IS_FLAG_SET(picf->dwOpenMode, GENERIC_READ)); ASSERT(dwcb > 0);
/* Is there any valid data that can be read from the cache? */
dwcbValid = GetValidReadData(picf, &pbyteStart);
if (dwcbValid > 0) { /* Yes. Copy it into the buffer. */
dwcbRead = min(dwcbValid, dwcb);
CopyMemory(hpbyteBuffer, pbyteStart, dwcbRead);
picf->dwcbCurFilePosition += dwcbRead; } else dwcbRead = 0;
return(dwcbRead); }
/*
** GetValidReadData() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE DWORD GetValidReadData(PICACHEDFILE picf, PBYTE *ppbyteStart) { DWORD dwcbValid;
ASSERT(IS_VALID_STRUCT_PTR(picf, CICACHEDFILE)); ASSERT(IS_VALID_WRITE_PTR(ppbyteStart, PBYTE *));
ASSERT(IS_FLAG_SET(picf->dwOpenMode, GENERIC_READ));
/* Is there any valid read data in the cache? */
/* The current file position must be inside the valid data in the cache. */
/* Watch out for overflow. */
ASSERT(picf->dwcbFileOffsetOfCache <= DWORD_MAX - picf->dwcbValid);
if (picf->dwcbCurFilePosition >= picf->dwcbFileOffsetOfCache && picf->dwcbCurFilePosition < picf->dwcbFileOffsetOfCache + picf->dwcbValid) { DWORD dwcbStartBias;
/* Yes. */
dwcbStartBias = picf->dwcbCurFilePosition - picf->dwcbFileOffsetOfCache;
*ppbyteStart = picf->pbyteCache + dwcbStartBias;
/* The second clause above protects against underflow here. */
dwcbValid = picf->dwcbValid - dwcbStartBias; } else /* No. */ dwcbValid = 0;
return(dwcbValid); }
/*
** FillCache() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE BOOL FillCache(PICACHEDFILE picf, PDWORD pdwcbNewData) { BOOL bResult = FALSE;
ASSERT(IS_VALID_STRUCT_PTR(picf, CICACHEDFILE)); ASSERT(IS_VALID_WRITE_PTR(pdwcbNewData, DWORD));
ASSERT(IS_FLAG_SET(picf->dwOpenMode, GENERIC_READ));
if (CommitCache(picf)) { DWORD dwcbOffset;
ResetCacheToEmpty(picf);
/* Seek to start position. */
dwcbOffset = SetFilePointer(picf->hfile, picf->dwcbCurFilePosition, NULL, FILE_BEGIN);
if (dwcbOffset != INVALID_SEEK_POSITION) { DWORD dwcbRead;
ASSERT(dwcbOffset == picf->dwcbCurFilePosition);
/* Fill cache from file. */
if (ReadFile(picf->hfile, picf->pbyteCache, picf->dwcbCacheSize, &dwcbRead, NULL)) { picf->dwcbValid = dwcbRead;
*pdwcbNewData = dwcbRead; bResult = TRUE;
TRACE_OUT((TEXT("FillCache(): Read %lu bytes into cache starting at offset %lu in file %s."), dwcbRead, dwcbOffset, picf->pszPath)); } } }
return(bResult); }
/*
** WriteToCache() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE DWORD WriteToCache(PICACHEDFILE picf, PCVOID hpbyteBuffer, DWORD dwcb) { DWORD dwcbAvailable; PBYTE pbyteStart; DWORD dwcbWritten; DWORD dwcbNewUncommitted;
ASSERT(IS_VALID_STRUCT_PTR(picf, CICACHEDFILE)); ASSERT(IS_VALID_READ_BUFFER_PTR(hpbyteBuffer, BYTE, (UINT)dwcb));
ASSERT(IS_FLAG_SET(picf->dwOpenMode, GENERIC_WRITE)); ASSERT(dwcb > 0);
/* Is there any room left to write data into the cache? */
dwcbAvailable = GetAvailableWriteSpace(picf, &pbyteStart);
/* Yes. Determine how much to copy into cache. */
dwcbWritten = min(dwcbAvailable, dwcb);
/* Can we write anything into the cache? */
if (dwcbWritten > 0) { /* Yes. Write it. */
CopyMemory(pbyteStart, hpbyteBuffer, dwcbWritten);
/* Watch out for overflow. */
ASSERT(picf->dwcbCurFilePosition <= DWORD_MAX - dwcbWritten);
picf->dwcbCurFilePosition += dwcbWritten;
/* Watch out for underflow. */
ASSERT(picf->dwcbCurFilePosition >= picf->dwcbFileOffsetOfCache);
dwcbNewUncommitted = picf->dwcbCurFilePosition - picf->dwcbFileOffsetOfCache;
if (picf->dwcbUncommitted < dwcbNewUncommitted) picf->dwcbUncommitted = dwcbNewUncommitted;
if (picf->dwcbValid < dwcbNewUncommitted) { DWORD dwcbNewFileLen;
picf->dwcbValid = dwcbNewUncommitted;
/* Watch out for overflow. */
ASSERT(picf->dwcbFileOffsetOfCache <= DWORD_MAX - dwcbNewUncommitted);
dwcbNewFileLen = picf->dwcbFileOffsetOfCache + dwcbNewUncommitted;
if (picf->dwcbFileLen < dwcbNewFileLen) picf->dwcbFileLen = dwcbNewFileLen; } }
return(dwcbWritten); }
/*
** GetAvailableWriteSpace() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE DWORD GetAvailableWriteSpace(PICACHEDFILE picf, PBYTE *ppbyteStart) { DWORD dwcbAvailable;
ASSERT(IS_VALID_STRUCT_PTR(picf, CICACHEDFILE)); ASSERT(IS_VALID_WRITE_PTR(ppbyteStart, PBYTE *));
ASSERT(IS_FLAG_SET(picf->dwOpenMode, GENERIC_WRITE));
/* Is there room to write data in the cache? */
/*
* The current file position must be inside or just after the end of the * valid data in the cache, or at the front of the cache when there is no * valid data in the cache. */
/* Watch out for overflow. */
ASSERT(picf->dwcbFileOffsetOfCache <= DWORD_MAX - picf->dwcbValid);
if (picf->dwcbCurFilePosition >= picf->dwcbFileOffsetOfCache && picf->dwcbCurFilePosition <= picf->dwcbFileOffsetOfCache + picf->dwcbValid) { DWORD dwcbStartBias;
/* Yes. */
dwcbStartBias = picf->dwcbCurFilePosition - picf->dwcbFileOffsetOfCache;
*ppbyteStart = picf->pbyteCache + dwcbStartBias;
/* Watch out for underflow. */
ASSERT(picf->dwcbCacheSize >= dwcbStartBias);
dwcbAvailable = picf->dwcbCacheSize - dwcbStartBias; } else /* No. */ dwcbAvailable = 0;
return(dwcbAvailable); }
/*
** CommitCache() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none ** ** Calling CommitCache() on a file opened without write access is a NOP. */ PRIVATE_CODE BOOL CommitCache(PICACHEDFILE picf) { BOOL bResult;
ASSERT(IS_VALID_STRUCT_PTR(picf, CICACHEDFILE));
/* Any data to commit? */
if (IS_FLAG_SET(picf->dwOpenMode, GENERIC_WRITE) && picf->dwcbUncommitted > 0) { DWORD dwcbOffset;
/* Yes. Seek to start position of cache in file. */
bResult = FALSE;
dwcbOffset = SetFilePointer(picf->hfile, picf->dwcbFileOffsetOfCache, NULL, FILE_BEGIN);
if (dwcbOffset != INVALID_SEEK_POSITION) { DWORD dwcbWritten;
ASSERT(dwcbOffset == picf->dwcbFileOffsetOfCache);
/* Write to file from cache. */
if (WriteFile(picf->hfile, picf->pbyteCache, picf->dwcbUncommitted, &dwcbWritten, NULL) && dwcbWritten == picf->dwcbUncommitted) { TRACE_OUT((TEXT("CommitCache(): Committed %lu uncommitted bytes starting at offset %lu in file %s."), dwcbWritten, dwcbOffset, picf->pszPath));
bResult = TRUE; } } } else bResult = TRUE;
return(bResult); }
#ifdef VSTF
/*
** IsValidPCICACHEDFILE() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE BOOL IsValidPCICACHEDFILE(PCICACHEDFILE pcicf) { return(IS_VALID_READ_PTR(pcicf, CICACHEDFILE) && IS_VALID_HANDLE(pcicf->hfile, FILE) && FLAGS_ARE_VALID(pcicf->dwOpenMode, ALL_FILE_ACCESS_FLAGS) && EVAL(pcicf->dwcbCacheSize > 0) && IS_VALID_WRITE_BUFFER_PTR(pcicf->pbyteCache, BYTE, (UINT)(pcicf->dwcbCacheSize)) && IS_VALID_WRITE_BUFFER_PTR(pcicf->pbyteDefaultCache, BYTE, (UINT)(pcicf->dwcbDefaultCacheSize)) && EVAL(pcicf->dwcbCacheSize > pcicf->dwcbDefaultCacheSize || pcicf->pbyteCache == pcicf->pbyteDefaultCache) && IS_VALID_STRING_PTR(pcicf->pszPath, STR) && EVAL(IS_FLAG_SET(pcicf->dwOpenMode, GENERIC_WRITE) || ! pcicf->dwcbUncommitted) && (EVAL(pcicf->dwcbValid <= pcicf->dwcbCacheSize) && EVAL(pcicf->dwcbUncommitted <= pcicf->dwcbCacheSize) && EVAL(pcicf->dwcbUncommitted <= pcicf->dwcbValid) && (EVAL(! pcicf->dwcbValid || pcicf->dwcbFileLen >= pcicf->dwcbFileOffsetOfCache + pcicf->dwcbValid) && EVAL(! pcicf->dwcbUncommitted || pcicf->dwcbFileLen >= pcicf->dwcbFileOffsetOfCache + pcicf->dwcbUncommitted)))); }
#endif /* VSTF */
#endif /* NOFCACHE */
#ifdef VSTF
/*
** IsValidPCCACHEDFILE() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE BOOL IsValidPCCACHEDFILE(PCCACHEDFILE pccf) { return(IS_VALID_READ_PTR(pccf, CCACHEDFILE) && IS_VALID_STRING_PTR(pccf->pcszPath, CSTR) && EVAL(pccf->dwcbDefaultCacheSize > 0) && FLAGS_ARE_VALID(pccf->dwOpenMode, ALL_FILE_ACCESS_FLAGS) && FLAGS_ARE_VALID(pccf->dwSharingMode, ALL_FILE_SHARING_FLAGS) && (! pccf->psa || IS_VALID_STRUCT_PTR(pccf->psa, CSECURITY_ATTRIBUTES)) && IsValidFileCreationMode(pccf->dwCreateMode) && FLAGS_ARE_VALID(pccf->dwAttrsAndFlags, ALL_FILE_ATTRIBUTES_AND_FLAGS) && IS_VALID_HANDLE(pccf->hTemplateFile, TEMPLATEFILE)); }
#endif /* VSTF */
/****************************** Public Functions *****************************/
/*
** CreateCachedFile() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE FCRESULT CreateCachedFile(PCCACHEDFILE pccf, PHCACHEDFILE phcf) { ASSERT(IS_VALID_STRUCT_PTR(pccf, CCACHEDFILE)); ASSERT(IS_VALID_WRITE_PTR(phcf, HCACHEDFILE));
return(SetUpCachedFile(pccf, phcf)); }
/*
** SetCachedFileCacheSize() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: Commits the cache, and discards cached data. */ PUBLIC_CODE FCRESULT SetCachedFileCacheSize(HCACHEDFILE hcf, DWORD dwcbNewCacheSize) { FCRESULT fcr;
/* dwcbNewCacheSize may be any value here. */
ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
#ifdef NOFCACHE
fcr = FCR_SUCCESS;
#else
/* Use default cache size instead of 0. */
if (! dwcbNewCacheSize) { ASSERT(((PICACHEDFILE)hcf)->dwcbDefaultCacheSize > 0);
dwcbNewCacheSize = ((PICACHEDFILE)hcf)->dwcbDefaultCacheSize; }
/* Is the cache size changing? */
if (dwcbNewCacheSize == ((PICACHEDFILE)hcf)->dwcbCacheSize) /* No. Whine about it. */ WARNING_OUT((TEXT("SetCachedFileCacheSize(): Cache size is already %lu bytes."), dwcbNewCacheSize));
/* Commit the cache so we can change its size. */
if (CommitCache((PICACHEDFILE)hcf)) { PBYTE pbyteNewCache;
/* Throw away cached data. */
ResetCacheToEmpty((PICACHEDFILE)hcf);
/* Do we need to allocate a new cache? */
if (dwcbNewCacheSize <= ((PICACHEDFILE)hcf)->dwcbDefaultCacheSize) { /* No. */
pbyteNewCache = ((PICACHEDFILE)hcf)->pbyteDefaultCache;
fcr = FCR_SUCCESS;
TRACE_OUT((TEXT("SetCachedFileCacheSize(): Using %lu bytes of %lu bytes allocated to default cache."), dwcbNewCacheSize, ((PICACHEDFILE)hcf)->dwcbDefaultCacheSize)); } else { /* Yes. */
if (AllocateMemory(dwcbNewCacheSize, &pbyteNewCache)) { fcr = FCR_SUCCESS;
TRACE_OUT((TEXT("SetCachedFileCacheSize(): Allocated %lu bytes for new cache."), dwcbNewCacheSize)); } else fcr = FCR_OUT_OF_MEMORY; }
if (fcr == FCR_SUCCESS) { /* Do we need to free the old cache? */
if (((PICACHEDFILE)hcf)->pbyteCache != ((PICACHEDFILE)hcf)->pbyteDefaultCache) { /* Yes. */
ASSERT(((PICACHEDFILE)hcf)->dwcbCacheSize > ((PICACHEDFILE)hcf)->dwcbDefaultCacheSize);
FreeMemory(((PICACHEDFILE)hcf)->pbyteCache); }
/* Use new cache. */
((PICACHEDFILE)hcf)->pbyteCache = pbyteNewCache; ((PICACHEDFILE)hcf)->dwcbCacheSize = dwcbNewCacheSize; } } else fcr = FCR_WRITE_FAILED;
#endif
return(fcr); }
/*
** SeekInCachedFile() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE DWORD SeekInCachedFile(HCACHEDFILE hcf, DWORD dwcbSeek, DWORD uOrigin) { DWORD dwcbResult;
ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE)); ASSERT(uOrigin == FILE_BEGIN || uOrigin == FILE_CURRENT || uOrigin == FILE_END);
#ifdef NOFCACHE
dwcbResult = SetFilePointer(hcf, dwcbSeek, NULL, uOrigin);
#else
{ BOOL bValidTarget = TRUE; DWORD dwcbWorkingOffset = 0;
/* Determine seek base. */
switch (uOrigin) { case SEEK_CUR: dwcbWorkingOffset = ((PICACHEDFILE)hcf)->dwcbCurFilePosition; break;
case SEEK_SET: break;
case SEEK_END: dwcbWorkingOffset = ((PICACHEDFILE)hcf)->dwcbFileLen; break;
default: bValidTarget = FALSE; break; }
if (bValidTarget) { /* Add bias. */
/* Watch out for overflow. */
ASSERT(dwcbWorkingOffset <= DWORD_MAX - dwcbSeek);
dwcbWorkingOffset += dwcbSeek;
((PICACHEDFILE)hcf)->dwcbCurFilePosition = dwcbWorkingOffset; dwcbResult = dwcbWorkingOffset; } else dwcbResult = INVALID_SEEK_POSITION; }
#endif /* NOFCACHE */
return(dwcbResult); }
/*
** SetEndOfCachedFile() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: Commits cache. */ PUBLIC_CODE BOOL SetEndOfCachedFile(HCACHEDFILE hcf) { BOOL bResult;
ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
bResult = CommitCache((PICACHEDFILE)hcf);
if (bResult) { bResult = (SetFilePointer(((PICACHEDFILE)hcf)->hfile, ((PICACHEDFILE)hcf)->dwcbCurFilePosition, NULL, FILE_BEGIN) == ((PICACHEDFILE)hcf)->dwcbCurFilePosition);
if (bResult) { bResult = SetEndOfFile(((PICACHEDFILE)hcf)->hfile);
if (bResult) { ResetCacheToEmpty((PICACHEDFILE)hcf);
((PICACHEDFILE)hcf)->dwcbFileLen = ((PICACHEDFILE)hcf)->dwcbCurFilePosition;
#ifdef DEBUG
{ DWORD dwcbFileSizeHigh; DWORD dwcbFileSizeLow;
dwcbFileSizeLow = GetFileSize(((PICACHEDFILE)hcf)->hfile, &dwcbFileSizeHigh);
ASSERT(! dwcbFileSizeHigh); ASSERT(((PICACHEDFILE)hcf)->dwcbFileLen == dwcbFileSizeLow); ASSERT(((PICACHEDFILE)hcf)->dwcbCurFilePosition == dwcbFileSizeLow); }
#endif
} } }
return(bResult); }
/*
** GetCachedFilePointerPosition() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE DWORD GetCachedFilePointerPosition(HCACHEDFILE hcf) { ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
return(((PICACHEDFILE)hcf)->dwcbCurFilePosition); }
/*
** GetCachedFileSize() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE DWORD GetCachedFileSize(HCACHEDFILE hcf) { ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
return(((PICACHEDFILE)hcf)->dwcbFileLen); }
/*
** ReadFromCachedFile() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL ReadFromCachedFile(HCACHEDFILE hcf, PVOID hpbyteBuffer, DWORD dwcb, PDWORD pdwcbRead) { BOOL bResult;
ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE)); ASSERT(IS_VALID_WRITE_BUFFER_PTR(hpbyteBuffer, BYTE, (UINT)dwcb)); ASSERT(! pdwcbRead || IS_VALID_WRITE_PTR(pdwcbRead, DWORD));
*pdwcbRead = 0;
#ifdef NOFCACHE
bResult = ReadFile(hcf, hpbyteBuffer, dwcb, pdwcbRead, NULL);
#else
/*
* Make sure that the cached file has been set up for read access before * allowing a read. */
if (IS_FLAG_SET(((PICACHEDFILE)hcf)->dwOpenMode, GENERIC_READ)) { DWORD dwcbToRead = dwcb;
/* Read requested data. */
bResult = TRUE;
while (dwcbToRead > 0) { DWORD dwcbRead;
dwcbRead = ReadFromCache((PICACHEDFILE)hcf, hpbyteBuffer, dwcbToRead);
/* Watch out for underflow. */
ASSERT(dwcbRead <= dwcbToRead);
dwcbToRead -= dwcbRead;
if (dwcbToRead > 0) { DWORD dwcbNewData;
if (FillCache((PICACHEDFILE)hcf, &dwcbNewData)) { hpbyteBuffer = (PBYTE)hpbyteBuffer + dwcbRead;
if (! dwcbNewData) break; } else { bResult = FALSE; break; } } }
/* Watch out for underflow. */
ASSERT(dwcb >= dwcbToRead);
if (bResult && pdwcbRead) *pdwcbRead = dwcb - dwcbToRead; } else bResult = FALSE;
#endif /* NOFCACHE */
ASSERT(! pdwcbRead || ((bResult && *pdwcbRead <= dwcb) || (! bResult && ! *pdwcbRead)));
return(bResult); }
/*
** WriteToCachedFile() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none ** ** N.b., callers don't currently check that *pdwcbWritten == dwcb when ** WriteToCachedFile() returns TRUE. */ PUBLIC_CODE BOOL WriteToCachedFile(HCACHEDFILE hcf, PCVOID hpbyteBuffer, DWORD dwcb, PDWORD pdwcbWritten) { BOOL bResult;
ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE)); ASSERT(IS_VALID_READ_BUFFER_PTR(hpbyteBuffer, BYTE, (UINT)dwcb));
ASSERT(dwcb > 0);
#ifdef NOFCACHE
bResult = WriteFile(hcf, hpbyteBuffer, dwcb, pdwcbWritten, NULL);
#else
/*
* Make sure that the cached file has been set up for write access before * allowing a write. */
if (IS_FLAG_SET(((PICACHEDFILE)hcf)->dwOpenMode, GENERIC_WRITE)) { DWORD dwcbToWrite = dwcb;
/* Write requested data. */
bResult = TRUE;
while (dwcbToWrite > 0) { DWORD dwcbWritten;
dwcbWritten = WriteToCache((PICACHEDFILE)hcf, hpbyteBuffer, dwcbToWrite);
/* Watch out for underflow. */
ASSERT(dwcbWritten <= dwcbToWrite);
dwcbToWrite -= dwcbWritten;
if (dwcbToWrite > 0) { if (CommitCache((PICACHEDFILE)hcf)) { ResetCacheToEmpty((PICACHEDFILE)hcf);
hpbyteBuffer = (PCBYTE)hpbyteBuffer + dwcbWritten; } else { bResult = FALSE;
break; } } }
ASSERT(dwcb >= dwcbToWrite);
if (pdwcbWritten) { if (bResult) { ASSERT(! dwcbToWrite);
*pdwcbWritten = dwcb; } else *pdwcbWritten = 0; } } else bResult = FALSE;
#endif /* NOFCACHE */
ASSERT(! pdwcbWritten || ((bResult && *pdwcbWritten == dwcb) || (! bResult && ! *pdwcbWritten)));
return(bResult); }
/*
** CommitCachedFile() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL CommitCachedFile(HCACHEDFILE hcf) { BOOL bResult;
ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
#ifdef NOFCACHE
bResult = TRUE;
#else
/*
* Make sure that the cached file has been set up for write access before * allowing a commit. */
if (IS_FLAG_SET(((PICACHEDFILE)hcf)->dwOpenMode, GENERIC_WRITE)) bResult = CommitCache((PICACHEDFILE)hcf); else bResult = FALSE;
#endif /* NOFCACHE */
return(bResult); }
/*
** GetFileHandle() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE HANDLE GetFileHandle(HCACHEDFILE hcf) { HANDLE hfResult;
ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
#ifdef NOFCACHE
hfResult = hcf;
#else
hfResult = ((PCICACHEDFILE)hcf)->hfile;
#endif /* NOFCACHE */
return(hfResult); }
/*
** CloseCachedFile() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL CloseCachedFile(HCACHEDFILE hcf) { BOOL bResult;
ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
#ifdef NOFCACHE
bResult = CloseHandle(hcf);
#else
{ BOOL bCommit; BOOL bClose;
bCommit = CommitCache((PICACHEDFILE)hcf);
bClose = CloseHandle(((PCICACHEDFILE)hcf)->hfile);
BreakDownCachedFile((PICACHEDFILE)hcf);
bResult = bCommit && bClose; }
#endif /* NOFCACHE */
return(bResult); }
#if defined(DEBUG) || defined(VSTF)
/*
** IsValidHCACHEDFILE() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL IsValidHCACHEDFILE(HCACHEDFILE hcf) { BOOL bResult;
#ifdef NOFCACHE
bResult = TRUE;
#else
bResult = IS_VALID_STRUCT_PTR((PCICACHEDFILE)hcf, CICACHEDFILE);
#endif /* NOFCACHE */
return(bResult); }
#endif /* DEBUG || VSTF */
|