2025-04-27 07:49:33 -04:00

1159 lines
28 KiB
C++

/*++
Copyright (C) 2000-2001 Microsoft Corporation
--*/
#include <wbemcomn.h>
#include <sync.h>
#include <malloc.h>
#include "shortstg.h"
#include "filecach.h"
#define A51_INSTRUCTION_TYPE_CREATEFILE 1
#define A51_INSTRUCTION_TYPE_DELETEFILE 2
#define A51_INSTRUCTION_TYPE_REMOVEDIRECTORY 3
CTempMemoryManager g_FileCacheManager;
CShortFileInstruction::CShortFileInstruction(CShortFileStagingFile* pFile)
: CStageInstruction(pFile), m_wszFilePath(NULL)
{
}
long CShortFileInstruction::Initialize(LPCWSTR wszFilePath)
{
int nFilePathLen = wcslen(wszFilePath);
m_wszFilePath = (WCHAR*)TempAlloc(g_FileCacheManager, (nFilePathLen+1) * sizeof(WCHAR));
if(m_wszFilePath == NULL)
return ERROR_OUTOFMEMORY;
wcscpy(m_wszFilePath, wszFilePath);
return ERROR_SUCCESS;
}
CShortFileInstruction::~CShortFileInstruction()
{
if (m_wszFilePath)
{
TempFree(g_FileCacheManager, m_wszFilePath);
}
}
DWORD CShortFileInstruction::ComputeSpaceForName()
{
return sizeof(DWORD) + wcslen(m_wszFilePath) * sizeof(WCHAR);
}
BYTE* CShortFileInstruction::WriteFileName(BYTE* pStart)
{
DWORD dwStringLen = wcslen(m_wszFilePath);
memcpy(pStart, (void*)&dwStringLen, sizeof(DWORD));
pStart += sizeof(DWORD);
memcpy(pStart, m_wszFilePath, dwStringLen * sizeof(WCHAR));
return pStart + dwStringLen * sizeof(WCHAR);
}
long CShortFileInstruction::RecoverFileName(HANDLE hFile)
{
_ASSERT(m_wszFilePath == NULL,
L"Double initialization of a file instruction!");
//
// Read the length
//
DWORD dwStringLen = 0;
DWORD dwRead;
if(!ReadFile(hFile, (BYTE*)&dwStringLen, sizeof(DWORD), &dwRead, NULL))
return GetLastError();
if(dwRead != sizeof(DWORD))
return ERROR_HANDLE_EOF;
//
// Read the file name
//
m_wszFilePath = (WCHAR*)TempAlloc(g_FileCacheManager,
(dwStringLen+1) * sizeof(WCHAR));
if(m_wszFilePath == NULL)
return ERROR_OUTOFMEMORY;
if(!ReadFile(hFile, (BYTE*)m_wszFilePath, dwStringLen * sizeof(WCHAR),
&dwRead, NULL))
{
TempFree(m_wszFilePath, (dwStringLen+1) * sizeof(WCHAR));
return GetLastError();
}
if(dwRead != dwStringLen * sizeof(WCHAR))
{
TempFree(m_wszFilePath, (dwStringLen+1) * sizeof(WCHAR));
return ERROR_HANDLE_EOF;
}
m_wszFilePath[dwStringLen] = 0;
return ERROR_SUCCESS;
}
void CShortFileInstruction::ComputeFullPath(wchar_t *wszFullPath)
{
wcscpy(wszFullPath, ((CShortFileStagingFile*)m_pManager)->GetBase());
wcscat(wszFullPath, m_wszFilePath);
}
CCreateFile::CCreateFile(CShortFileStagingFile* pFile)
: CShortFileInstruction(pFile), m_dwFileLen(0), m_dwFileStart(0)
{
}
void* CCreateFile::operator new(size_t)
{
return TempAlloc(g_FileCacheManager, sizeof(CCreateFile));
}
void CCreateFile::operator delete(void* p)
{
return TempFree(g_FileCacheManager, p, sizeof(CCreateFile));
}
long CCreateFile::Initialize(LPCWSTR wszFilePath, DWORD dwFileLen)
{
long lRes = CShortFileInstruction::Initialize(wszFilePath);
if(lRes != ERROR_SUCCESS)
return lRes;
m_dwFileLen = dwFileLen;
return ERROR_SUCCESS;
}
DWORD CCreateFile::ComputeNeededSpace()
{
return sizeof(BYTE) + // for the type
ComputeSpaceForName() + // for the file name
sizeof(DWORD) + // for the length of data
m_dwFileLen + // for the data
A51_TAIL_SIZE; // for the trailer
}
long CCreateFile::Write(TFileOffset lOffset, BYTE* pBuffer)
{
if(pBuffer)
memcpy(&m_dwFileStart, pBuffer, sizeof(DWORD));
else
m_dwFileStart = 0;
//
// Construct an in-memory buffer large enough for the whole thing
//
DWORD dwNeededSpace = ComputeNeededSpace();
BYTE* pWholeBuffer = (BYTE*)TempAlloc(dwNeededSpace);
if(pWholeBuffer == NULL)
return ERROR_OUTOFMEMORY;
CTempFreeMe vdm(pWholeBuffer, dwNeededSpace);
BYTE* pCurrent = pWholeBuffer;
//
// Write instruction type
//
*pCurrent = A51_INSTRUCTION_TYPE_CREATEFILE;
pCurrent++;
//
// Write the name of the file
//
pCurrent = WriteFileName(pCurrent);
//
// Write the length of the data for the file
//
memcpy(pCurrent, (void*)&m_dwFileLen, sizeof(DWORD));
pCurrent += sizeof(DWORD);
//
// Write the data itself and record its offset
//
memcpy(pCurrent, pBuffer, m_dwFileLen);
m_lStageOffset = lOffset + (pCurrent - pWholeBuffer);
//
// Write the trailer
//
memset(pCurrent + m_dwFileLen, 0, sizeof(DWORD));
//
// Write it
//
return m_pManager->WriteInstruction(lOffset, pWholeBuffer, dwNeededSpace);
}
long CCreateFile::RecoverData(HANDLE hFile)
{
//
// Recover the file name first
//
long lRes = CShortFileInstruction::RecoverFileName(hFile);
if(lRes != ERROR_SUCCESS)
return lRes;
//
// Read the length of the data from the file
//
DWORD dwRead;
if(!ReadFile(hFile, (BYTE*)&m_dwFileLen, sizeof(DWORD), &dwRead, NULL))
return GetLastError();
if(dwRead != sizeof(DWORD))
return ERROR_HANDLE_EOF;
//
// We do not need to actually read the data from the file --- we keep it
// there until it is time to flush. But we do need to skip it. At the same
// time, we need to record the position in the file where this data resides
//
LARGE_INTEGER liFileLen;
liFileLen.QuadPart = m_dwFileLen;
LARGE_INTEGER liNewPosition;
if(!SetFilePointerEx(hFile, liFileLen, &liNewPosition, FILE_CURRENT))
return GetLastError();
_ASSERT(liNewPosition.HighPart == 0, L"Staging file too long!");
m_lStageOffset = (long)(liNewPosition.QuadPart - m_dwFileLen);
return ERROR_SUCCESS;
}
long CCreateFile::GetData(HANDLE hFile, DWORD* pdwLen, BYTE** ppBuffer)
{
//
// Lock the file
//
CInCritSec ics(m_pManager->GetLock());
_ASSERT(m_pManager->GetFirstFreeOffset() >= m_lStageOffset,
L"Instruction points to empty space in stage file");
if(pdwLen)
*pdwLen = m_dwFileLen;
if(ppBuffer == NULL)
return ERROR_SUCCESS;
//
// Allocate the buffer
//
*ppBuffer = (BYTE*)TempAlloc(m_dwFileLen);
if(*ppBuffer == NULL)
return ERROR_OUTOFMEMORY;
long lRes = A51ReadFromFileSync(hFile, m_lStageOffset, *ppBuffer, m_dwFileLen);
if(lRes != ERROR_SUCCESS)
{
delete *ppBuffer;
return lRes;
}
if(m_dwFileLen && m_dwFileStart && memcmp(*ppBuffer, &m_dwFileStart, sizeof(DWORD)))
{
_ASSERT(false, L"Stage file overwritten");
TempFree(*ppBuffer, m_dwFileLen);
return ERROR_OUTOFMEMORY;
}
return ERROR_SUCCESS;
}
long CCreateFile::Execute()
{
//
// Construct full path
//
CFileName wszFullPath;
if (wszFullPath == NULL)
return ERROR_OUTOFMEMORY;
ComputeFullPath(wszFullPath);
long lRes;
//
// Read the data from the staging file
//
BYTE* pBuffer = NULL;
lRes = GetData(m_pManager->GetHandle(), NULL, &pBuffer);
if(lRes != ERROR_SUCCESS)
return lRes;
CTempFreeMe vdm(pBuffer, m_dwFileLen);
return ((CShortFileStagingFile*)m_pManager)->
WriteActualFile(wszFullPath, m_dwFileLen, pBuffer);
}
CDeleteFile::CDeleteFile(CShortFileStagingFile* pFile)
: CShortFileInstruction(pFile)
{
}
void* CDeleteFile::operator new(size_t)
{
return TempAlloc(g_FileCacheManager, sizeof(CDeleteFile));
}
void CDeleteFile::operator delete(void* p)
{
return TempFree(g_FileCacheManager, p, sizeof(CDeleteFile));
}
long CDeleteFile::Initialize(LPCWSTR wszFileName)
{
return CShortFileInstruction::Initialize(wszFileName);
}
DWORD CDeleteFile::ComputeNeededSpace()
{
return sizeof(BYTE) + // for instruction type
ComputeSpaceForName() + // for the file name
A51_TAIL_SIZE; // for the trailer
}
long CDeleteFile::Write(TFileOffset lOffset)
{
//
// Construct an in-memory buffer large enough for the whole thing
//
DWORD dwNeededSpace = ComputeNeededSpace();
BYTE* pWholeBuffer = (BYTE*)TempAlloc(dwNeededSpace);
if(pWholeBuffer == NULL)
return ERROR_OUTOFMEMORY;
CTempFreeMe vdm(pWholeBuffer, dwNeededSpace);
BYTE* pCurrent = pWholeBuffer;
//
// Write the instruction type
//
*pCurrent = A51_INSTRUCTION_TYPE_DELETEFILE;
pCurrent++;
//
// Write the file name
//
pCurrent = WriteFileName(pCurrent);
m_lStageOffset = lOffset + (pCurrent - pWholeBuffer);
//
// Write the trailer
//
memset(pCurrent, 0, sizeof(DWORD));
//
// Write it
//
return m_pManager->WriteInstruction(lOffset, pWholeBuffer, dwNeededSpace);
}
long CDeleteFile::RecoverData(HANDLE hFile)
{
//
// Recover the file name
//
long lRes = CShortFileInstruction::RecoverFileName(hFile);
if(lRes != ERROR_SUCCESS)
return lRes;
LARGE_INTEGER liZero;
liZero.QuadPart = 0;
LARGE_INTEGER liPosition;
if(!SetFilePointerEx(hFile, liZero, &liPosition, FILE_CURRENT))
return GetLastError();
_ASSERT(liPosition.HighPart == 0, L"Staging file too long!");
m_lStageOffset = (long)(liPosition.QuadPart);
return ERROR_SUCCESS;
}
long CDeleteFile::Execute()
{
//
// Construct full path
//
CFileName wszFullPath;
if (wszFullPath == NULL)
return ERROR_OUTOFMEMORY;
ComputeFullPath(wszFullPath);
//
// Delete the right file
//
long lRes = ((CShortFileStagingFile*)m_pManager)->
DeleteActualFile(wszFullPath);
if(lRes != ERROR_FILE_NOT_FOUND && lRes != ERROR_PATH_NOT_FOUND)
return lRes;
else
return ERROR_SUCCESS;
}
CRemoveDirectory::CRemoveDirectory(CShortFileStagingFile* pFile)
: CShortFileInstruction(pFile)
{
}
void* CRemoveDirectory::operator new(size_t)
{
return TempAlloc(g_FileCacheManager, sizeof(CRemoveDirectory));
}
void CRemoveDirectory::operator delete(void* p)
{
return TempFree(g_FileCacheManager, p, sizeof(CRemoveDirectory));
}
long CRemoveDirectory::Initialize(LPCWSTR wszFileName)
{
return CShortFileInstruction::Initialize(wszFileName);
}
DWORD CRemoveDirectory::ComputeNeededSpace()
{
return sizeof(BYTE) + // for the instruction type
ComputeSpaceForName() + // for the file name
A51_TAIL_SIZE; // for the trailer
}
long CRemoveDirectory::Write(TFileOffset lOffset)
{
//
// Construct an in-memory buffer large enough for the whole thing
//
DWORD dwNeededSpace = ComputeNeededSpace();
BYTE* pWholeBuffer = (BYTE*)TempAlloc(dwNeededSpace);
if(pWholeBuffer == NULL)
return ERROR_OUTOFMEMORY;
CTempFreeMe vdm(pWholeBuffer, dwNeededSpace);
BYTE* pCurrent = pWholeBuffer;
//
// Write instruction type
//
*pCurrent = A51_INSTRUCTION_TYPE_REMOVEDIRECTORY;
pCurrent++;
//
// Write the file name
//
pCurrent = WriteFileName(pCurrent);
m_lStageOffset = lOffset + (pCurrent - pWholeBuffer);
//
// Write the trailer
//
memset(pCurrent, 0, sizeof(DWORD));
//
// Write it
//
return m_pManager->WriteInstruction(lOffset, pWholeBuffer, dwNeededSpace);
}
long CRemoveDirectory::RecoverData(HANDLE hFile)
{
//
// Recover the file name
//
long lRes = CShortFileInstruction::RecoverFileName(hFile);
if(lRes != ERROR_SUCCESS)
return lRes;
LARGE_INTEGER liZero;
liZero.QuadPart = 0;
LARGE_INTEGER liPosition;
if(!SetFilePointerEx(hFile, liZero, &liPosition, FILE_CURRENT))
return GetLastError();
_ASSERT(liPosition.HighPart == 0, L"Staging file too long!");
m_lStageOffset = (long)(liPosition.QuadPart);
return ERROR_SUCCESS;
}
long CRemoveDirectory::Execute()
{
//
// Construct full path
//
CFileName wszFullPath;
if (wszFullPath == NULL)
return ERROR_OUTOFMEMORY;
ComputeFullPath(wszFullPath);
//
// Remove the directory
//
long lRes = ((CShortFileStagingFile*)m_pManager)->
RemoveActualDirectory(wszFullPath);
if(lRes != ERROR_FILE_NOT_FOUND && lRes != ERROR_PATH_NOT_FOUND &&
lRes != ERROR_DIR_NOT_EMPTY)
{
return lRes;
}
else
{
return ERROR_SUCCESS;
}
}
CShortFileStagingFile::CShortFileStagingFile(CFileCache* pCache,
LPCWSTR wszBaseName,
long lMaxFileSize,
long lAbortTransactionFileSize)
: CExecutableStageManager(lMaxFileSize, lAbortTransactionFileSize),
m_map(TMap::key_compare(), TMap::allocator_type(&g_FileCacheManager)),
m_pCache(pCache)
{
wcscpy(m_wszBaseName, wszBaseName);
}
CShortFileStagingFile::~CShortFileStagingFile()
{
}
void CShortFileStagingFile::ComputeKey(LPCWSTR wszFileName, LPWSTR wszKey)
{
wbem_wcsupr(wszKey, wszFileName);
}
long CShortFileStagingFile::RemoveInstructionFromMap(
CStageInstruction* pRawInst)
{
CInCritSec ics(m_pCache->GetLock());
CShortFileInstruction* pInst = (CShortFileInstruction*)pRawInst;
TIterator it = m_map.find(pInst->GetFilePath());
if(it != m_map.end() && it->second == pInst)
{
//
// This instruction is currently in the map. Remove it.
//
it->second->Release();
EraseIterator(it);
}
return ERROR_SUCCESS;
}
long CShortFileStagingFile::WriteFile(LPCWSTR wszFileName, DWORD dwLen,
BYTE* pBuffer)
{
long lRes;
CFileName wszKey;
if (wszKey == NULL)
return ERROR_OUTOFMEMORY;
ComputeKey(wszFileName, wszKey);
CCreateFile* pInst = new CCreateFile(this);
if(pInst == NULL)
return ERROR_OUTOFMEMORY;
pInst->AddRef();
CTemplateReleaseMe<CShortFileInstruction> rm1(pInst);
lRes = pInst->Initialize(wszKey, dwLen);
if(lRes != ERROR_SUCCESS)
return lRes;
DWORD dwSpaceNeeded = pInst->ComputeNeededSpace();
if(!CanWriteInTransaction(dwSpaceNeeded))
return ERROR_NOT_ENOUGH_QUOTA;
{
CInCritSec ics(&m_cs);
//
// Write all the data into the staging area
//
lRes = pInst->Write(m_lFirstFreeOffset, pBuffer);
if(lRes)
return lRes;
m_lFirstFreeOffset += dwSpaceNeeded - A51_TAIL_SIZE;
lRes = AddInstruction(pInst);
}
return lRes;
}
long CShortFileStagingFile::DeleteFile(LPCWSTR wszFileName)
{
long lRes;
CFileName wszKey;
if (wszKey == NULL)
return ERROR_OUTOFMEMORY;
ComputeKey(wszFileName, wszKey);
CDeleteFile* pInst = new CDeleteFile(this);
if(pInst == NULL)
return ERROR_OUTOFMEMORY;
pInst->AddRef();
CTemplateReleaseMe<CShortFileInstruction> rm1(pInst);
lRes = pInst->Initialize(wszKey);
if(lRes != ERROR_SUCCESS)
return lRes;
DWORD dwSpaceNeeded = pInst->ComputeNeededSpace();
if(!CanWriteInTransaction(dwSpaceNeeded))
return ERROR_NOT_ENOUGH_QUOTA;
{
CInCritSec ics(&m_cs);
//
// Write all the data into the staging area
//
lRes = pInst->Write(m_lFirstFreeOffset);
if(lRes)
return lRes;
//
// Write the new offset into the offset file
//
m_lFirstFreeOffset += dwSpaceNeeded - A51_TAIL_SIZE;
lRes = AddInstruction(pInst);
}
return lRes;
}
long CShortFileStagingFile::RemoveDirectory(LPCWSTR wszFileName)
{
long lRes;
CFileName wszKey;
if (wszKey == NULL)
return ERROR_OUTOFMEMORY;
ComputeKey(wszFileName, wszKey);
CRemoveDirectory* pInst = new CRemoveDirectory(this);
if(pInst == NULL)
return ERROR_OUTOFMEMORY;
pInst->AddRef();
CTemplateReleaseMe<CShortFileInstruction> rm1(pInst);
lRes = pInst->Initialize(wszKey);
if(lRes != ERROR_SUCCESS)
return lRes;
DWORD dwSpaceNeeded = pInst->ComputeNeededSpace();
if(!CanWriteInTransaction(dwSpaceNeeded))
return ERROR_NOT_ENOUGH_QUOTA;
{
CInCritSec ics(&m_cs);
//
// Write all the data into the staging area
//
lRes = pInst->Write(m_lFirstFreeOffset);
if(lRes)
{
m_cs.Leave();
return lRes;
}
//
// Write the new offset into the offset file
//
m_lFirstFreeOffset += dwSpaceNeeded - A51_TAIL_SIZE;
lRes = AddInstruction(pInst);
}
return lRes;
}
// assumes: locked
long CShortFileStagingFile::AddInstructionToMap(CStageInstruction* pRawInst,
CStageInstruction** ppUndoInst)
{
CInCritSec ics(m_pCache->GetLock());
if(ppUndoInst)
*ppUndoInst = NULL;
CShortFileInstruction* pInst = (CShortFileInstruction*)pRawInst;
pInst->AddRef();
TIterator it = m_map.find(pInst->GetFilePath());
if(it != m_map.end())
{
//
// It is already there. We need to replace that instruction with our
// own. However, if that instruction was committed, we should remember
// it in case our transaction aborts.
//
// The extra quirk here is that we should not be doing this if the
// instruction being replaced came from our own transaction. This is
// not an empty optimization --- if we do and the transaction aborts,
// we may end up attempting to execute this one even though its body
// is in the garbaged area of the staging file
//
if(ppUndoInst && it->second->IsCommitted())
{
*ppUndoInst = it->second; // transferred ref-count
}
else
{
it->second->Release();
}
EraseIterator(it);
}
try
{
m_map[pInst->GetFilePath()] = pInst;
}
catch(...)
{
//
// Put everything back as well as we can
//
if(ppUndoInst && *ppUndoInst)
*ppUndoInst = NULL;
pInst->Release();
return ERROR_OUTOFMEMORY;
}
return ERROR_SUCCESS;
}
bool CShortFileStagingFile::IsStillCurrent(CStageInstruction* pRawInst)
{
CShortFileInstruction* pInst = (CShortFileInstruction*)pRawInst;
TIterator it = m_map.find(pInst->GetFilePath());
if(it != m_map.end())
{
if(it->second == pInst)
{
//
// This instruction is currently in the map
//
return true;
}
else if(it->second->IsCommitted())
{
//
// Overriden by a committed instruction --- not current
//
return false;
}
else
{
return true;
}
}
else
{
_ASSERT(false, L"Why would we be asking about an instruction that is "
"not even there?");
return false;
}
}
long CShortFileStagingFile::ReadFile(LPCWSTR wszFileName, DWORD* pdwLen,
BYTE** ppBuffer, bool bMustBeThere)
{
CInCritSec ics(&m_cs);
//
// Search for the file
//
CFileName wszKey;
if (wszKey == NULL)
return ERROR_OUTOFMEMORY;
ComputeKey(wszFileName, wszKey);
TIterator it = m_map.find(wszKey);
if(it == m_map.end())
{
return ERROR_NO_INFORMATION;
}
else
{
CShortFileInstruction* pInstruction = it->second;
if(pInstruction->IsDeletion())
{
if(bMustBeThere)
{
Dump();
_ASSERT(false, L"Must-be-present file is not there. Dumped");
}
return ERROR_FILE_NOT_FOUND;
}
else
{
long lRes = ((CCreateFile*)pInstruction)->GetData(m_hFile, pdwLen,
ppBuffer);
return lRes;
}
}
}
void CShortFileStagingFile::Dump()
{
FILE* f = fopen("c:\\a.dmp", "a");
if(f == NULL)
return;
fprintf(f, "MAP:\n");
TIterator it = m_map.begin();
while(it != m_map.end())
{
CShortFileInstruction* pInstruction = it->second;
if(pInstruction->IsDeletion())
fprintf(f, "Delete ");
else
fprintf(f, "Create ");
fprintf(f, "%S\n", pInstruction->GetFilePath());
it++;
}
fprintf(f, "LIST:\n");
int nSize = m_qToWrite.size();
for(int i = 0; i < nSize; i++)
{
CShortFileInstruction* pInstruction = (CShortFileInstruction*)m_qToWrite.front();
if(pInstruction->IsDeletion())
fprintf(f, "Delete ");
else
fprintf(f, "Create ");
fprintf(f, "%S\n", pInstruction->GetFilePath());
m_qToWrite.pop_front();
m_qToWrite.push_back(pInstruction);
}
fclose(f);
}
long CShortFileStagingFile::IsDeleted(LPCWSTR wszFilePath)
{
CInCritSec ics(&m_cs);
//
// Search for the file
//
CFileName wszKey;
if (wszKey == NULL)
return ERROR_OUTOFMEMORY;
ComputeKey(wszFilePath, wszKey);
TIterator it = m_map.find(wszKey);
if(it == m_map.end())
{
return S_FALSE;
}
else
{
CShortFileInstruction* pInstruction = it->second;
if(pInstruction->IsDeletion())
return S_OK;
else
return S_FALSE;
}
}
long CShortFileStagingFile::FindFirst(LPCWSTR wszFilePrefix, WIN32_FIND_DATAW* pfd,
void** ppHandle)
{
CInCritSec ics(&m_cs);
//
// Compute the key for the prefix --- key computation is such that the
// keys come in the same lexicographic order as the names, so this will
// give us the lower bound for the search
//
CFileName wszKey;
if (wszKey == NULL)
return ERROR_OUTOFMEMORY;
ComputeKey(wszFilePrefix, wszKey);
//
// Find this spot in the map
//
TIterator it = m_map.lower_bound(wszKey);
if(it == m_map.end())
return ERROR_FILE_NOT_FOUND;
//
// Retrieve the first element
//
CIterationHandle* pHandle = new CIterationHandle(m_map, it, wszKey);
if(pHandle == NULL)
return WBEM_E_OUT_OF_MEMORY;
long lRes = pHandle->GetNext(pfd);
if(lRes != ERROR_SUCCESS)
{
delete pHandle;
if(lRes == ERROR_NO_MORE_FILES)
lRes = ERROR_FILE_NOT_FOUND;
return lRes;
}
m_apIterators.Add(pHandle);
*ppHandle = pHandle;
return ERROR_SUCCESS;
}
long CShortFileStagingFile::FindNext(void* pHandle, WIN32_FIND_DATAW* pfd)
{
CInCritSec ics(&m_cs);
//
// The "handle" is really an iteration handle pointer
//
CIterationHandle* pIterationHandle = (CIterationHandle*)pHandle;
//
// Get the thing pointed to by the iterator, unless it is past the end
//
return pIterationHandle->GetNext(pfd);
}
void CShortFileStagingFile::FindClose(void* pHandle)
{
CInCritSec ics(&m_cs);
//
// The "handle" is really an iteration handle pointer
//
CIterationHandle* pIterationHandle = (CIterationHandle*)pHandle;
for(int i = 0; i < m_apIterators.GetSize(); i++)
{
if(m_apIterators[i] == pIterationHandle)
{
m_apIterators.RemoveAt(i);
delete pIterationHandle;
return;
}
}
_ASSERT(false, L"Non-existent iteration handle is closed");
}
long CShortFileStagingFile::ConstructInstructionFromType(int nType,
CStageInstruction** ppInst)
{
CShortFileInstruction* pInst = NULL;
switch(nType)
{
case A51_INSTRUCTION_TYPE_CREATEFILE:
pInst = new CCreateFile(this);
break;
case A51_INSTRUCTION_TYPE_DELETEFILE:
pInst = new CDeleteFile(this);
break;
case A51_INSTRUCTION_TYPE_REMOVEDIRECTORY:
pInst = new CRemoveDirectory(this);
break;
default:
return ERROR_RXACT_INVALID_STATE;
}
if(pInst == NULL)
return WBEM_E_OUT_OF_MEMORY;
pInst->AddRef();
*ppInst = pInst;
return ERROR_SUCCESS;
}
CShortFileStagingFile::TIterator CShortFileStagingFile::EraseIterator(
CShortFileStagingFile::TIterator it)
{
//
// In order to safely remove an iterator, we need to make sure that
// no iteration handle is standing on it
//
for(int i = 0; i < m_apIterators.GetSize(); i++)
{
CIterationHandle* pHandle = m_apIterators[i];
if(pHandle->m_it == it)
{
//
// Advance it to the next position, since this one is dead
//
pHandle->m_it++;
}
}
//
// It is now safe to remove the element
//
return m_map.erase(it);
}
CShortFileStagingFile::CIterationHandle::CIterationHandle(
CShortFileStagingFile::TMap& rMap,
const CShortFileStagingFile::TIterator& rIt,
LPCWSTR wszPrefix)
: m_rMap(rMap), m_it(rIt)
{
wcscpy(m_wszPrefix, wszPrefix);
m_dwPrefixLen = wcslen(wszPrefix);
//
// Compute the length of the directory portion of the prefix
//
WCHAR* pwcLastSlash = wcsrchr(wszPrefix, L'\\');
if(pwcLastSlash == NULL)
m_dwPrefixDirLen = 0;
else
m_dwPrefixDirLen = pwcLastSlash - wszPrefix + 1;
}
long CShortFileStagingFile::CIterationHandle::GetNext(WIN32_FIND_DATAW* pfd)
{
//
// Repeat while we are not at the end of the list or past the prefix
//
while(m_it != m_rMap.end() &&
!wcsncmp(m_it->first, m_wszPrefix, m_dwPrefixLen))
{
CShortFileInstruction* pInst = m_it->second;
//
// Ignore deletioin requests
//
if(!m_it->second->IsDeletion())
{
//
// Copy the file name (ignoring dir) into the variable
//
wcscpy(pfd->cFileName,
m_it->second->GetFilePath() + m_dwPrefixDirLen);
pfd->dwFileAttributes = 0;
m_it++;
return ERROR_SUCCESS;
}
m_it++;
}
return ERROR_NO_MORE_FILES;
}
long CShortFileStagingFile::WriteActualFile(LPCWSTR wszFileName, DWORD dwLen,
BYTE* pBuffer)
{
#ifdef A51_USE_HEAP
return m_pCache->GetObjectHeap()->WriteFile(wszFileName, dwLen, pBuffer);
#else
return A51WriteFile(wszFileName, dwLen, pBuffer);
#endif
}
long CShortFileStagingFile::DeleteActualFile(LPCWSTR wszFileName)
{
#ifdef A51_USE_HEAP
return m_pCache->GetObjectHeap()->DeleteFile(wszFileName);
#else
return A51DeleteFile(wszFileName);
#endif
}
long CShortFileStagingFile::RemoveActualDirectory(LPCWSTR wszFileName)
{
#ifdef A51_USE_HEAP
return ERROR_SUCCESS;
#else
return A51RemoveDirectory(wszFileName);
#endif
}