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.
2433 lines
55 KiB
2433 lines
55 KiB
/*++
|
|
|
|
Copyright (c) 1990 - 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
filepool.cxx
|
|
|
|
Abstract:
|
|
|
|
Contains the routines for handling Filepools for the Spooler. Contains the C++ objects
|
|
and the C wrapper functions.
|
|
|
|
Author:
|
|
|
|
Bryan Kilian (Bryankil) 5-Apr-2000
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
|
|
#include "precomp.h"
|
|
|
|
#pragma hdrstop
|
|
|
|
|
|
#include "filepool.hxx"
|
|
|
|
|
|
VOID FPCloseFiles(struct FileListItem * pItem, BOOL CloseShad);
|
|
|
|
/*--
|
|
|
|
Interface Functions:
|
|
|
|
CreateFilePool
|
|
GetFileItemHandle
|
|
GetNameFromHandle
|
|
GetWriterFromHandle
|
|
GetReaderFromHandle
|
|
ReleasePoolHandle
|
|
DestroyFilePool
|
|
|
|
--*/
|
|
|
|
/*********************
|
|
* CreateFilePool()
|
|
*
|
|
* Creates the Filepool.
|
|
*
|
|
* Arguments:
|
|
* OUT FilePool : Pointer to a Filepool handle.
|
|
* IN BasePath : String to use as a spool dir.
|
|
* IN PreNumStr : String to use as a filename prefix.
|
|
* IN SplExt : String to use as a spool extension.
|
|
* IN ShdExt : String to use as a shadow file extension.
|
|
* IN PoolTimeout : Dword in milliseconds before an idle pool item gets deleted.
|
|
* IN MaxFiles : Maximum number of free files in the pool.
|
|
*
|
|
* The path gets created as <Basepath>\<PreNumStr>XXXXX<SplExt>
|
|
*
|
|
*/
|
|
|
|
|
|
HRESULT CreateFilePool(
|
|
HANDLE * FilePoolHandle,
|
|
LPCTSTR BasePath,
|
|
LPCTSTR PreNumStr,
|
|
LPCTSTR SplExt,
|
|
LPCTSTR ShdExt,
|
|
DWORD PoolTimeout,
|
|
DWORD MaxFiles
|
|
)
|
|
{
|
|
HRESULT RetVal = E_FAIL;
|
|
|
|
class FilePool * FP = NULL;
|
|
|
|
if (FilePoolHandle && BasePath && PreNumStr && SplExt && ShdExt)
|
|
{
|
|
MaxFiles = (MaxFiles > 9999) ? 9999 : MaxFiles;
|
|
FP = new FilePool(
|
|
PoolTimeout,
|
|
MaxFiles
|
|
);
|
|
|
|
|
|
if ( FP )
|
|
{
|
|
RetVal = FP->AllocInit(
|
|
BasePath,
|
|
PreNumStr,
|
|
SplExt,
|
|
ShdExt
|
|
);
|
|
if (SUCCEEDED(RetVal))
|
|
{
|
|
*FilePoolHandle = (HANDLE) FP;
|
|
}
|
|
else
|
|
{
|
|
delete FP;
|
|
*FilePoolHandle = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RetVal = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RetVal = E_INVALIDARG;
|
|
}
|
|
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
/*********************
|
|
* GetFileItemHandle()
|
|
*
|
|
* Takes a FilePool Object and An empty Filehandle, and returns
|
|
* an open File handle. Use ReleasePoolHandle Once you're finished
|
|
* with the file.
|
|
*
|
|
* Arguments:
|
|
* IN FilePool : Handle of a FilePool Object Created with CreateFilePool()
|
|
* OUT FileItem : Pointer to a FileItem Handle.
|
|
* IN FromFilename : String to use as a filename.
|
|
*
|
|
* Returns Error if it is passed in an invalid argument, or S_OK if it succeeds.
|
|
*
|
|
*/
|
|
|
|
HRESULT
|
|
GetFileItemHandle(
|
|
HANDLE FilePoolHandle,
|
|
HANDLE * FileItem,
|
|
LPWSTR FromFilename
|
|
)
|
|
{
|
|
class FilePool * FP = NULL;
|
|
HRESULT RetVal = E_FAIL;
|
|
struct FileListItem * FLItem = NULL;
|
|
|
|
FP = (class FilePool *)FilePoolHandle;
|
|
|
|
RetVal = FP->GetWriteFileStruct(&FLItem, FromFilename);
|
|
|
|
if (SUCCEEDED(RetVal))
|
|
{
|
|
*FileItem = (HANDLE) FLItem;
|
|
}
|
|
else
|
|
{
|
|
*FileItem = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
|
|
/*********************
|
|
* GetNameFromHandle()
|
|
*
|
|
* Takes a FileItem and a string pointer, and returns
|
|
* an allocated string containing the name of the file.
|
|
*
|
|
* Arguments:
|
|
* IN FileItem : Handle of a FileItem, retrieved with GetFileItemHandle()
|
|
* OUT FileNameStr : Pointer to a string variable.
|
|
* IN IsSpool : BOOL - TRUE - Returns the Spool Filename, FALSE returns the Shadow Filename
|
|
*
|
|
* Returns Error if it is passed in an invalid argument or if it cannot allocate the string,
|
|
* or S_OK if it succeeds.
|
|
*
|
|
*/
|
|
|
|
HRESULT
|
|
GetNameFromHandle(
|
|
HANDLE FileItem,
|
|
PWSTR * FileNameStr,
|
|
BOOL IsSpool
|
|
)
|
|
{
|
|
HRESULT RetVal = S_OK;
|
|
struct FileListItem * FPI;
|
|
|
|
if (FileItem && (FileItem != INVALID_HANDLE_VALUE))
|
|
{
|
|
FPI = (struct FileListItem *)FileItem;
|
|
|
|
if (FileNameStr && !*FileNameStr)
|
|
{
|
|
if (IsSpool)
|
|
{
|
|
*FileNameStr = AllocSplStr(FPI->SplFilename);
|
|
}
|
|
else
|
|
{
|
|
*FileNameStr = AllocSplStr(FPI->ShdFilename);
|
|
}
|
|
if (!*FileNameStr)
|
|
{
|
|
RetVal = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RetVal = E_INVALIDARG;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RetVal = E_INVALIDARG;
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
/*********************
|
|
* GetCurrentWriter()
|
|
*
|
|
* Takes a FileItem and returns a FileHandle of the current WriteHandle if it exists.
|
|
*
|
|
* Arguments:
|
|
* IN FileItem : FileItem Handle.
|
|
* IN IsSpool : BOOL - TRUE: Returns the Spool file handle, FALSE returns the Shadow file handle.
|
|
*
|
|
* This will not create a writer if it is not yet created, and will also not update the object's flags.
|
|
*
|
|
* Return: Valid Handle if success or INVALID_HANDLE_VALUE.
|
|
*/
|
|
|
|
HANDLE GetCurrentWriter(
|
|
HANDLE FileItem,
|
|
BOOL IsSpool)
|
|
{
|
|
struct FileListItem * FPI;
|
|
HANDLE RetVal = INVALID_HANDLE_VALUE;
|
|
HANDLE Temp = INVALID_HANDLE_VALUE;
|
|
|
|
if (FileItem)
|
|
{
|
|
FPI = (struct FileListItem *) FileItem;
|
|
|
|
FPI->EnterCritSec();
|
|
|
|
if (IsSpool)
|
|
{
|
|
Temp = FPI->SplWriteHandle;
|
|
}
|
|
else
|
|
{
|
|
Temp = FPI->ShdWriteHandle;
|
|
}
|
|
|
|
FPI->LeaveCritSec();
|
|
|
|
if (Temp != INVALID_HANDLE_VALUE)
|
|
{
|
|
RetVal = Temp;
|
|
}
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
/*********************
|
|
* GetFileCreationInfo
|
|
*
|
|
* Takes a FileItem and returns a bitmap.
|
|
*
|
|
* Arguments:
|
|
* IN FileItem : FileItem Handle.
|
|
* OUT BitMap
|
|
*
|
|
* Returns bitmap indicating which files needed to be opened. Bitmap reset when
|
|
* the pool handle is released.
|
|
*
|
|
* Return: S_OK if success, otherwise an error value.
|
|
*/
|
|
|
|
|
|
HRESULT
|
|
GetFileCreationInfo(
|
|
HANDLE FileItem,
|
|
PDWORD BitMap
|
|
)
|
|
{
|
|
struct FileListItem * FPI;
|
|
*BitMap = 0;
|
|
|
|
if (FileItem && (FileItem != INVALID_HANDLE_VALUE))
|
|
{
|
|
FPI = (struct FileListItem *) FileItem;
|
|
*BitMap = FPI->CreateInfo;
|
|
return S_OK;
|
|
}
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
|
|
/*********************
|
|
* GetWriterFromHandle()
|
|
*
|
|
* Takes a FileItem and returns a FileHandle with an open Writer.
|
|
*
|
|
* Arguments:
|
|
* IN FileItem : FileItem Handle.
|
|
* OUT File : Pointer to a filehandle.
|
|
* IN IsSpool : BOOL - TRUE: Returns the Spool file handle, FALSE returns the Shadow file handle.
|
|
*
|
|
* This will create a writer if it is not yet created, and will also update the object's flags. It will
|
|
* return the current handle if there is one.
|
|
*
|
|
* Return: S_OK if success, otherwise an error value.
|
|
*/
|
|
|
|
HRESULT
|
|
GetWriterFromHandle(
|
|
HANDLE FileItem,
|
|
HANDLE * File,
|
|
BOOL IsSpool
|
|
)
|
|
{
|
|
HRESULT RetVal = S_OK;
|
|
class FilePool * FP = NULL;
|
|
struct FileListItem * FPI;
|
|
|
|
|
|
if (FileItem && File)
|
|
{
|
|
FPI = (struct FileListItem *) FileItem;
|
|
FP = FPI->FP;
|
|
|
|
*File = INVALID_HANDLE_VALUE;
|
|
|
|
FPI->EnterCritSec();
|
|
|
|
if (IsSpool)
|
|
{
|
|
if (FPI->SplWriteHandle == INVALID_HANDLE_VALUE)
|
|
{
|
|
RetVal = FP->CreateSplWriter(FPI);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
if (FPI->ShdWriteHandle == INVALID_HANDLE_VALUE)
|
|
{
|
|
RetVal = FP->CreateShdWriter(FPI);
|
|
}
|
|
|
|
}
|
|
|
|
if (SUCCEEDED(RetVal))
|
|
{
|
|
if (IsSpool)
|
|
{
|
|
*File = FPI->SplWriteHandle;
|
|
FPI->Status |= FP_STATUS_SPL_WRITING;
|
|
}
|
|
else
|
|
{
|
|
*File = FPI->ShdWriteHandle;
|
|
FPI->Status |= FP_STATUS_SHD_WRITING;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RetVal = E_FAIL;
|
|
}
|
|
|
|
FPI->LeaveCritSec();
|
|
|
|
}
|
|
else
|
|
{
|
|
RetVal = E_INVALIDARG;
|
|
}
|
|
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
/*********************
|
|
* GetReaderFromHandle()
|
|
*
|
|
* Takes a FileItem and returns a FileHandle with an open Reader.
|
|
*
|
|
* Arguments:
|
|
* IN FileItem : FileItem Handle.
|
|
* OUT File : Pointer to a filehandle.
|
|
*
|
|
* This will create a Reader if it is not yet created, and will also update the object's flags. It will
|
|
* return the current handle if there is one. It will also return the writer if the system is finished with it.
|
|
*
|
|
* Return: S_OK if success, otherwise an error value.
|
|
*/
|
|
|
|
HRESULT
|
|
GetReaderFromHandle(
|
|
HANDLE FileItem,
|
|
HANDLE * File
|
|
)
|
|
{
|
|
HRESULT RetVal = S_OK;
|
|
class FilePool * FP = NULL;
|
|
struct FileListItem * FPI;
|
|
|
|
if (FileItem)
|
|
{
|
|
FPI = (struct FileListItem *) FileItem;
|
|
FP = FPI->FP;
|
|
|
|
// CriticalSection
|
|
|
|
FPI->EnterCritSec();
|
|
|
|
if (!(FPI->Status & FP_STATUS_SPL_WRITING) &&
|
|
(FPI->SplWriteHandle != INVALID_HANDLE_VALUE) &&
|
|
(FPI->SplReadHandle == INVALID_HANDLE_VALUE) )
|
|
{
|
|
//
|
|
// We aren't writing this job anymore, we can reuse the
|
|
// write handle for reading.
|
|
//
|
|
if (!(FPI->Status & FP_STATUS_SPL_READING))
|
|
{
|
|
if (SetFilePointer(FPI->SplWriteHandle, 0, NULL, FILE_BEGIN) !=
|
|
INVALID_SET_FILE_POINTER)
|
|
{
|
|
*File = FPI->SplWriteHandle;
|
|
FPI->Status |= FP_STATUS_SPL_READING;
|
|
}
|
|
else
|
|
{
|
|
RetVal = E_FAIL;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
*File = FPI->SplWriteHandle;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We are still writing this job, so we need to use the readhandle.
|
|
//
|
|
if (FPI->SplReadHandle == INVALID_HANDLE_VALUE)
|
|
{
|
|
//
|
|
// The Reader doesn't already exist, We need to create it.
|
|
//
|
|
RetVal = FP->CreateSplReader(FPI);
|
|
|
|
}
|
|
|
|
if (SUCCEEDED(RetVal))
|
|
{
|
|
//
|
|
// We now have a valid handle
|
|
//
|
|
|
|
*File = FPI->SplReadHandle;
|
|
FPI->Status |= FP_STATUS_SPL_READING;
|
|
|
|
}
|
|
else
|
|
{
|
|
RetVal = E_FAIL;
|
|
}
|
|
|
|
}
|
|
|
|
FPI->LeaveCritSec();
|
|
|
|
}
|
|
else
|
|
{
|
|
RetVal = E_INVALIDARG;
|
|
}
|
|
return RetVal;
|
|
}
|
|
|
|
/*********************
|
|
* FishedReading()
|
|
*
|
|
* Indicates to the object that we are finished with it for reading purposes.
|
|
*
|
|
* Arguments:
|
|
* IN FileItem : Handle of a FileItem.
|
|
*
|
|
* Returns Error if it is passed in an invalid argument, or S_OK if it succeeds.
|
|
*
|
|
*/
|
|
|
|
HRESULT
|
|
FinishedReading(
|
|
HANDLE FileItem
|
|
)
|
|
{
|
|
HRESULT RetVal = S_OK;
|
|
struct FileListItem * FPI;
|
|
|
|
if (FileItem)
|
|
{
|
|
FPI = (struct FileListItem *) FileItem;
|
|
|
|
FPI->EnterCritSec();
|
|
FPI->Status &= ~FP_STATUS_SPL_READING;
|
|
CloseFilesCheck(FPI, kCloseReadHandle);
|
|
FPI->LeaveCritSec();
|
|
|
|
}
|
|
else
|
|
{
|
|
RetVal = E_INVALIDARG;
|
|
}
|
|
|
|
|
|
return RetVal;
|
|
|
|
}
|
|
|
|
/*********************
|
|
* FishedWriting()
|
|
*
|
|
* Indicates to the object that we are finished with it for writing purposes.
|
|
*
|
|
* Arguments:
|
|
* IN FileItem : Handle of a FileItem.
|
|
* IN IsSpool : BOOL - TRUE: Affects the Spl file, FALSE: Affects the Shd file.
|
|
*
|
|
* Returns Error if it is passed in an invalid argument, or S_OK if it succeeds.
|
|
*
|
|
*/
|
|
|
|
HRESULT
|
|
FinishedWriting(
|
|
HANDLE FileItem,
|
|
BOOL IsSpool
|
|
)
|
|
{
|
|
HRESULT RetVal = S_OK;
|
|
struct FileListItem * FPI;
|
|
|
|
if (FileItem)
|
|
{
|
|
FPI = (struct FileListItem *) FileItem;
|
|
|
|
FPI->EnterCritSec();
|
|
if (IsSpool)
|
|
{
|
|
FPI->Status &= ~FP_STATUS_SPL_WRITING;
|
|
CloseFilesCheck(FPI, kCloseWriteHandle);
|
|
}
|
|
else
|
|
{
|
|
FPI->Status &= ~FP_STATUS_SHD_WRITING;
|
|
CloseFilesCheck(FPI, kCloseShdHandle);
|
|
}
|
|
FPI->LeaveCritSec();
|
|
}
|
|
else
|
|
{
|
|
RetVal = E_INVALIDARG;
|
|
}
|
|
|
|
|
|
return RetVal;
|
|
|
|
}
|
|
|
|
/*********************
|
|
* ReleasePoolHandle()
|
|
*
|
|
* Releases the pool item back to the pool to reuse. The pool will not reuse the item if all the
|
|
* filehandles are closed, and also if we have reached our free files limit.
|
|
*
|
|
* Arguments:
|
|
* IN OUT FileItem : Pointer to a FileItem Handle.
|
|
*
|
|
* Returns Error if it fails, or S_OK if it succeeds. FileItem gets set to INVALID_HANDLE_VALUE if it succeeds.
|
|
*
|
|
*/
|
|
|
|
HRESULT
|
|
ReleasePoolHandle(
|
|
HANDLE * FileItem
|
|
)
|
|
{
|
|
HRESULT RetVal = S_OK;
|
|
class FilePool * FP = NULL;
|
|
struct FileListItem * FPI;
|
|
|
|
if (FileItem && *FileItem )
|
|
{
|
|
FPI = (struct FileListItem *) *FileItem;
|
|
FP = FPI->FP;
|
|
|
|
//
|
|
// This should not be in the critsec, since we might delete
|
|
// the critical section.
|
|
//
|
|
RetVal = FP->ReleasePoolHandle(FPI);
|
|
|
|
if (SUCCEEDED(RetVal))
|
|
{
|
|
*FileItem = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RetVal = E_INVALIDARG;
|
|
}
|
|
return RetVal;
|
|
}
|
|
|
|
/*********************
|
|
* RemoveFromFilePool()
|
|
*
|
|
* Removes the pool item from the pool completely and frees the associated memory.
|
|
*
|
|
* Arguments:
|
|
* IN OUT FileItem : Pointer to a FileItem Handle.
|
|
* IN Delete : BOOL, Tells us whether to delete the files or not.
|
|
*
|
|
* Returns Error if it fails, or S_OK if it succeeds. FileItem gets set to INVALID_HANDLE_VALUE if it succeeds.
|
|
*
|
|
*/
|
|
|
|
HRESULT
|
|
RemoveFromFilePool(
|
|
HANDLE* FileItem,
|
|
BOOL Delete
|
|
)
|
|
{
|
|
HRESULT RetVal = S_OK;
|
|
class FilePool * FP = NULL;
|
|
struct FileListItem * FPI;
|
|
|
|
if (FileItem && *FileItem )
|
|
{
|
|
FPI = (struct FileListItem *) *FileItem;
|
|
FP = FPI->FP;
|
|
|
|
RetVal = FP->RemoveFromPool(FPI, Delete);
|
|
|
|
if (SUCCEEDED(RetVal))
|
|
{
|
|
*FileItem = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RetVal = E_INVALIDARG;
|
|
}
|
|
return RetVal;
|
|
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Name
|
|
|
|
ForceCloseJobPoolFiles
|
|
|
|
Routine Description:
|
|
|
|
Closes all the handles to the SHD and SPL files, regardless if they are in use or not.
|
|
|
|
Arguments:
|
|
|
|
hFileItem - handle to file pool item
|
|
|
|
Return Value:
|
|
|
|
S_OK - all handles were closed or hFileItem is NULL
|
|
other HRESULT - an error occurred
|
|
|
|
--*/
|
|
HRESULT
|
|
ForceCloseJobPoolFiles(
|
|
HANDLE hFileItem
|
|
)
|
|
{
|
|
HRESULT hRet = S_OK;
|
|
|
|
if (hFileItem)
|
|
{
|
|
//
|
|
// Mark the files as ready to be closed. The function below
|
|
// won't close the file handles ,if they are in use
|
|
//
|
|
CloseFiles(hFileItem, TRUE);
|
|
|
|
//
|
|
// Because CloseFile marked the handles as ready to be closed, the function
|
|
// below will close the handle for writing to the spool file
|
|
//
|
|
if (FAILED(hRet = FinishedWriting(hFileItem, TRUE)))
|
|
{
|
|
DBGMSG(DBG_WARN, ("ForceCloseJobPoolFiles FinishedWriting on SPL file failed. HRESULT 0x%x\n", hRet));
|
|
}
|
|
|
|
//
|
|
// Because CloseFile marked the handles as ready to be closed, the function
|
|
// below will close the handle for reading from the spool file
|
|
//
|
|
if (FAILED(hRet = FinishedReading(hFileItem)))
|
|
{
|
|
DBGMSG(DBG_WARN, ("ForceCloseJobPoolFiles FinishedReading failed. HRESULT 0x%x\n", hRet));
|
|
}
|
|
|
|
//
|
|
// Because CloseFile marked the handles as ready to be closed, the function
|
|
// below will close the handle for writing to the shadow file
|
|
//
|
|
if (FAILED(hRet = FinishedWriting(hFileItem, FALSE)))
|
|
{
|
|
DBGMSG(DBG_WARN, ("ForceCloseJobPoolFiles FinishedWriting on SHD file failed. HRESULT 0x%x\n", hRet));
|
|
}
|
|
}
|
|
|
|
return hRet;
|
|
}
|
|
|
|
|
|
/*********************
|
|
* CloseFiles()
|
|
*
|
|
* Closes the filehandles in the Pool Item (To save memory).
|
|
*
|
|
* Arguments:
|
|
* IN FileItem : FileItem Handle.
|
|
* IN CloseShad : Close the shadow file handle too.
|
|
*
|
|
*
|
|
*/
|
|
|
|
VOID
|
|
CloseFiles(
|
|
HANDLE FileItem,
|
|
BOOL CloseShad
|
|
)
|
|
{
|
|
struct FileListItem * FPI;
|
|
|
|
if (FileItem )
|
|
{
|
|
FPI = (struct FileListItem *) FileItem;
|
|
|
|
FPCloseFiles(FPI, CloseShad);
|
|
}
|
|
}
|
|
|
|
/*********************
|
|
* CloseFilesCheck()
|
|
*
|
|
* Checks to see if there are any file handles which were not
|
|
* closed on the call to CloseFiles because they were in use.
|
|
* If the status was set at that time we delete the files now.
|
|
* Assumes we are holding the critical section.
|
|
*
|
|
* Arguments:
|
|
* IN FileListItem : FileListItem pointer.
|
|
* IN CloseHandle : Type of handle to be closed.
|
|
*
|
|
*/
|
|
|
|
VOID
|
|
CloseFilesCheck(
|
|
FileListItem *pItem,
|
|
ECloseHandle eCloseHandle
|
|
)
|
|
{
|
|
if (pItem)
|
|
{
|
|
switch (eCloseHandle)
|
|
{
|
|
case kCloseWriteHandle:
|
|
|
|
if ((pItem->Status & FP_STATUS_SPL_WRITE_CLOSED) && pItem->SplWriteHandle != INVALID_HANDLE_VALUE)
|
|
{
|
|
__try
|
|
{
|
|
CloseHandle(pItem->SplWriteHandle);
|
|
pItem->SplWriteHandle = INVALID_HANDLE_VALUE;
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DBGMSG(DBG_WARN, ("Hit an Exception Closing SplWriteHandle in CloseFilesCheck\n"));
|
|
pItem->SplWriteHandle = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case kCloseReadHandle:
|
|
|
|
if ((pItem->Status & FP_STATUS_SPL_READ_CLOSED) && pItem->SplReadHandle != INVALID_HANDLE_VALUE)
|
|
{
|
|
__try
|
|
{
|
|
CloseHandle(pItem->SplReadHandle);
|
|
pItem->SplReadHandle = INVALID_HANDLE_VALUE;
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DBGMSG(DBG_WARN, ("Hit an Exception Closing SplReadHandle in CloseFilesCheck\n"));
|
|
pItem->SplReadHandle = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case kCloseShdHandle:
|
|
if ((pItem->Status & FP_STATUS_SHD_CLOSED) && pItem->ShdWriteHandle != INVALID_HANDLE_VALUE)
|
|
{
|
|
__try
|
|
{
|
|
CloseHandle(pItem->ShdWriteHandle);
|
|
pItem->ShdWriteHandle = INVALID_HANDLE_VALUE;
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DBGMSG(DBG_WARN, ("Hit an Exception Closing ShdWriteHandle in CloseFilesCheck\n"));
|
|
pItem->ShdWriteHandle = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*********************
|
|
* SetFileItemState
|
|
*
|
|
* Takes a FilePool Object and frees it, optionally deleting the files associated with it.
|
|
*
|
|
* Arguments:
|
|
* hFileItem - The file item whose state we are going to change.
|
|
* eState - The new state of the file item
|
|
*
|
|
* Returns Error if it is passed in an invalid argument, or S_OK if it succeeds.
|
|
*
|
|
*/
|
|
HRESULT
|
|
SetFileItemState(
|
|
IN HANDLE hFileItem,
|
|
IN EFileItemState eState
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = hFileItem ? S_OK : HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = FPSetFileItemState(reinterpret_cast<FileListItem *>(hFileItem), eState);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*********************
|
|
* DestroyFilePool()
|
|
*
|
|
* Takes a FilePool Object and frees it, optionally deleting the files associated with it.
|
|
*
|
|
* Arguments:
|
|
* IN OUT FilePoolHandle : Pointer to existing Filepool.
|
|
* IN DeleteFiles : BOOL - TRUE: Delete the Pool files.
|
|
*
|
|
* Returns Error if it is passed in an invalid argument, or S_OK if it succeeds.
|
|
*
|
|
*/
|
|
|
|
HRESULT
|
|
DestroyFilePool(
|
|
HANDLE* FilePoolHandle,
|
|
BOOL DeleteFiles
|
|
)
|
|
{
|
|
HRESULT RetVal = S_OK;
|
|
class FilePool * FP = NULL;
|
|
|
|
if (FilePoolHandle && *FilePoolHandle)
|
|
{
|
|
FP = (class FilePool *)FilePoolHandle;
|
|
|
|
FP->DeleteEmptyFilesOnClose = DeleteFiles;
|
|
|
|
delete FP;
|
|
}
|
|
else
|
|
{
|
|
RetVal = E_INVALIDARG;
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
|
|
/*********************
|
|
* TrimPool()
|
|
*
|
|
* Takes a FilePool Object and trim the free list, deleting old files.
|
|
*
|
|
* Arguments:
|
|
* IN FilePool : Handle of a FilePool Object Created with CreateFilePool()
|
|
*
|
|
* Returns TRUE if there are files still in the free list, or FALSE if no files left.
|
|
*/
|
|
|
|
BOOL
|
|
TrimPool(
|
|
HANDLE FilePoolHandle
|
|
)
|
|
{
|
|
class FilePool * FP = NULL;
|
|
BOOL Retval = FALSE;
|
|
|
|
if (FilePoolHandle)
|
|
{
|
|
FP = (class FilePool *)FilePoolHandle;
|
|
|
|
Retval = FP->TrimPool();
|
|
}
|
|
|
|
return Retval;
|
|
}
|
|
|
|
|
|
/*********************
|
|
* ChangeFilePoolBasePath()
|
|
*
|
|
* Takes a FilePool Object and changes the base path in it. This will be called
|
|
* when the spool directory is changed.
|
|
*
|
|
* Arguments:
|
|
* IN FilePool : Handle of a FilePool Object Created with CreateFilePool
|
|
* IN BasePath : New base path to use
|
|
*
|
|
* Returns an HRESULT
|
|
*/
|
|
HRESULT
|
|
ChangeFilePoolBasePath(
|
|
IN HANDLE *FilePoolHandle,
|
|
IN LPCTSTR BasePath
|
|
)
|
|
{
|
|
FilePool *FP = (FilePool *)FilePoolHandle;
|
|
HRESULT RetVal = E_INVALIDARG;
|
|
LPTSTR FileBase = NULL;
|
|
|
|
if (FP)
|
|
{
|
|
if (FileBase = AllocSplStr(BasePath))
|
|
{
|
|
FP->EnterCritSec();
|
|
|
|
FreeSplStr(FP->FileBase);
|
|
FP->FileBase = FileBase;
|
|
FP->LeaveCritSec();
|
|
|
|
RetVal = S_OK;
|
|
}
|
|
else
|
|
{
|
|
RetVal = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
|
|
/*--
|
|
Generic Utility Functions
|
|
|
|
ConvertFileExt
|
|
|
|
--*/
|
|
|
|
/*********************
|
|
* ConvertFileExt()
|
|
*
|
|
* Utility function to change one extension to another.
|
|
* Requires the extension to only be in the filename once.
|
|
* The extensions being converted must be the same size.
|
|
*
|
|
* Arguments:
|
|
* IN OUT FileName : String of Filename to be changed.
|
|
* IN ExtFrom : Extension to change.
|
|
* IN ExtTo : Extension to change it to.
|
|
*
|
|
*/
|
|
|
|
HRESULT
|
|
ConvertFileExt(
|
|
PWSTR Filename,
|
|
PCWSTR ExtFrom,
|
|
PCWSTR ExtTo
|
|
)
|
|
{
|
|
HRESULT RetVal = E_FAIL;
|
|
PWSTR Temp = NULL;
|
|
DWORD cchExtTo = 0;
|
|
|
|
if (Filename && ExtFrom && ExtTo && (wcslen(ExtFrom) == (cchExtTo = wcslen(ExtTo))) && ExtFrom[0])
|
|
{
|
|
Temp = wcsstr(Filename, ExtFrom);
|
|
|
|
if (Temp)
|
|
{
|
|
//
|
|
// This should work in all our cases.
|
|
//
|
|
CopyMemory(Temp, ExtTo, cchExtTo * sizeof(WCHAR));
|
|
RetVal = S_OK;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RetVal = E_INVALIDARG;
|
|
}
|
|
return RetVal;
|
|
}
|
|
|
|
/*--
|
|
FileItem Management Functions
|
|
|
|
TruncateFiles
|
|
|
|
--*/
|
|
|
|
/*********************
|
|
* TruncateFiles()
|
|
*
|
|
* Takes a File Item and truncates any open files to 0 length.
|
|
*
|
|
* Arguments:
|
|
* IN FileListItem : Item containing the files to truncate.
|
|
*
|
|
*
|
|
*/
|
|
VOID
|
|
TruncateFiles(
|
|
struct FileListItem * Item
|
|
)
|
|
{
|
|
BOOL Trunced = FALSE;
|
|
if (Item)
|
|
{
|
|
Item->EnterCritSec();
|
|
|
|
//
|
|
// Reinitialize cache data.
|
|
//
|
|
Item->CreateInfo = 0;
|
|
|
|
//
|
|
// Truncate the Shadow File
|
|
//
|
|
if (Item->ShdWriteHandle != INVALID_HANDLE_VALUE)
|
|
{
|
|
if (SetFilePointer(Item->ShdWriteHandle, 0, NULL, FILE_BEGIN) !=
|
|
INVALID_SET_FILE_POINTER)
|
|
{
|
|
if (!SetEndOfFile(Item->ShdWriteHandle))
|
|
{
|
|
DBGMSG(DBG_WARN, ("FAILED to set SPL end of file to 0 %d.\n", GetLastError()));
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Truncate the Spool File. If the writehandle is closed, use the readhandle.
|
|
//
|
|
if (Item->SplWriteHandle != INVALID_HANDLE_VALUE)
|
|
{
|
|
if (SetFilePointer(Item->SplWriteHandle, 0, NULL, FILE_BEGIN) !=
|
|
INVALID_SET_FILE_POINTER)
|
|
{
|
|
if (!SetEndOfFile(Item->SplWriteHandle))
|
|
{
|
|
DBGMSG(DBG_WARN, ("FAILED to set SPL end of file to 0 %d.\n", GetLastError()));
|
|
}
|
|
}
|
|
}
|
|
else if (Item->SplReadHandle != INVALID_HANDLE_VALUE)
|
|
{
|
|
if (SetFilePointer(Item->SplReadHandle, 0, NULL, FILE_BEGIN) !=
|
|
INVALID_SET_FILE_POINTER)
|
|
{
|
|
if (!SetEndOfFile(Item->SplReadHandle))
|
|
{
|
|
DBGMSG(DBG_WARN, ("FAILED to set SPL end of file to 0 %d.\n", GetLastError()));
|
|
}
|
|
}
|
|
// There is only one open spool handle at this point so make that
|
|
// open handle the writer. This is what the spooler needs when it
|
|
// first requests a new pool item. This also saves file I/O if the
|
|
// next use of this item doesn't need both writer and reader at the
|
|
// same time.
|
|
Item->SplWriteHandle = Item->SplReadHandle;
|
|
Item->SplReadHandle = INVALID_HANDLE_VALUE;
|
|
|
|
Trunced = TRUE;
|
|
}
|
|
|
|
if ((Item->SplReadHandle != INVALID_HANDLE_VALUE) && !Trunced)
|
|
{
|
|
//CloseHandle(Item->SplReadHandle);
|
|
SetFilePointer(Item->SplReadHandle, 0, NULL, FILE_BEGIN);
|
|
}
|
|
|
|
Item->LeaveCritSec();
|
|
}
|
|
}
|
|
|
|
|
|
/*********************
|
|
* FPCloseFiles()
|
|
*
|
|
* Takes a FileList item and closes the files associated with it, if they
|
|
* are not in use. Else it just marks them as closed and it is the job of the
|
|
* reader or writer to close the handles when it is done with them.
|
|
*
|
|
* Arguments:
|
|
* IN FileListItem : FileItem with files to close.
|
|
* IN CloseShad : BOOL - TRUE: Close the Shadow File too.
|
|
*
|
|
*
|
|
*/
|
|
VOID
|
|
FPCloseFiles(
|
|
struct FileListItem * pItem,
|
|
BOOL CloseShad
|
|
)
|
|
{
|
|
if (pItem)
|
|
{
|
|
pItem->EnterCritSec();
|
|
|
|
if (pItem->SplWriteHandle != INVALID_HANDLE_VALUE)
|
|
{
|
|
if (pItem->Status & FP_STATUS_SPL_WRITING)
|
|
{
|
|
pItem->Status |= FP_STATUS_SPL_WRITE_CLOSED;
|
|
}
|
|
else
|
|
{
|
|
__try
|
|
{
|
|
CloseHandle(pItem->SplWriteHandle);
|
|
pItem->SplWriteHandle = INVALID_HANDLE_VALUE;
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DBGMSG(DBG_WARN, ("Hit an Exception Closing SplWriteHandle in FPCloseFiles\n"));
|
|
pItem->SplWriteHandle = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pItem->SplReadHandle != INVALID_HANDLE_VALUE)
|
|
{
|
|
if (pItem->Status & FP_STATUS_SPL_READING)
|
|
{
|
|
pItem->Status |= FP_STATUS_SPL_READ_CLOSED;
|
|
}
|
|
else
|
|
{
|
|
__try
|
|
{
|
|
CloseHandle(pItem->SplReadHandle);
|
|
pItem->SplReadHandle = INVALID_HANDLE_VALUE;
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DBGMSG(DBG_WARN, ("Hit an Exception Closing SplReadHandle in FPCloseFiles\n"));
|
|
pItem->SplReadHandle = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( CloseShad && pItem->ShdWriteHandle != INVALID_HANDLE_VALUE)
|
|
{
|
|
if (pItem->Status & FP_STATUS_SPL_WRITING)
|
|
{
|
|
pItem->Status |= FP_STATUS_SPL_WRITE_CLOSED;
|
|
}
|
|
else
|
|
{
|
|
__try
|
|
{
|
|
CloseHandle(pItem->ShdWriteHandle);
|
|
pItem->ShdWriteHandle = INVALID_HANDLE_VALUE;
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DBGMSG(DBG_WARN, ("Hit an Exception Closing ShdWriteHandle in FPCloseFiles\n"));
|
|
pItem->ShdWriteHandle = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
pItem->LeaveCritSec();
|
|
}
|
|
}
|
|
|
|
/*********************
|
|
* FPSetFileItemState
|
|
*
|
|
* Changes the state of a file pool item. Currently, it can just be marked not
|
|
* to recycle the file pool object.
|
|
*
|
|
* Arguments:
|
|
* pItem : The file list item.
|
|
* eFileItemState : New state for the file item.
|
|
*
|
|
*/
|
|
HRESULT
|
|
FPSetFileItemState(
|
|
IN FileListItem *pItem,
|
|
IN EFileItemState eFileItemState
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
pItem->EnterCritSec();
|
|
|
|
switch(eFileItemState)
|
|
{
|
|
case kDontRecycle:
|
|
|
|
pItem->Status |= FP_STATUS_ITEM_DONT_RECYCLE;
|
|
break;
|
|
|
|
default:
|
|
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_LEVEL);
|
|
break;
|
|
}
|
|
|
|
|
|
pItem->LeaveCritSec();
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*********************
|
|
* DeletePoolFile()
|
|
*
|
|
* Takes a FilePool Object and trim the free list, deleting old files and freeing memory.
|
|
*
|
|
* Arguments:
|
|
* IN OUT FileListItem : FileItem to delete the files from and free up.
|
|
*
|
|
* Closes the files, deletes them, frees the memory, and sets the pItem to NULL
|
|
*
|
|
*/
|
|
VOID
|
|
DeletePoolFile(struct FileListItem ** ppItem)
|
|
{
|
|
struct FileListItem * pItem;
|
|
|
|
if (ppItem && *ppItem)
|
|
{
|
|
pItem = *ppItem;
|
|
FPCloseFiles(pItem, TRUE);
|
|
|
|
DeleteCriticalSection(&pItem->CritSec);
|
|
|
|
if (pItem->SplFilename)
|
|
{
|
|
DeleteFile(pItem->SplFilename);
|
|
FreeSplMem(pItem->SplFilename);
|
|
}
|
|
|
|
if (pItem->ShdFilename)
|
|
{
|
|
DeleteFile(pItem->ShdFilename);
|
|
FreeSplMem(pItem->ShdFilename);
|
|
}
|
|
|
|
FreeSplMem(pItem);
|
|
}
|
|
|
|
|
|
*ppItem = NULL;
|
|
}
|
|
|
|
/*--
|
|
|
|
List Management Functions
|
|
|
|
RemoveFromFPList
|
|
AddToFPListEnd
|
|
AddToFPListHead
|
|
|
|
--*/
|
|
|
|
|
|
|
|
HRESULT
|
|
RemoveFromFPList(
|
|
struct FileListItem * Item,
|
|
struct FileListItem ** Head,
|
|
struct FileListItem ** Tail
|
|
)
|
|
{
|
|
struct FileListItem * Check = NULL;
|
|
HRESULT RetVal = E_FAIL;
|
|
|
|
//
|
|
// Validate we have valid args.
|
|
//
|
|
if ( Item && Head && *Head && Tail && *Tail )
|
|
{
|
|
|
|
for ( Check = *Head; Check && (Item != Check); Check = Check->FLNext );
|
|
|
|
if ( Check )
|
|
{
|
|
if ( *Head == Check )
|
|
{
|
|
*Head = Check->FLNext;
|
|
}
|
|
else
|
|
{
|
|
Check->FLPrev->FLNext = Check->FLNext;
|
|
|
|
}
|
|
|
|
if ( *Tail == Check )
|
|
{
|
|
*Tail = Check->FLPrev;
|
|
}
|
|
else
|
|
{
|
|
Check->FLNext->FLPrev = Check->FLPrev;
|
|
}
|
|
|
|
Check->FLNext = NULL;
|
|
Check->FLPrev = NULL;
|
|
|
|
RetVal = S_OK;
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// you gave me a pointer to an item not in the list.
|
|
//
|
|
RetVal = E_POINTER;
|
|
}
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
RetVal = E_INVALIDARG;
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
HRESULT
|
|
AddToFPListEnd(
|
|
struct FileListItem * Item,
|
|
struct FileListItem ** Head,
|
|
struct FileListItem ** Tail
|
|
)
|
|
{
|
|
struct FileListItem * Check = NULL;
|
|
HRESULT RetVal = E_FAIL;
|
|
|
|
//
|
|
// Validate we have valid args.
|
|
//
|
|
if ( Item && Head && Tail )
|
|
{
|
|
|
|
if ( *Tail )
|
|
{
|
|
//
|
|
// There are items in the list, add something
|
|
// onto the end.
|
|
//
|
|
Check = *Tail;
|
|
|
|
Check->FLNext = Item;
|
|
Item->FLPrev = Check;
|
|
Item->FLNext = NULL;
|
|
|
|
*Tail = Item;
|
|
RetVal = S_OK;
|
|
}
|
|
else
|
|
{
|
|
if ( *Head )
|
|
{
|
|
//
|
|
// If we have a head and no tail, something
|
|
// is seriously wrong.
|
|
//
|
|
RetVal = E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Adding the first item into a list.
|
|
//
|
|
|
|
Item->FLNext = NULL;
|
|
Item->FLPrev = NULL;
|
|
|
|
*Head = Item;
|
|
*Tail = Item;
|
|
RetVal = S_OK;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RetVal = E_INVALIDARG;
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
AddToFPListHead(
|
|
struct FileListItem * Item,
|
|
struct FileListItem ** Head,
|
|
struct FileListItem ** Tail
|
|
)
|
|
{
|
|
HRESULT RetVal = S_OK;
|
|
|
|
if ( Item && Head && Tail )
|
|
{
|
|
if ( *Head )
|
|
{
|
|
Item->FLNext = *Head;
|
|
(*Head)->FLPrev = Item;
|
|
}
|
|
else
|
|
{
|
|
*Tail = Item;
|
|
}
|
|
*Head = Item;
|
|
Item->FLPrev = NULL;
|
|
}
|
|
else
|
|
{
|
|
RetVal = E_INVALIDARG;
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
VOID
|
|
FreeFPList(
|
|
struct FileListItem ** Head,
|
|
BOOL DeleteFiles
|
|
)
|
|
{
|
|
struct FileListItem * Item = NULL;
|
|
struct FileListItem * Next = NULL;
|
|
|
|
if (Head && *Head)
|
|
{
|
|
Item = *Head;
|
|
while (Item)
|
|
{
|
|
Next = Item->FLNext;
|
|
Item->FLNext = NULL;
|
|
Item->FLPrev = NULL;
|
|
|
|
if (Item->SplFilename && DeleteFiles)
|
|
{
|
|
DeletePoolFile(&Item);
|
|
Item = Next;
|
|
}
|
|
else
|
|
{
|
|
FPCloseFiles(Item, TRUE);
|
|
DeleteCriticalSection(&Item->CritSec);
|
|
|
|
if (Item->SplFilename)
|
|
{
|
|
FreeSplMem(Item->SplFilename);
|
|
}
|
|
if (Item->ShdFilename)
|
|
{
|
|
FreeSplMem(Item->ShdFilename);
|
|
}
|
|
FreeSplMem(Item);
|
|
Item = Next;
|
|
}
|
|
}
|
|
*Head = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/*--
|
|
|
|
FilePool Class Functions:
|
|
|
|
InitFilePoolVars
|
|
FilePool
|
|
~FilePool
|
|
EnterCritSec
|
|
LeaveCritSec
|
|
GetNextFileName
|
|
CreatePoolFile
|
|
GetWriteFileStruct
|
|
ReleasePoolHandle
|
|
DeletePoolFile
|
|
operator delete
|
|
|
|
--*/
|
|
|
|
|
|
|
|
|
|
|
|
/*********************
|
|
* Filepool::FilePool()
|
|
*
|
|
* See CreateFilePool() Above.
|
|
*/
|
|
|
|
FilePool::FilePool(
|
|
DWORD PTimeout,
|
|
DWORD MaxFreeFiles
|
|
) : FreeFiles(NULL), EndFreeFiles(NULL), FileInUse(NULL), EndUsedFiles(NULL),
|
|
CurrentNum(0), PoolTimeout(PTimeout), MaxFiles(MaxFreeFiles), FreeSize(0), UsedSize(0),
|
|
DeleteEmptyFilesOnClose(FALSE)
|
|
{
|
|
SplModes.Mode = GENERIC_READ | GENERIC_WRITE;
|
|
SplModes.Flags = FILE_ATTRIBUTE_NORMAL;
|
|
SplModes.ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
|
SplModes.Disp = 0;
|
|
|
|
ShdModes.Mode = GENERIC_WRITE;
|
|
ShdModes.Flags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN;
|
|
ShdModes.ShareMode = 0;
|
|
ShdModes.Disp = 0;
|
|
}
|
|
|
|
|
|
/*********************
|
|
* Filepool::AllocInit()
|
|
*
|
|
* See CreateFilePool() Above.
|
|
*/
|
|
|
|
HRESULT
|
|
FilePool::AllocInit(
|
|
LPCTSTR BasePath,
|
|
LPCTSTR PreNumStr,
|
|
LPCTSTR SplExt,
|
|
LPCTSTR ShdExt
|
|
)
|
|
{
|
|
HRESULT RetVal = S_OK;
|
|
|
|
__try
|
|
{
|
|
InitializeCriticalSection(&FilePoolCritSec);
|
|
}
|
|
__except( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DBGMSG(DBG_WARN, ("FilePool: Failed to Initialise Critical Section.\n"));
|
|
RetVal = E_FAIL;
|
|
}
|
|
|
|
|
|
if ((RetVal == S_OK) &&
|
|
(FileBase = AllocSplStr(BasePath)) &&
|
|
(FilePreNumStr = AllocSplStr(PreNumStr)) &&
|
|
(SplFileExt = AllocSplStr(SplExt)) &&
|
|
(ShdFileExt = AllocSplStr(ShdExt))
|
|
)
|
|
{
|
|
//
|
|
// We have all of our strings allocated.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
FreeSplStr(FileBase);
|
|
FreeSplStr(FilePreNumStr);
|
|
FreeSplStr(SplFileExt);
|
|
FreeSplStr(ShdFileExt);
|
|
RetVal = E_FAIL;
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
|
|
/*********************
|
|
* Filepool::FilePool()
|
|
*
|
|
* See CreateFilePool() Above.
|
|
*/
|
|
|
|
FilePool::~FilePool(
|
|
)
|
|
{
|
|
if (FileBase)
|
|
{
|
|
FreeSplMem(FileBase);
|
|
}
|
|
|
|
if (FilePreNumStr)
|
|
{
|
|
FreeSplMem(FilePreNumStr);
|
|
}
|
|
|
|
if (SplFileExt)
|
|
{
|
|
FreeSplMem(SplFileExt);
|
|
}
|
|
|
|
if (ShdFileExt)
|
|
{
|
|
FreeSplMem(ShdFileExt);
|
|
}
|
|
|
|
//
|
|
// Free The lists here.
|
|
//
|
|
FreeFPList(&FileInUse, FALSE);
|
|
FreeFPList(&FreeFiles, DeleteEmptyFilesOnClose);
|
|
EndUsedFiles = NULL;
|
|
EndFreeFiles = NULL;
|
|
|
|
DeleteCriticalSection(&FilePoolCritSec);
|
|
}
|
|
|
|
VOID
|
|
FilePool::EnterCritSec()
|
|
{
|
|
EnterCriticalSection(&FilePoolCritSec);
|
|
}
|
|
|
|
VOID
|
|
FilePool::LeaveCritSec()
|
|
{
|
|
LeaveCriticalSection(&FilePoolCritSec);
|
|
}
|
|
|
|
|
|
VOID
|
|
FileListItem::EnterCritSec()
|
|
{
|
|
EnterCriticalSection(&CritSec);
|
|
}
|
|
|
|
VOID
|
|
FileListItem::LeaveCritSec()
|
|
{
|
|
LeaveCriticalSection(&CritSec);
|
|
}
|
|
|
|
/*********************
|
|
* FilePool::GetNextFileName()
|
|
*
|
|
* Returns the next open Spool file name. Allocates memory.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Return:
|
|
* A valid spool file name, or NULL.
|
|
*
|
|
*/
|
|
|
|
LPWSTR
|
|
FilePool::GetNextFileName(VOID)
|
|
{
|
|
|
|
DWORD SizeToAlloc = 0;
|
|
PWSTR FName = NULL;
|
|
|
|
SizeToAlloc =
|
|
wcslen(FileBase) + 1 +
|
|
wcslen(FilePreNumStr) + 5 +
|
|
wcslen(SplFileExt) + 1;
|
|
|
|
FName = (PWSTR)AllocSplMem(SizeToAlloc * sizeof(WCHAR));
|
|
|
|
if (FName)
|
|
{
|
|
DWORD NextNum;
|
|
|
|
EnterCritSec();
|
|
NextNum = CurrentNum;
|
|
|
|
CurrentNum++;
|
|
|
|
if (CurrentNum > 99999)
|
|
{
|
|
CurrentNum = 0;
|
|
}
|
|
|
|
LeaveCritSec();
|
|
|
|
StringCchPrintf(FName,
|
|
SizeToAlloc,
|
|
L"%ws\\%ws%05d%ws",
|
|
FileBase,
|
|
FilePreNumStr,
|
|
NextNum,
|
|
SplFileExt);
|
|
}
|
|
|
|
return FName;
|
|
}
|
|
|
|
/*********************
|
|
* FilePool::GetNextFileNameNoAlloc()
|
|
*
|
|
* Returns the next open Spool file name. Uses a buffer.
|
|
* It is only used after a call to GetNextFileName.
|
|
*
|
|
* Arguments:
|
|
* IN OUT Filename : Buffer to copy the name into.
|
|
* IN cchFileName : Size of the buffer to copy into.
|
|
*
|
|
* Return:
|
|
* None.
|
|
*
|
|
*/
|
|
|
|
HRESULT
|
|
FilePool::GetNextFileNameNoAlloc(
|
|
IN OUT PWSTR Filename,
|
|
IN SIZE_T cchFileName
|
|
)
|
|
{
|
|
DWORD NextNum;
|
|
|
|
EnterCritSec();
|
|
NextNum = CurrentNum;
|
|
|
|
CurrentNum++;
|
|
|
|
if (CurrentNum > 99999)
|
|
{
|
|
CurrentNum = 0;
|
|
}
|
|
|
|
LeaveCritSec();
|
|
|
|
return StringCchPrintf(Filename,
|
|
cchFileName,
|
|
L"%ws\\%ws%05d%ws",
|
|
FileBase,
|
|
FilePreNumStr,
|
|
NextNum,
|
|
SplFileExt);
|
|
|
|
}
|
|
|
|
/*********************
|
|
* Filepool::CreatePoolFile()
|
|
*
|
|
* Takes a pointer to a Filepool item and returns a new one. Can use a filename
|
|
* passed in.
|
|
*
|
|
* Parameters:
|
|
* OUT Item : Pointer to a File Item.
|
|
* IN Filename : Optional Filename. Can be NULL.
|
|
*
|
|
* Returns S_OK if successful.
|
|
*/
|
|
|
|
|
|
HRESULT
|
|
FilePool::CreatePoolFile(
|
|
struct FileListItem ** Item,
|
|
PWSTR Filename
|
|
)
|
|
{
|
|
HRESULT RetVal = E_FAIL;
|
|
struct FileListItem * Temp = NULL;
|
|
DWORD OldNum = 0;
|
|
BOOL CritInitialized = FALSE;
|
|
|
|
if ( Item )
|
|
{
|
|
Temp = (struct FileListItem *)AllocSplMem(sizeof(struct FileListItem));
|
|
|
|
if ( Temp )
|
|
{
|
|
Temp->FLNext = NULL;
|
|
Temp->FLPrev = NULL;
|
|
OldNum = CurrentNum;
|
|
Temp->TimeStamp = 0;
|
|
Temp->FP = this;
|
|
Temp->CreateInfo = 0;
|
|
|
|
__try
|
|
{
|
|
InitializeCriticalSection(&Temp->CritSec);
|
|
CritInitialized = TRUE;
|
|
}
|
|
__except( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DBGMSG(DBG_WARN, ("FilePool: Failed to Initialise FL Critical Section.\n"));
|
|
RetVal = E_FAIL;
|
|
}
|
|
if (CritInitialized)
|
|
{
|
|
|
|
if ( Filename )
|
|
{
|
|
Temp->SplFilename = AllocSplStr(Filename);
|
|
Temp->ShdFilename = AllocSplStr(Filename);
|
|
|
|
if (Temp->SplFilename && Temp->ShdFilename)
|
|
{
|
|
*Item = Temp;
|
|
ConvertFileExt(Temp->ShdFilename, SplFileExt, ShdFileExt);
|
|
Temp->SplReadHandle = INVALID_HANDLE_VALUE;
|
|
Temp->SplWriteHandle = INVALID_HANDLE_VALUE;
|
|
Temp->ShdWriteHandle = INVALID_HANDLE_VALUE;
|
|
RetVal = S_OK;
|
|
}
|
|
else
|
|
{
|
|
RetVal = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Temp->SplFilename = GetNextFileName();
|
|
|
|
if (Temp->SplFilename)
|
|
{
|
|
RetVal = S_OK;
|
|
while (FileExists(Temp->SplFilename))
|
|
{
|
|
//
|
|
// Fundamental assumption here is the number of
|
|
// characters occupied by the filename does not
|
|
// change.
|
|
//
|
|
GetNextFileNameNoAlloc(Temp->SplFilename, wcslen(Temp->SplFilename) + 1);
|
|
if (OldNum == CurrentNum)
|
|
{
|
|
//
|
|
// We went right around.
|
|
//
|
|
RetVal = E_FAIL;
|
|
break;
|
|
}
|
|
}
|
|
if (SUCCEEDED(RetVal))
|
|
{
|
|
Temp->ShdFilename = AllocSplStr(Temp->SplFilename);
|
|
if (Temp->ShdFilename)
|
|
{
|
|
ConvertFileExt(Temp->ShdFilename, SplFileExt, ShdFileExt);
|
|
Temp->SplReadHandle = INVALID_HANDLE_VALUE;
|
|
Temp->SplWriteHandle = INVALID_HANDLE_VALUE;
|
|
Temp->ShdWriteHandle = INVALID_HANDLE_VALUE;
|
|
*Item = Temp;
|
|
RetVal = S_OK;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RetVal = E_INVALIDARG;
|
|
|
|
}
|
|
|
|
if (FAILED(RetVal))
|
|
{
|
|
if (Temp)
|
|
{
|
|
if (CritInitialized)
|
|
{
|
|
DeleteCriticalSection(&Temp->CritSec);
|
|
}
|
|
|
|
if (Temp->SplFilename)
|
|
{
|
|
FreeSplMem(Temp->SplFilename);
|
|
}
|
|
|
|
if (Temp->ShdFilename)
|
|
{
|
|
FreeSplMem(Temp->ShdFilename);
|
|
}
|
|
|
|
FreeSplMem(Temp);
|
|
}
|
|
}
|
|
return RetVal;
|
|
}
|
|
|
|
|
|
/*********************
|
|
* Filepool::GetWriteFileStruct()
|
|
*
|
|
* See GetFileItemHandle() Above.
|
|
*/
|
|
|
|
HRESULT
|
|
FilePool::GetWriteFileStruct(
|
|
struct FileListItem ** File,
|
|
PWSTR Filename
|
|
)
|
|
{
|
|
struct FileListItem * Temp = NULL;
|
|
HRESULT RetVal = S_OK;
|
|
HRESULT OurRetVal = S_OK;
|
|
|
|
EnterCritSec();
|
|
|
|
if ( FreeFiles && !Filename)
|
|
{
|
|
Temp = FreeFiles;
|
|
|
|
RetVal = RemoveFromFPList( Temp, &FreeFiles, &EndFreeFiles );
|
|
|
|
if (SUCCEEDED(RetVal))
|
|
{
|
|
FreeSize--;
|
|
|
|
RetVal = AddToFPListEnd( Temp, &FileInUse, &EndUsedFiles);
|
|
|
|
if (FAILED(RetVal))
|
|
{
|
|
//
|
|
// Bad things
|
|
//
|
|
DBGMSG(DBG_WARN, ("Could not add to List End %x\n", RetVal));
|
|
OurRetVal = E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
UsedSize++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Find out what went wrong.
|
|
//
|
|
DBGMSG(DBG_WARN, ("Could not remove Item %x\n", RetVal));
|
|
Temp = NULL;
|
|
OurRetVal = E_FAIL;
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LeaveCritSec();
|
|
|
|
RetVal = CreatePoolFile(&Temp, Filename);
|
|
|
|
if ( FAILED(RetVal) )
|
|
{
|
|
//
|
|
// Bad Things
|
|
//
|
|
DBGMSG(DBG_WARN, ("Could not create Item %x\n", RetVal));
|
|
OurRetVal = E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
EnterCritSec();
|
|
RetVal = AddToFPListEnd(Temp, &FileInUse, &EndUsedFiles);
|
|
|
|
if ( FAILED(RetVal) )
|
|
{
|
|
//
|
|
// Bad Things
|
|
//
|
|
DBGMSG(DBG_WARN, ("Could not add to List End after create %x\n", RetVal));
|
|
OurRetVal = E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
UsedSize++;
|
|
}
|
|
LeaveCritSec();
|
|
}
|
|
EnterCritSec();
|
|
}
|
|
|
|
LeaveCritSec();
|
|
|
|
if ( FAILED(OurRetVal) )
|
|
{
|
|
//
|
|
// Clean up.
|
|
//
|
|
|
|
if ( Temp )
|
|
{
|
|
//
|
|
// We weren't able to add the file to the structure,
|
|
// This should never happen, but if it does, clean up
|
|
// the memory we use.
|
|
//
|
|
DeletePoolFile(&Temp);
|
|
|
|
}
|
|
|
|
*File = NULL;
|
|
}
|
|
else
|
|
{
|
|
*File = Temp;
|
|
}
|
|
|
|
return OurRetVal;
|
|
}
|
|
|
|
/*********************
|
|
* Filepool::ReleasePoolHandle()
|
|
*
|
|
* See ReleasePoolHandle() Above.
|
|
*/
|
|
|
|
HRESULT
|
|
FilePool::ReleasePoolHandle(
|
|
struct FileListItem * File
|
|
)
|
|
{
|
|
BOOL bDeletePoolFile = FALSE;
|
|
HRESULT RetVal = S_OK;
|
|
HRESULT RemRetVal = S_OK;
|
|
|
|
if ((File->Status & FP_STATUS_SPL_READING) ||
|
|
(File->Status & FP_STATUS_SPL_WRITING) ||
|
|
(File->Status & FP_STATUS_SHD_WRITING))
|
|
{
|
|
RetVal = E_FAIL;
|
|
|
|
//
|
|
// This is a pathological case as we will subsequently leak this handle.
|
|
// Break.
|
|
//
|
|
DBGMSG(DBG_ERROR, ("Tried to release a file with handles in use\n"));
|
|
}
|
|
else
|
|
{
|
|
EnterCritSec();
|
|
RemRetVal = RemoveFromFPList(File, &FileInUse, &EndUsedFiles);
|
|
|
|
if (SUCCEEDED(RemRetVal))
|
|
{
|
|
UsedSize--;
|
|
|
|
//
|
|
// If the spool directory has changed we need to delete the pool file
|
|
//
|
|
if ( _wcsnicmp(FileBase, File->SplFilename, wcslen(FileBase)) )
|
|
{
|
|
bDeletePoolFile = TRUE;
|
|
}
|
|
}
|
|
LeaveCritSec();
|
|
|
|
if (SUCCEEDED(RemRetVal))
|
|
{
|
|
if (bDeletePoolFile == TRUE ||
|
|
FreeSize >= MaxFiles ||
|
|
File->Status & FP_STATUS_ITEM_DONT_RECYCLE ||
|
|
((File->SplWriteHandle == INVALID_HANDLE_VALUE) &&
|
|
(File->SplReadHandle == INVALID_HANDLE_VALUE)))
|
|
{
|
|
DeletePoolFile(&File);
|
|
}
|
|
else
|
|
{
|
|
File->TimeStamp = GetTickCount();
|
|
|
|
TruncateFiles(File);
|
|
|
|
EnterCritSec();
|
|
RetVal = AddToFPListEnd(File, &FreeFiles, &EndFreeFiles);
|
|
|
|
if (SUCCEEDED(RetVal))
|
|
{
|
|
FreeSize++;
|
|
}
|
|
LeaveCritSec();
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RetVal = E_INVALIDARG;
|
|
}
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
/*********************
|
|
* Filepool::CreateSplReader()
|
|
*
|
|
*Used in GetReaderFromHandle.
|
|
*/
|
|
|
|
HRESULT
|
|
FilePool::CreateSplReader(
|
|
struct FileListItem * Item
|
|
)
|
|
{
|
|
HRESULT RetVal = S_OK;
|
|
HANDLE Temp = INVALID_HANDLE_VALUE;
|
|
|
|
|
|
Temp = CreateFile( Item->SplFilename,
|
|
SplModes.Mode,
|
|
SplModes.ShareMode,
|
|
NULL,
|
|
OPEN_EXISTING | SplModes.Disp,
|
|
SplModes.Flags,
|
|
NULL);
|
|
|
|
if (Temp && (Temp != INVALID_HANDLE_VALUE))
|
|
{
|
|
Item->SplReadHandle = Temp;
|
|
Item->CreateInfo |= FP_SPL_READER_CREATED;
|
|
}
|
|
else
|
|
{
|
|
RetVal = E_FAIL;
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
|
|
/*********************
|
|
* Filepool::CreateSplWriter()
|
|
*
|
|
* Does the CreateFile for the Spool File. Used for GetWriterFromHandle().
|
|
*/
|
|
|
|
HRESULT
|
|
FilePool::CreateSplWriter(
|
|
struct FileListItem * Item
|
|
)
|
|
{
|
|
HRESULT RetVal = S_OK;
|
|
HANDLE Temp = INVALID_HANDLE_VALUE;
|
|
|
|
Temp = CreateFile( Item->SplFilename,
|
|
SplModes.Mode,
|
|
SplModes.ShareMode,
|
|
NULL,
|
|
CREATE_ALWAYS | SplModes.Disp,
|
|
SplModes.Flags,
|
|
NULL);
|
|
|
|
if (Temp && (Temp != INVALID_HANDLE_VALUE))
|
|
{
|
|
Item->SplWriteHandle = Temp;
|
|
Item->CreateInfo |= FP_SPL_WRITER_CREATED;
|
|
}
|
|
else
|
|
{
|
|
RetVal = E_FAIL;
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
/*********************
|
|
* Filepool::CreateShdWriter()
|
|
*
|
|
* Does the CreateFile for the ShadowFile. Used for GetWriterFromHandle().
|
|
*/
|
|
|
|
HRESULT
|
|
FilePool::CreateShdWriter(
|
|
struct FileListItem * Item
|
|
)
|
|
{
|
|
HRESULT RetVal = S_OK;
|
|
HANDLE Temp = INVALID_HANDLE_VALUE;
|
|
|
|
|
|
Temp = CreateFile( Item->ShdFilename,
|
|
ShdModes.Mode,
|
|
ShdModes.ShareMode,
|
|
NULL,
|
|
CREATE_ALWAYS | ShdModes.Disp,
|
|
ShdModes.Flags,
|
|
NULL);
|
|
|
|
if (Temp && (Temp != INVALID_HANDLE_VALUE))
|
|
{
|
|
Item->ShdWriteHandle = Temp;
|
|
Item->CreateInfo |= FP_SHD_CREATED;
|
|
}
|
|
else
|
|
{
|
|
RetVal = E_FAIL;
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
/*********************
|
|
* Filepool::RemoveFromPool()
|
|
*
|
|
* See RemoveFromFilePool() Above.
|
|
*/
|
|
|
|
HRESULT
|
|
FilePool::RemoveFromPool(
|
|
struct FileListItem * File,
|
|
BOOL Delete
|
|
)
|
|
{
|
|
HRESULT RemRetVal = S_OK;
|
|
|
|
if ((File->Status & FP_STATUS_SPL_READING) ||
|
|
(File->Status & FP_STATUS_SPL_WRITING) ||
|
|
(File->Status & FP_STATUS_SHD_WRITING))
|
|
{
|
|
RemRetVal = E_FAIL;
|
|
|
|
//
|
|
// This is a pathological case as it will cause us to leak a KM handle.
|
|
// Hard break here.
|
|
//
|
|
DBGMSG(DBG_ERROR, ("Tried to release a file with handles in use\n"));
|
|
}
|
|
else
|
|
{
|
|
EnterCritSec();
|
|
RemRetVal = RemoveFromFPList(File, &FileInUse, &EndUsedFiles);
|
|
|
|
if (SUCCEEDED(RemRetVal))
|
|
{
|
|
UsedSize--;
|
|
}
|
|
LeaveCritSec();
|
|
|
|
if (FAILED(RemRetVal))
|
|
{
|
|
EnterCritSec();
|
|
RemRetVal = RemoveFromFPList(File, &FreeFiles, &EndFreeFiles);
|
|
|
|
if (SUCCEEDED(RemRetVal))
|
|
{
|
|
FreeSize--;
|
|
}
|
|
LeaveCritSec();
|
|
}
|
|
|
|
|
|
if (SUCCEEDED(RemRetVal))
|
|
{
|
|
if (Delete)
|
|
{
|
|
DeletePoolFile(&File);
|
|
}
|
|
else
|
|
{
|
|
FPCloseFiles(File, TRUE);
|
|
|
|
DeleteCriticalSection(&File->CritSec);
|
|
|
|
if (File->SplFilename)
|
|
{
|
|
FreeSplMem(File->SplFilename);
|
|
}
|
|
if (File->ShdFilename)
|
|
{
|
|
FreeSplMem(File->ShdFilename);
|
|
}
|
|
FreeSplMem(File);
|
|
}
|
|
}
|
|
}
|
|
|
|
return RemRetVal;
|
|
|
|
}
|
|
|
|
/*********************
|
|
* Filepool::TrimPool()
|
|
*
|
|
* See TrimPool() Above.
|
|
*/
|
|
|
|
|
|
BOOL
|
|
FilePool::TrimPool(
|
|
VOID
|
|
)
|
|
{
|
|
DWORD Time = 0;
|
|
BOOL GotToTrim = TRUE;
|
|
struct FileListItem * Temp = NULL;
|
|
struct FileListItem * DeleteFiles = NULL;
|
|
DWORD TrimCount = 0;
|
|
BOOL bFilesToTrim = FALSE;
|
|
|
|
Time = GetTickCount();
|
|
|
|
EnterCritSec();
|
|
|
|
DeleteFiles = FreeFiles;
|
|
|
|
while (FreeFiles)
|
|
{
|
|
if ((FreeFiles->TimeStamp > Time) ||
|
|
(Time - FreeFiles->TimeStamp > PoolTimeout))
|
|
{
|
|
//
|
|
// Walk forward until you reach a file that is not too old.
|
|
//
|
|
FreeFiles = FreeFiles->FLNext;
|
|
|
|
TrimCount++;
|
|
}
|
|
else
|
|
{
|
|
if (FreeFiles->FLPrev)
|
|
{
|
|
//
|
|
// There are files to delete.
|
|
//
|
|
FreeFiles->FLPrev->FLNext = NULL;
|
|
FreeFiles->FLPrev = NULL;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// No files have timed out.
|
|
//
|
|
DeleteFiles = NULL;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!FreeFiles)
|
|
{
|
|
EndFreeFiles = NULL;
|
|
}
|
|
|
|
//
|
|
// We need to decrease the FreeSize by the number of elements we are just about
|
|
// to trim off it.
|
|
//
|
|
FreeSize -= TrimCount;
|
|
|
|
//
|
|
// We should trim files the next time around if there is a FreeFiles list.
|
|
//
|
|
bFilesToTrim = FreeFiles != NULL;
|
|
|
|
LeaveCritSec();
|
|
|
|
//
|
|
// Now outside the critsec do the deletions.
|
|
//
|
|
while (DeleteFiles)
|
|
{
|
|
struct FileListItem * Temp = DeleteFiles;
|
|
DeleteFiles = DeleteFiles->FLNext;
|
|
DeletePoolFile(&Temp);
|
|
}
|
|
|
|
return bFilesToTrim;
|
|
}
|
|
|
|
|
|
void*
|
|
FilePool::operator new(
|
|
size_t n
|
|
)
|
|
{
|
|
return AllocSplMem(n);
|
|
}
|
|
|
|
void
|
|
FilePool::operator delete(
|
|
void* p,
|
|
size_t n
|
|
)
|
|
{
|
|
if (p)
|
|
{
|
|
FreeSplMem(p);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|