464 lines
11 KiB
C++
464 lines
11 KiB
C++
|
#include <wbemcomn.h>
|
||
|
#include "a51tools.h"
|
||
|
#include "objheap.h"
|
||
|
#include "index.h"
|
||
|
|
||
|
#define ROSWELL_OFFSET_FORMAT_STRING L"%d"
|
||
|
#define ROSWELL_HEAPALLOC_TYPE_BUSY 0xA51A51A5
|
||
|
|
||
|
long CObjectHeap::Initialize(CAbstractFileSource * pAbstractSource,
|
||
|
WCHAR * wszObjHeapName,
|
||
|
WCHAR * wszBaseName,
|
||
|
DWORD dwBaseNameLen)
|
||
|
{
|
||
|
CInCritSec ics(&m_cs);
|
||
|
if (m_bInit)
|
||
|
return ERROR_SUCCESS;
|
||
|
|
||
|
long lRes;
|
||
|
|
||
|
lRes = m_Heap.Initialize(pAbstractSource, wszObjHeapName);
|
||
|
|
||
|
if(lRes != ERROR_SUCCESS)
|
||
|
return lRes;
|
||
|
|
||
|
lRes = m_Index.Initialize(dwBaseNameLen, wszBaseName, pAbstractSource);
|
||
|
if(lRes != ERROR_SUCCESS)
|
||
|
return lRes;
|
||
|
|
||
|
m_bInit = TRUE;
|
||
|
|
||
|
return lRes;
|
||
|
}
|
||
|
|
||
|
long CObjectHeap::Uninitialize(DWORD dwShutDownFlags)
|
||
|
{
|
||
|
CInCritSec ics(&m_cs);
|
||
|
if (!m_bInit)
|
||
|
return ERROR_SUCCESS;
|
||
|
|
||
|
m_Index.Shutdown(dwShutDownFlags);
|
||
|
|
||
|
m_Heap.Uninitialize();
|
||
|
|
||
|
m_bInit = FALSE;
|
||
|
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
void CObjectHeap::InvalidateCache()
|
||
|
{
|
||
|
m_Index.InvalidateCache();
|
||
|
m_Heap.InvalidateCache();
|
||
|
}
|
||
|
|
||
|
long CObjectHeap::FindClose(HANDLE hFileEnum)
|
||
|
{
|
||
|
return m_Index.FindClose(hFileEnum);
|
||
|
}
|
||
|
|
||
|
long CObjectHeap::FindFirst(LPCWSTR wszPrefix,
|
||
|
WIN32_FIND_DATAW* pfd,
|
||
|
void** ppHandle)
|
||
|
{
|
||
|
return m_Index.FindFirst(wszPrefix,pfd,ppHandle);
|
||
|
}
|
||
|
|
||
|
long CObjectHeap::FindNext(void* pHandle, WIN32_FIND_DATAW* pfd)
|
||
|
{
|
||
|
return m_Index.FindNext(pHandle,pfd);
|
||
|
}
|
||
|
|
||
|
long CObjectHeap::GetIndexFileName(LPCWSTR wszFilePath, LPWSTR wszIndexFileName)
|
||
|
{
|
||
|
WIN32_FIND_DATAW wfd;
|
||
|
HANDLE hSearch = NULL;
|
||
|
|
||
|
long lRes = m_pIndex->FindFirst(wszFilePath, &wfd, NULL);
|
||
|
if(lRes != ERROR_SUCCESS)
|
||
|
{
|
||
|
if(lRes == ERROR_PATH_NOT_FOUND)
|
||
|
lRes = ERROR_FILE_NOT_FOUND;
|
||
|
return lRes;
|
||
|
}
|
||
|
|
||
|
// m_pIndex->FindClose(hSearch);
|
||
|
wcscpy(wszIndexFileName, wfd.cFileName);
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
long CObjectHeap::GetFileInfo(LPCWSTR wszFilePath, TOffset* pnOffset,
|
||
|
DWORD* pdwLength)
|
||
|
{
|
||
|
CFileName wszIndexFileName;
|
||
|
if(wszIndexFileName == NULL)
|
||
|
return ERROR_OUTOFMEMORY;
|
||
|
|
||
|
long lRes = GetIndexFileName(wszFilePath, wszIndexFileName);
|
||
|
if(lRes != ERROR_SUCCESS)
|
||
|
return lRes;
|
||
|
|
||
|
return ParseInfoFromIndexFile(wszIndexFileName, pnOffset, pdwLength);
|
||
|
}
|
||
|
|
||
|
long CObjectHeap::ParseInfoFromIndexFile(LPCWSTR wszIndexFileName,
|
||
|
TOffset* pnOffset, DWORD* pdwLength)
|
||
|
{
|
||
|
WCHAR* pDot = wcschr(wszIndexFileName, L'.');
|
||
|
if(pDot == NULL)
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
|
||
|
WCHAR* pwc = pDot+1;
|
||
|
*pnOffset = 0;
|
||
|
while(*pwc && *pwc != L'.')
|
||
|
{
|
||
|
*pnOffset = (*pnOffset * 10) + (*pwc - '0');
|
||
|
pwc++;
|
||
|
}
|
||
|
|
||
|
if(*pwc != L'.')
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
|
||
|
pwc++;
|
||
|
|
||
|
*pdwLength = 0;
|
||
|
while(*pwc && *pwc != L'.')
|
||
|
{
|
||
|
*pdwLength = (*pdwLength * 10) + (*pwc - '0');
|
||
|
pwc++;
|
||
|
}
|
||
|
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
long CObjectHeap::CreateIndexFile(LPCWSTR wszFilePath, TOffset nOffset,
|
||
|
DWORD dwLength)
|
||
|
{
|
||
|
//
|
||
|
// Simply append the numbers to the file path
|
||
|
//
|
||
|
|
||
|
CFileName wszIndexFilePath;
|
||
|
if(wszIndexFilePath == NULL)
|
||
|
return ERROR_OUTOFMEMORY;
|
||
|
|
||
|
swprintf(wszIndexFilePath, L"%s." ROSWELL_OFFSET_FORMAT_STRING L".%d",
|
||
|
wszFilePath, nOffset, dwLength);
|
||
|
|
||
|
return CreateZeroLengthFile(wszIndexFilePath);
|
||
|
}
|
||
|
|
||
|
long CObjectHeap::DeleteIndexFile(LPCWSTR wszFilePath, LPCWSTR wszIndexFileName)
|
||
|
{
|
||
|
//
|
||
|
// Construct the full path to the index file by concatenating the directory
|
||
|
// of the original file with the name
|
||
|
//
|
||
|
|
||
|
CFileName wszIndexFilePath;
|
||
|
if(wszIndexFilePath == NULL)
|
||
|
return ERROR_OUTOFMEMORY;
|
||
|
|
||
|
WCHAR* pwcLastSlash = wcsrchr(wszFilePath, L'\\');
|
||
|
if(pwcLastSlash == NULL)
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
|
||
|
int nPrefixLen = (pwcLastSlash - wszFilePath + 1);
|
||
|
memcpy(wszIndexFilePath, wszFilePath, nPrefixLen * sizeof(WCHAR));
|
||
|
|
||
|
wcscpy(wszIndexFilePath + nPrefixLen, wszIndexFileName);
|
||
|
return DeleteZeroLengthFile(wszIndexFilePath);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
long CObjectHeap::CreateZeroLengthFile(LPCWSTR wszFilePath)
|
||
|
{
|
||
|
// TBD: use staging file, use more efficient API
|
||
|
|
||
|
return m_pIndex->Create(wszFilePath);
|
||
|
}
|
||
|
|
||
|
long CObjectHeap::DeleteZeroLengthFile(LPCWSTR wszFilePath)
|
||
|
{
|
||
|
// TBD: use staging file, use more efficient API
|
||
|
|
||
|
return m_pIndex->Delete(wszFilePath);
|
||
|
}
|
||
|
|
||
|
DWORD CObjectHeap::GetAllocationHeaderLength()
|
||
|
{
|
||
|
return sizeof(DWORD) // length
|
||
|
+ sizeof(DWORD); // type
|
||
|
}
|
||
|
|
||
|
long CObjectHeap::WriteAllocation(TOffset nOffset, DWORD dwDataLength,
|
||
|
BYTE* pData)
|
||
|
{
|
||
|
//
|
||
|
// Prepare a buffer with the complete allocation
|
||
|
//
|
||
|
|
||
|
DWORD dwAllocationLength = dwDataLength + GetAllocationHeaderLength();
|
||
|
BYTE* pAllocation = (BYTE*)TempAlloc(dwAllocationLength);
|
||
|
if(pAllocation == NULL)
|
||
|
return ERROR_OUTOFMEMORY;
|
||
|
CTempFreeMe tfm(pAllocation);
|
||
|
|
||
|
memcpy(pAllocation, &dwDataLength, sizeof(DWORD));
|
||
|
DWORD dwType = ROSWELL_HEAPALLOC_TYPE_BUSY;
|
||
|
memcpy(pAllocation + sizeof(DWORD), &dwType, sizeof(DWORD));
|
||
|
|
||
|
memcpy(pAllocation + GetAllocationHeaderLength(), pData, dwDataLength);
|
||
|
|
||
|
return m_pHeap->WriteBytes(nOffset, pAllocation, dwAllocationLength);
|
||
|
}
|
||
|
|
||
|
long CObjectHeap::ReadAllocation(TOffset nOffset, DWORD dwDataLength,
|
||
|
BYTE* pBuffer)
|
||
|
{
|
||
|
//
|
||
|
// Prepare a buffer with the complete allocation
|
||
|
//
|
||
|
|
||
|
DWORD dwAllocationLength = dwDataLength + GetAllocationHeaderLength();
|
||
|
BYTE* pAllocation = (BYTE*)TempAlloc(dwAllocationLength);
|
||
|
if(pAllocation == NULL)
|
||
|
return ERROR_OUTOFMEMORY;
|
||
|
CTempFreeMe tfm(pAllocation);
|
||
|
|
||
|
long lRes = m_pHeap->ReadBytes(nOffset, pAllocation, dwAllocationLength);
|
||
|
if(lRes != ERROR_SUCCESS)
|
||
|
return lRes;
|
||
|
|
||
|
//
|
||
|
// Sanity checks
|
||
|
//
|
||
|
|
||
|
_ASSERT(!memcmp(pAllocation, &dwDataLength, sizeof(DWORD)),
|
||
|
L"Allocation size in conflict with the index size");
|
||
|
|
||
|
DWORD dwType = ROSWELL_HEAPALLOC_TYPE_BUSY;
|
||
|
_ASSERT(!memcmp(pAllocation + sizeof(DWORD), &dwType, sizeof(DWORD)),
|
||
|
L"Allocation type is not BUSY");
|
||
|
|
||
|
memcpy(pBuffer, pAllocation + GetAllocationHeaderLength(), dwDataLength);
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
|
||
|
long CObjectHeap::WriteFile(LPCWSTR wszFilePath, DWORD dwBufferLen,
|
||
|
BYTE* pBuffer)
|
||
|
{
|
||
|
CInCritSec ics(&m_cs);
|
||
|
if (!m_bInit)
|
||
|
return -1;
|
||
|
|
||
|
long lRes;
|
||
|
|
||
|
if(dwBufferLen == 0)
|
||
|
{
|
||
|
//
|
||
|
// We do not use the heap for 0-length files, we create them directly
|
||
|
//
|
||
|
|
||
|
return CreateZeroLengthFile(wszFilePath);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now, check if this file already exists
|
||
|
//
|
||
|
|
||
|
CFileName wszIndexFileName;
|
||
|
if(wszIndexFileName == NULL)
|
||
|
return ERROR_OUTOFMEMORY;
|
||
|
|
||
|
lRes = GetIndexFileName(wszFilePath, wszIndexFileName);
|
||
|
if(lRes != ERROR_FILE_NOT_FOUND && lRes != ERROR_SUCCESS)
|
||
|
return lRes;
|
||
|
|
||
|
if(lRes == ERROR_SUCCESS)
|
||
|
{
|
||
|
//
|
||
|
// Already there. Check if we can simply update it
|
||
|
//
|
||
|
|
||
|
TOffset nOffset;
|
||
|
DWORD dwOldLength;
|
||
|
lRes = ParseInfoFromIndexFile(wszIndexFileName, &nOffset, &dwOldLength);
|
||
|
if(lRes != ERROR_SUCCESS)
|
||
|
return lRes;
|
||
|
|
||
|
if(dwOldLength >= dwBufferLen)
|
||
|
{
|
||
|
//
|
||
|
// Enough space in place --- just write the data and update the
|
||
|
// length
|
||
|
//
|
||
|
|
||
|
lRes = WriteAllocation(nOffset, dwBufferLen, pBuffer);
|
||
|
if(lRes != ERROR_SUCCESS)
|
||
|
return lRes;
|
||
|
|
||
|
if(dwOldLength != dwBufferLen)
|
||
|
{
|
||
|
//
|
||
|
// The length has changed --- first of all, mark the rest of
|
||
|
// the block as free
|
||
|
//
|
||
|
|
||
|
lRes = m_pHeap->FreeAllocation(
|
||
|
nOffset + GetAllocationHeaderLength() + dwBufferLen,
|
||
|
dwOldLength - dwBufferLen);
|
||
|
|
||
|
if(lRes != ERROR_SUCCESS)
|
||
|
return lRes;
|
||
|
|
||
|
//
|
||
|
// Now, delete the old index file and create a new one (the
|
||
|
// length has changed
|
||
|
//
|
||
|
|
||
|
lRes = DeleteIndexFile(wszFilePath, wszIndexFileName);
|
||
|
if(lRes != ERROR_SUCCESS)
|
||
|
return lRes;
|
||
|
|
||
|
lRes = CreateIndexFile(wszFilePath, nOffset, dwBufferLen);
|
||
|
if(lRes != ERROR_SUCCESS)
|
||
|
return lRes;
|
||
|
}
|
||
|
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Doesn't fit. Erase it
|
||
|
//
|
||
|
|
||
|
lRes = m_pHeap->FreeAllocation(nOffset,
|
||
|
GetAllocationHeaderLength() + dwOldLength);
|
||
|
if(lRes != ERROR_SUCCESS)
|
||
|
return lRes;
|
||
|
|
||
|
lRes = DeleteIndexFile(wszFilePath, wszIndexFileName);
|
||
|
if(lRes != ERROR_SUCCESS)
|
||
|
return lRes;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Either it wasn't there, or we have cleaned it up. Insert it now
|
||
|
//
|
||
|
|
||
|
TOffset nOffset;
|
||
|
lRes = m_pHeap->Allocate(dwBufferLen + GetAllocationHeaderLength(),
|
||
|
&nOffset);
|
||
|
if(lRes != ERROR_SUCCESS)
|
||
|
return lRes;
|
||
|
|
||
|
lRes = WriteAllocation(nOffset, dwBufferLen, pBuffer);
|
||
|
if(lRes != ERROR_SUCCESS)
|
||
|
return lRes;
|
||
|
|
||
|
lRes = CreateIndexFile(wszFilePath, nOffset, dwBufferLen);
|
||
|
if(lRes != ERROR_SUCCESS)
|
||
|
return lRes;
|
||
|
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
long CObjectHeap::ReadFile(LPCWSTR wszFilePath, DWORD* pdwLength,
|
||
|
BYTE** ppBuffer)
|
||
|
{
|
||
|
CInCritSec ics(&m_cs);
|
||
|
if (!m_bInit)
|
||
|
return -1;
|
||
|
|
||
|
long lRes;
|
||
|
|
||
|
//
|
||
|
// TBD: deal with filepath being the path to the index file instead of the
|
||
|
// theoretical file path --- this can happen if people FindFirstFile it
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// Find the file
|
||
|
//
|
||
|
|
||
|
TOffset nOffset;
|
||
|
lRes = GetFileInfo(wszFilePath, &nOffset, pdwLength);
|
||
|
if(lRes != ERROR_SUCCESS)
|
||
|
return lRes;
|
||
|
|
||
|
//
|
||
|
// Read the allocation
|
||
|
//
|
||
|
|
||
|
*ppBuffer = (BYTE*)TempAlloc(*pdwLength);
|
||
|
if(*ppBuffer == NULL)
|
||
|
return ERROR_OUTOFMEMORY;
|
||
|
|
||
|
lRes = ReadAllocation(nOffset, *pdwLength, *ppBuffer);
|
||
|
if(lRes != ERROR_SUCCESS)
|
||
|
{
|
||
|
TempFree(*ppBuffer);
|
||
|
return lRes;
|
||
|
}
|
||
|
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
long CObjectHeap::DeleteFile(LPCWSTR wszFilePath)
|
||
|
{
|
||
|
CInCritSec ics(&m_cs);
|
||
|
if (!m_bInit)
|
||
|
return -1;
|
||
|
|
||
|
//
|
||
|
// Find the index file
|
||
|
//
|
||
|
|
||
|
CFileName wszIndexFileName;
|
||
|
if(wszIndexFileName == NULL)
|
||
|
return ERROR_OUTOFMEMORY;
|
||
|
|
||
|
long lRes = GetIndexFileName(wszFilePath, wszIndexFileName);
|
||
|
if(lRes != ERROR_SUCCESS)
|
||
|
return lRes;
|
||
|
|
||
|
//
|
||
|
// Delete the allocation
|
||
|
//
|
||
|
|
||
|
TOffset nOffset;
|
||
|
DWORD dwLength;
|
||
|
lRes = ParseInfoFromIndexFile(wszIndexFileName, &nOffset, &dwLength);
|
||
|
if(lRes == ERROR_INVALID_PARAMETER)
|
||
|
{
|
||
|
//
|
||
|
// Not an index file --- must be a zero-length one
|
||
|
//
|
||
|
|
||
|
return DeleteZeroLengthFile(wszFilePath);
|
||
|
}
|
||
|
|
||
|
lRes = m_pHeap->FreeAllocation(nOffset,
|
||
|
dwLength + GetAllocationHeaderLength());
|
||
|
if(lRes != ERROR_SUCCESS)
|
||
|
return lRes;
|
||
|
|
||
|
//
|
||
|
// Delete the index itself
|
||
|
//
|
||
|
|
||
|
lRes = DeleteIndexFile(wszFilePath, wszIndexFileName);
|
||
|
if(lRes != ERROR_SUCCESS)
|
||
|
return lRes;
|
||
|
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
|
||
|
|