|
|
#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; }
|