/* * 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 */