NT4/private/windows/rover/filesync/core/fcache.c
2020-09-30 17:12:29 +02:00

1373 lines
28 KiB
C

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