650 lines
14 KiB
C++
650 lines
14 KiB
C++
/*++
|
|
|
|
Copyright (C) 2000-2001 Microsoft Corporation
|
|
|
|
--*/
|
|
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <wbemcomn.h>
|
|
#include "a51tools.h"
|
|
|
|
__int64 g_nCurrentTime = 1;
|
|
|
|
__int64 g_nReadFailures = 0;
|
|
__int64 g_nWriteFailures = 0;
|
|
|
|
//
|
|
// FILE_ATTRIBUTE_NOT_CONTENT_INDEXED is not actually supported on CreateFile,
|
|
// contrary to the docs. However, also contrary to the docs, it is inherited
|
|
// from the parent directory
|
|
//
|
|
|
|
#define A51_FILE_CREATION_FLAGS 0 //FILE_ATTRIBUTE_NOT_CONTENT_INDEXED
|
|
|
|
CTempMemoryManager g_Manager;
|
|
|
|
void* TempAlloc(DWORD dwLen)
|
|
{
|
|
return g_Manager.Allocate(dwLen);
|
|
}
|
|
|
|
void TempFree(void* p, DWORD dwLen)
|
|
{
|
|
g_Manager.Free(p, dwLen);
|
|
}
|
|
|
|
void* TempAlloc(CTempMemoryManager& Manager, DWORD dwLen)
|
|
{
|
|
return Manager.Allocate(dwLen);
|
|
}
|
|
|
|
void TempFree(CTempMemoryManager& Manager, void* p, DWORD dwLen)
|
|
{
|
|
Manager.Free(p, dwLen);
|
|
}
|
|
|
|
HANDLE g_hLastEvent = NULL;
|
|
CCritSec g_csEvents;
|
|
HANDLE A51GetNewEvent()
|
|
{
|
|
{
|
|
CInCritSec ics(&g_csEvents);
|
|
if(g_hLastEvent)
|
|
{
|
|
HANDLE h = g_hLastEvent;
|
|
g_hLastEvent = NULL;
|
|
return h;
|
|
}
|
|
}
|
|
|
|
return CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
}
|
|
|
|
void A51ReturnEvent(HANDLE hEvent)
|
|
{
|
|
{
|
|
CInCritSec ics(&g_csEvents);
|
|
if(g_hLastEvent == NULL)
|
|
{
|
|
g_hLastEvent = hEvent;
|
|
return;
|
|
}
|
|
}
|
|
|
|
CloseHandle(hEvent);
|
|
}
|
|
|
|
HRESULT A51TranslateErrorCode(long lRes)
|
|
{
|
|
if (lRes == ERROR_SUCCESS)
|
|
return WBEM_S_NO_ERROR;
|
|
|
|
switch(lRes)
|
|
{
|
|
case ERROR_FILE_NOT_FOUND:
|
|
case ERROR_PATH_NOT_FOUND:
|
|
return WBEM_E_NOT_FOUND;
|
|
|
|
case ERROR_OUTOFMEMORY:
|
|
case ERROR_NOT_ENOUGH_MEMORY:
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
|
|
case ERROR_NOT_ENOUGH_QUOTA:
|
|
case ERROR_DISK_FULL:
|
|
return WBEM_E_OUT_OF_DISK_SPACE;
|
|
|
|
case ERROR_SERVER_SHUTDOWN_IN_PROGRESS:
|
|
return WBEM_E_SHUTTING_DOWN;
|
|
|
|
default:
|
|
return WBEM_E_FAILED;
|
|
}
|
|
}
|
|
|
|
long __stdcall EnsureDirectory(LPCWSTR wszPath, LPSECURITY_ATTRIBUTES pSA)
|
|
{
|
|
if(!CreateDirectoryW(wszPath, NULL))
|
|
{
|
|
long lRes = GetLastError();
|
|
if(lRes != ERROR_ALREADY_EXISTS)
|
|
return lRes;
|
|
else
|
|
return ERROR_SUCCESS;
|
|
}
|
|
else
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
long __stdcall EnsureDirectoryRecursiveForFile(LPWSTR wszPath,
|
|
LPSECURITY_ATTRIBUTES pSA);
|
|
long __stdcall EnsureDirectoryForFile(LPCWSTR wszPath, LPSECURITY_ATTRIBUTES pSA)
|
|
{
|
|
//
|
|
// Make a copy, since we will be messing with it
|
|
//
|
|
|
|
CFileName wszNewPath;
|
|
if (wszNewPath == NULL)
|
|
return ERROR_OUTOFMEMORY;
|
|
wcscpy(wszNewPath, wszPath);
|
|
|
|
return EnsureDirectoryRecursiveForFile(wszNewPath, pSA);
|
|
}
|
|
|
|
|
|
long __stdcall EnsureDirectoryRecursiveForFile(LPWSTR wszPath,
|
|
LPSECURITY_ATTRIBUTES pSA)
|
|
{
|
|
long lRes;
|
|
|
|
//
|
|
// Find the last backslash and remove
|
|
//
|
|
|
|
WCHAR* pwcLastSlash = wcsrchr(wszPath, L'\\');
|
|
if(pwcLastSlash == NULL)
|
|
return ERROR_BAD_PATHNAME;
|
|
|
|
*pwcLastSlash = 0;
|
|
|
|
//
|
|
// Try to create it
|
|
//
|
|
|
|
if(!CreateDirectoryW(wszPath, pSA))
|
|
{
|
|
//
|
|
// Call ourselves recursively --- to create our parents
|
|
//
|
|
|
|
lRes = EnsureDirectoryRecursiveForFile(wszPath, pSA);
|
|
if(lRes != ERROR_SUCCESS)
|
|
{
|
|
*pwcLastSlash = L'\\';
|
|
return lRes;
|
|
}
|
|
|
|
//
|
|
// Try again
|
|
//
|
|
|
|
BOOL bRes = CreateDirectoryW(wszPath, pSA);
|
|
*pwcLastSlash = L'\\';
|
|
if(bRes)
|
|
return ERROR_SUCCESS;
|
|
else
|
|
return GetLastError();
|
|
}
|
|
else
|
|
{
|
|
*pwcLastSlash = L'\\';
|
|
return ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
static WCHAR g_HexDigit[] =
|
|
{ L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7', L'8', L'9',
|
|
L'A', L'B', L'C', L'D', L'E', L'F'
|
|
};
|
|
|
|
bool A51Hash(LPCWSTR wszName, LPWSTR wszHash)
|
|
{
|
|
//
|
|
// Have to upper-case everything
|
|
//
|
|
|
|
DWORD dwBufferSize = wcslen(wszName)*2+2;
|
|
LPWSTR wszBuffer = (WCHAR*)TempAlloc(dwBufferSize);
|
|
if (wszBuffer == NULL)
|
|
return false;
|
|
CTempFreeMe vdm(wszBuffer, dwBufferSize);
|
|
|
|
wbem_wcsupr(wszBuffer, wszName);
|
|
|
|
BYTE RawHash[16];
|
|
MD5::Transform((void*)wszBuffer, wcslen(wszBuffer)*2, RawHash);
|
|
|
|
WCHAR* pwc = wszHash;
|
|
for(int i = 0; i < 16; i++)
|
|
{
|
|
*(pwc++) = g_HexDigit[RawHash[i]/16];
|
|
*(pwc++) = g_HexDigit[RawHash[i]%16];
|
|
}
|
|
*pwc = 0;
|
|
return true;
|
|
}
|
|
|
|
long A51WriteFile(LPCWSTR wszFullPath, DWORD dwLen, BYTE* pBuffer)
|
|
{
|
|
long lRes;
|
|
|
|
A51TRACE(( "Create file %S\n", wszFullPath));
|
|
|
|
//
|
|
// Create the right file
|
|
//
|
|
|
|
HANDLE hFile = CreateFileW(wszFullPath, GENERIC_WRITE, 0,
|
|
NULL, CREATE_ALWAYS, A51_FILE_CREATION_FLAGS, NULL);
|
|
|
|
if(hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
lRes = GetLastError();
|
|
if(lRes == ERROR_PATH_NOT_FOUND)
|
|
{
|
|
lRes = EnsureDirectoryForFile(wszFullPath, NULL);
|
|
if(lRes != ERROR_SUCCESS)
|
|
return lRes;
|
|
|
|
hFile = CreateFileW(wszFullPath, GENERIC_WRITE, 0,
|
|
NULL, CREATE_ALWAYS, A51_FILE_CREATION_FLAGS, NULL);
|
|
|
|
if(hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
lRes = GetLastError();
|
|
_ASSERT(lRes != ERROR_SUCCESS, L"success error code from fail");
|
|
return lRes;
|
|
}
|
|
}
|
|
else
|
|
return lRes;
|
|
}
|
|
|
|
CCloseMe cm(hFile);
|
|
|
|
//
|
|
// Write it and close
|
|
//
|
|
|
|
if(!WriteFile(hFile, pBuffer, dwLen, &dwLen, NULL))
|
|
{
|
|
lRes = GetLastError();
|
|
_ASSERT(lRes != ERROR_SUCCESS, L"success error code from fail");
|
|
return lRes;
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
long A51DeleteFile(LPCWSTR wszFullPath)
|
|
{
|
|
A51TRACE(("Delete file %S\n", wszFullPath));
|
|
|
|
//
|
|
// Delete the right file
|
|
//
|
|
|
|
if(!DeleteFileW(wszFullPath))
|
|
return GetLastError();
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
long A51WriteToFileAsync(HANDLE hFile, long lStartingOffset, BYTE* pBuffer,
|
|
DWORD dwBufferLen, OVERLAPPED* pov)
|
|
{
|
|
pov->Offset = lStartingOffset;
|
|
pov->OffsetHigh = 0;
|
|
pov->hEvent = A51GetNewEvent();
|
|
|
|
BOOL bRes;
|
|
DWORD dwWritten;
|
|
while(!(bRes = WriteFile(hFile, pBuffer, dwBufferLen, &dwWritten, pov)) &&
|
|
(GetLastError() == ERROR_INVALID_USER_BUFFER ||
|
|
GetLastError() == ERROR_NOT_ENOUGH_MEMORY))
|
|
{
|
|
//
|
|
// Out of buffer-space --- wait a bit and retry
|
|
//
|
|
|
|
g_nWriteFailures++;
|
|
Sleep(16);
|
|
}
|
|
|
|
if(!bRes)
|
|
{
|
|
long lRes = GetLastError();
|
|
if(lRes == ERROR_IO_PENDING)
|
|
// perfect!
|
|
return ERROR_SUCCESS;
|
|
else
|
|
{
|
|
A51ReturnEvent(pov->hEvent);
|
|
pov->hEvent = NULL;
|
|
return lRes;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Succeeded synchronously --- clean up and return
|
|
//
|
|
|
|
A51ReturnEvent(pov->hEvent);
|
|
pov->hEvent = NULL;
|
|
|
|
if(dwWritten != dwBufferLen)
|
|
return ERROR_OUTOFMEMORY;
|
|
else
|
|
return ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
long A51WriteToFileSync(HANDLE hFile, long lStartingOffset, BYTE* pBuffer,
|
|
DWORD dwBufferLen)
|
|
{
|
|
OVERLAPPED ov;
|
|
|
|
long lRes = A51WriteToFileAsync(hFile, lStartingOffset, pBuffer,
|
|
dwBufferLen, &ov);
|
|
if(lRes != ERROR_SUCCESS)
|
|
return lRes;
|
|
|
|
if(ov.hEvent)
|
|
{
|
|
CReturnMe rm(ov.hEvent);
|
|
|
|
//
|
|
// Wait for completion
|
|
//
|
|
|
|
DWORD dwWritten;
|
|
if(!GetOverlappedResult(hFile, &ov, &dwWritten, TRUE))
|
|
return GetLastError();
|
|
|
|
if(dwWritten != dwBufferLen)
|
|
return ERROR_OUTOFMEMORY;
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
long A51ReadFromFileAsync(HANDLE hFile, long lStartingOffset, BYTE* pBuffer,
|
|
DWORD dwBufferLen, OVERLAPPED* pov)
|
|
{
|
|
long lRes;
|
|
|
|
pov->Offset = lStartingOffset;
|
|
pov->OffsetHigh = 0;
|
|
pov->hEvent = A51GetNewEvent();
|
|
|
|
BOOL bRes;
|
|
DWORD dwRead;
|
|
while(!(bRes = ReadFile(hFile, pBuffer, dwBufferLen, &dwRead, pov)) &&
|
|
(GetLastError() == ERROR_INVALID_USER_BUFFER ||
|
|
GetLastError() == ERROR_NOT_ENOUGH_MEMORY))
|
|
{
|
|
//
|
|
// Out of buffer-space --- wait a bit and retry
|
|
//
|
|
|
|
g_nReadFailures++;
|
|
Sleep(16);
|
|
}
|
|
|
|
if(!bRes)
|
|
{
|
|
if(GetLastError() == ERROR_IO_PENDING)
|
|
// perfect!
|
|
return ERROR_SUCCESS;
|
|
else
|
|
{
|
|
lRes = GetLastError();
|
|
_ASSERT(lRes != ERROR_SUCCESS, L"Success returned on failure");
|
|
A51ReturnEvent(pov->hEvent);
|
|
pov->hEvent = NULL;
|
|
if(lRes == ERROR_HANDLE_EOF)
|
|
lRes = ERROR_SUCCESS;
|
|
return lRes;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Succeeded synchronously --- clean up and return
|
|
//
|
|
|
|
A51ReturnEvent(pov->hEvent);
|
|
pov->hEvent = NULL;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
long A51ReadFromFileSync(HANDLE hFile, long lStartingOffset, BYTE* pBuffer,
|
|
DWORD dwBufferLen)
|
|
{
|
|
OVERLAPPED ov;
|
|
|
|
long lRes = A51ReadFromFileAsync(hFile, lStartingOffset, pBuffer,
|
|
dwBufferLen, &ov);
|
|
if(lRes != ERROR_SUCCESS)
|
|
return lRes;
|
|
|
|
if(ov.hEvent)
|
|
{
|
|
CReturnMe rm(ov.hEvent);
|
|
|
|
//
|
|
// Wait for completion
|
|
//
|
|
|
|
DWORD dwRead = 0;
|
|
if(!GetOverlappedResult(hFile, &ov, &dwRead, TRUE))
|
|
{
|
|
lRes = GetLastError();
|
|
_ASSERT(lRes != ERROR_SUCCESS, L"Success returned on failure");
|
|
if(lRes == ERROR_HANDLE_EOF)
|
|
lRes = ERROR_SUCCESS;
|
|
return lRes;
|
|
}
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
long RemoveDirectoryRecursive(LPCWSTR wszDirectoryPath, bool bAbortOnFiles);
|
|
long A51RemoveDirectory(LPCWSTR wszFullPath, bool bAbortOnFiles)
|
|
{
|
|
long lRes = RemoveDirectoryRecursive(wszFullPath, bAbortOnFiles);
|
|
if(lRes == ERROR_PATH_NOT_FOUND || lRes == ERROR_FILE_NOT_FOUND)
|
|
return ERROR_FILE_NOT_FOUND;
|
|
else
|
|
return lRes;
|
|
}
|
|
|
|
long RemoveDirectoryRecursive(LPCWSTR wszDirectoryPath, bool bAbortOnFiles)
|
|
{
|
|
long lRes;
|
|
|
|
//
|
|
// Try removing it right away
|
|
//
|
|
|
|
if(!RemoveDirectoryW(wszDirectoryPath))
|
|
{
|
|
lRes = GetLastError();
|
|
if(lRes == ERROR_PATH_NOT_FOUND || lRes == ERROR_FILE_NOT_FOUND)
|
|
return ERROR_FILE_NOT_FOUND;
|
|
else if(lRes != ERROR_DIR_NOT_EMPTY && lRes != ERROR_SHARING_VIOLATION)
|
|
return lRes;
|
|
}
|
|
else
|
|
return ERROR_SUCCESS;
|
|
|
|
//
|
|
// Not empty (or at least we are not sure it is empty) --- enumerate
|
|
// everything
|
|
//
|
|
|
|
CFileName wszMap;
|
|
if (wszMap == NULL)
|
|
return ERROR_OUTOFMEMORY;
|
|
wcscpy(wszMap, wszDirectoryPath);
|
|
wcscat(wszMap, L"\\*");
|
|
|
|
CFileName wszChild;
|
|
if (wszChild == NULL)
|
|
return ERROR_OUTOFMEMORY;
|
|
wcscpy(wszChild, wszDirectoryPath);
|
|
wcscat(wszChild, L"\\");
|
|
long lChildLen = wcslen(wszChild);
|
|
|
|
WIN32_FIND_DATAW fd;
|
|
HANDLE hSearch = FindFirstFileW(wszMap, &fd);
|
|
if(hSearch == INVALID_HANDLE_VALUE)
|
|
return ERROR_DIR_NOT_EMPTY;
|
|
|
|
do
|
|
{
|
|
if(fd.cFileName[0] == L'.')
|
|
continue;
|
|
|
|
if((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
|
|
{
|
|
if(bAbortOnFiles)
|
|
{
|
|
// There is a file --- give up
|
|
FindClose(hSearch);
|
|
return ERROR_DIR_NOT_EMPTY;
|
|
}
|
|
else
|
|
{
|
|
wcscpy(wszChild + lChildLen, fd.cFileName);
|
|
if(!DeleteFileW(wszChild))
|
|
{
|
|
FindClose(hSearch);
|
|
return GetLastError();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wcscpy(wszChild + lChildLen, fd.cFileName);
|
|
lRes = RemoveDirectoryRecursive(wszChild, bAbortOnFiles);
|
|
if(lRes != ERROR_SUCCESS && lRes != ERROR_FILE_NOT_FOUND)
|
|
{
|
|
FindClose(hSearch);
|
|
return lRes;
|
|
}
|
|
}
|
|
}
|
|
while(FindNextFileW(hSearch, &fd));
|
|
|
|
FindClose(hSearch);
|
|
|
|
//
|
|
// And try again
|
|
//
|
|
|
|
if(!RemoveDirectoryW(wszDirectoryPath))
|
|
{
|
|
lRes = GetLastError();
|
|
if(lRes == ERROR_PATH_NOT_FOUND || lRes == ERROR_FILE_NOT_FOUND)
|
|
return ERROR_FILE_NOT_FOUND;
|
|
else if(lRes == ERROR_SHARING_VIOLATION)
|
|
return ERROR_SUCCESS;
|
|
else
|
|
return lRes;
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
CRITICAL_SECTION g_csLog;
|
|
char* g_szText = NULL;
|
|
long g_lTextLen = 0;
|
|
WCHAR g_wszLogFilename[MAX_PATH] = L"";
|
|
void A51Trace(LPCSTR szFormat, ...)
|
|
{
|
|
if((g_wszLogFilename[0] == 0) || (g_szText == NULL))
|
|
{
|
|
InitializeCriticalSection(&g_csLog);
|
|
|
|
delete g_szText;
|
|
g_wszLogFilename[0] = 0;
|
|
g_szText = NULL;
|
|
|
|
HKEY hKey;
|
|
long lRes = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
|
L"SOFTWARE\\Microsoft\\WBEM\\CIMOM",
|
|
0, KEY_READ, &hKey);
|
|
if(lRes)
|
|
{
|
|
wcscpy(g_wszLogFilename, L"c:\\a51.log");
|
|
}
|
|
else
|
|
{
|
|
DWORD dwLen = MAX_PATH;
|
|
CFileName wszTmp;
|
|
if (wszTmp == 0)
|
|
{
|
|
wcscpy(g_wszLogFilename, L"c:\\a51.log");
|
|
RegCloseKey(hKey);
|
|
}
|
|
else
|
|
{
|
|
lRes = RegQueryValueExW(hKey, L"Logging Directory", NULL, NULL,
|
|
(LPBYTE)(wchar_t*)wszTmp, &dwLen);
|
|
RegCloseKey(hKey);
|
|
if(lRes)
|
|
{
|
|
wcscpy(g_wszLogFilename, L"c:\\a51.log");
|
|
}
|
|
else
|
|
{
|
|
if (ExpandEnvironmentStringsW(wszTmp,g_wszLogFilename,MAX_PATH) == 0)
|
|
{
|
|
wcscpy(g_wszLogFilename, L"c:\\a51.log");
|
|
}
|
|
else
|
|
{
|
|
if (g_wszLogFilename[wcslen(g_wszLogFilename)] == L'\\')
|
|
{
|
|
wcscat(g_wszLogFilename, L"a51.log");
|
|
}
|
|
else
|
|
{
|
|
wcscat(g_wszLogFilename, L"\\a51.log");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
g_szText = new char[3000000];
|
|
if (g_szText == NULL)
|
|
return;
|
|
}
|
|
|
|
EnterCriticalSection(&g_csLog);
|
|
|
|
char szBuffer[256];
|
|
va_list argptr;
|
|
va_start(argptr, szFormat);
|
|
vsprintf(szBuffer, szFormat, argptr);
|
|
long lLen = strlen(szBuffer);
|
|
if(g_lTextLen + lLen > 2900000)
|
|
A51TraceFlush();
|
|
|
|
strcpy(g_szText + g_lTextLen, szBuffer);
|
|
g_lTextLen += lLen;
|
|
|
|
LeaveCriticalSection(&g_csLog);
|
|
}
|
|
|
|
void A51TraceFlush()
|
|
{
|
|
FILE* fLog = NULL;
|
|
fLog = _wfopen(g_wszLogFilename, L"a");
|
|
if(fLog)
|
|
{
|
|
fwrite(g_szText, 1, g_lTextLen, fLog);
|
|
g_lTextLen = 0;
|
|
// fflush(fLog);
|
|
fclose(fLog);
|
|
}
|
|
}
|