Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1423 lines
45 KiB

#include "stdafx.hxx"
//#include "vs_idl.hxx"
#include "vss.h"
#include "vswriter.h"
#include "vsbackup.h"
#include "compont.h"
#include <debug.h>
#include <cwriter.h>
#include <lmshare.h>
#include <lmaccess.h>
#include <time.h>
#include <vs_inc.hxx>
extern WCHAR g_wszSavedFilesDirectory[];
bool FindComponent
(
IVssExamineWriterMetadata *pMetadata,
LPCWSTR wszLogicalPath,
LPCWSTR wszComponentName,
IVssWMComponent **ppComponent
);
typedef struct _SAVE_INFO
{
IVssBackupComponents *pvbc;
IVssComponent *pComponent;
IVssExamineWriterMetadata *pMetadata;
CVssSimpleMap<VSS_PWSZ, VSS_PWSZ> mapSnapshots;
} SAVE_INFO;
void DoCopyFile(LPCWSTR wszSource, LPCWSTR wszDest)
{
CComBSTR bstr = wszDest;
UINT cwc = (UINT) wcslen(wszDest);
HANDLE hFile;
LPWSTR wszBuf = new WCHAR[cwc + 1];
if (wszBuf == NULL)
Error(E_OUTOFMEMORY, L"Out of Memory");
while(TRUE)
{
LPWSTR wsz = wcsrchr(bstr, L'\\');
if (wsz == NULL)
break;
*wsz = L'\0';
wcscpy(wszBuf, bstr);
wcscat(wszBuf, L"\\");
hFile = CreateFile
(
wszBuf,
GENERIC_READ,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL
);
if (hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(hFile);
break;
}
}
delete wszBuf;
// add backslash removed previously
bstr[wcslen(bstr)] = L'\\';
while(wcslen(bstr) < cwc)
{
if (!CreateDirectory(bstr, NULL))
{
DWORD dwErr = GetLastError();
Error(HRESULT_FROM_WIN32(dwErr), L"CreateDirectory failed with error %d.\n", dwErr);
}
bstr[wcslen(bstr)] = L'\\';
}
if (wszSource)
{
if (!CopyFile(wszSource, wszDest, FALSE))
{
DWORD dwErr = GetLastError();
Error(HRESULT_FROM_WIN32(dwErr), L"CopyFile failed with error %d.\n", dwErr);
}
}
}
void SaveFilesMatchingFilespec
(
LPCWSTR wszSnapshotPath,
LPCWSTR wszSavedPath,
LPCWSTR wszFilespec
)
{
CComBSTR bstrSP = wszSnapshotPath;
if (bstrSP[wcslen(bstrSP) - 1] != L'\\')
bstrSP.Append(L"\\");
bstrSP.Append(wszFilespec);
WIN32_FIND_DATA findData;
HANDLE hFile = FindFirstFile(bstrSP, &findData);
if (hFile == INVALID_HANDLE_VALUE)
return;
try
{
do
{
if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
{
CComBSTR bstrCP = wszSavedPath;
bstrSP = wszSnapshotPath;
if (bstrSP[wcslen(bstrSP) - 1] != L'\\')
bstrSP.Append(L"\\");
bstrSP.Append(findData.cFileName);
if (bstrCP[wcslen(bstrCP) - 1] != L'\\')
bstrCP.Append(L"\\");
bstrCP.Append(findData.cFileName);
DoCopyFile(bstrSP, bstrCP);
}
} while(FindNextFile(hFile, &findData));
FindClose(hFile);
}
catch(...)
{
FindClose(hFile);
throw;
}
}
void RecurseSaveFiles
(
LPCWSTR wszSnapshotPath,
LPCWSTR wszSavedPath,
LPCWSTR wszFilespec
)
{
CComBSTR bstrSP = wszSnapshotPath;
bstrSP.Append(L"\\*.*");
WIN32_FIND_DATA findData;
HANDLE hFile = FindFirstFile(bstrSP, &findData);
if (hFile == INVALID_HANDLE_VALUE)
return;
try
{
do
{
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if (wcscmp(findData.cFileName, L".") == 0 ||
wcscmp(findData.cFileName, L"..") == 0)
continue;
bstrSP = wszSnapshotPath;
bstrSP.Append(L"\\");
bstrSP.Append(findData.cFileName);
CComBSTR bstrCP = wszSavedPath;
bstrCP.Append(L"\\");
bstrCP.Append(findData.cFileName);
SaveFilesMatchingFilespec(bstrSP, bstrCP, wszFilespec);
RecurseSaveFiles(bstrSP, bstrCP, wszFilespec);
}
} while(FindNextFile(hFile, &findData));
FindClose(hFile);
}
catch(...)
{
FindClose(hFile);
throw;
}
}
bool BuildSnapshotPath
(
SAVE_INFO &info,
LPCWSTR wszPath,
CComBSTR &bstrSnapshotPath
)
{
CComBSTR bstrPath((UINT) wcslen(wszPath) + 1);
CComBSTR bstrVolumePath((UINT) wcslen(wszPath) + 1);
wcscpy(bstrPath, wszPath);
if (wszPath[wcslen(wszPath) - 1] != L'\\')
wcscat(bstrPath, L"\\");
if (!GetVolumePathName(bstrPath, bstrVolumePath, (UINT) wcslen(wszPath) + 1))
{
DWORD dwErr = GetLastError();
if (dwErr == ERROR_FILENAME_EXCED_RANGE)
{
if (wcslen(bstrPath) >= 3 && bstrPath[1] == L':' && bstrPath[2] == L'\\')
{
memcpy(bstrVolumePath, bstrPath, 6);
bstrVolumePath[3] = L'\0';
}
else
Error(HRESULT_FROM_WIN32(dwErr), L"GetVolumePathName failed with error %d\nPath=%s.", dwErr, wszPath);
}
else
Error(HRESULT_FROM_WIN32(dwErr), L"GetVolumePathName failed with error %d\nPath=%s.", dwErr, wszPath);
}
WCHAR wszVolumeName[MAX_PATH];
if (!GetVolumeNameForVolumeMountPoint(bstrVolumePath, wszVolumeName, MAX_PATH))
return false;
LPCWSTR wszSnapshotDeviceName = info.mapSnapshots.Lookup(wszVolumeName);
if (wszSnapshotDeviceName == NULL)
Error(E_UNEXPECTED, L"Snapshot device does not exist for path %s", wszPath);
bstrSnapshotPath.Append(wszSnapshotDeviceName);
bstrSnapshotPath.Append(wszPath + wcslen(bstrVolumePath) - 1);
return true;
}
void BuildSavedPath
(
LPCWSTR wszPath,
CComBSTR &bstrSavedPath
)
{
bstrSavedPath.Append(g_wszSavedFilesDirectory);
bstrSavedPath.Append(L"VOLUME");
WCHAR wszDrive[2];
wszDrive[0] = wszPath[0];
wszDrive[1] = L'\0';
bstrSavedPath.Append(wszDrive);
bstrSavedPath.Append(wszPath + 2);
}
void DoExpandEnvironmentStrings(CComBSTR &bstrPath)
{
if (!bstrPath)
return;
if (wcschr(bstrPath, L'%') != NULL)
{
WCHAR wsz[MAX_PATH];
UINT cwc = ExpandEnvironmentStrings(bstrPath, wsz, MAX_PATH);
if (cwc == 0)
{
DWORD dwErr = GetLastError();
Error(HRESULT_FROM_WIN32(dwErr), L"ExpandEnvironmentStrings failed due to error %d.\n", dwErr);
}
else if (cwc <= MAX_PATH)
bstrPath = wsz;
else
{
LPWSTR wszT = new WCHAR[cwc];
if (!ExpandEnvironmentStrings(bstrPath, wszT, MAX_PATH))
{
DWORD dwErr = GetLastError();
Error(HRESULT_FROM_WIN32(dwErr), L"ExpandEnvironmentStrings failed due to error %d.\n", dwErr);
}
bstrPath = wszT;
}
}
}
void SaveDataFiles
(
SAVE_INFO &saveInfo,
IVssWMFiledesc *pFiledesc
)
{
CComBSTR bstrPath;
CComBSTR bstrFilespec;
bool bRecursive;
CComBSTR bstrAlternatePath;
HRESULT hr;
CHECK_SUCCESS(pFiledesc->GetPath(&bstrPath));
CHECK_SUCCESS(pFiledesc->GetFilespec(&bstrFilespec));
CHECK_NOFAIL(pFiledesc->GetRecursive(&bRecursive));
CHECK_NOFAIL(pFiledesc->GetAlternateLocation(&bstrAlternatePath));
DoExpandEnvironmentStrings(bstrPath);
DoExpandEnvironmentStrings(bstrAlternatePath);
CComBSTR bstrSnapshotPath;
CComBSTR bstrSavedPath;
if (!BuildSnapshotPath
(
saveInfo,
bstrAlternatePath ? bstrAlternatePath : bstrPath,
bstrSnapshotPath
))
return;
BuildSavedPath(bstrPath, bstrSavedPath);
SaveFilesMatchingFilespec(bstrSnapshotPath, bstrSavedPath, bstrFilespec);
if (bRecursive)
RecurseSaveFiles(bstrSnapshotPath, bstrSavedPath, bstrFilespec);
}
// save data files associated with a component
void SaveComponentFiles
(
SAVE_INFO &saveInfo
)
{
HRESULT hr;
PVSSCOMPONENTINFO pInfo = NULL;
CComPtr<IVssWMComponent> pComponent;
CComBSTR bstrComponentLogicalPath;
CComBSTR bstrComponentName;
CHECK_NOFAIL(saveInfo.pComponent->GetLogicalPath(&bstrComponentLogicalPath));
CHECK_SUCCESS(saveInfo.pComponent->GetComponentName(&bstrComponentName));
// calculate the component's full path
CComBSTR bstrFullPath = bstrComponentLogicalPath;
if (bstrFullPath)
bstrFullPath += L"\\";
bstrFullPath += bstrComponentName;
if (!bstrFullPath)
Error(E_OUTOFMEMORY, L"Ran out of memory");
try
{
unsigned cIncludeFiles, cExcludeFiles, cComponents;
CHECK_SUCCESS(saveInfo.pMetadata->GetFileCounts
(
&cIncludeFiles,
&cExcludeFiles,
&cComponents
));
for(unsigned iComponent = 0; iComponent < cComponents; iComponent++)
{
CHECK_SUCCESS(saveInfo.pMetadata->GetComponent(iComponent, &pComponent));
CHECK_SUCCESS(pComponent->GetComponentInfo(&pInfo));
// if the name and logical path match, we want to save the files
bool bSaveComponent = false;
bSaveComponent = (wcscmp(pInfo->bstrComponentName, bstrComponentName) == 0) &&
(!bstrComponentLogicalPath && !pInfo->bstrLogicalPath) ||
(bstrComponentLogicalPath && pInfo->bstrLogicalPath &&
wcscmp(bstrComponentLogicalPath, pInfo->bstrLogicalPath) == 0);
// if this is a subcomponent, we want to save the files
bSaveComponent = bSaveComponent ||
(pInfo->bstrLogicalPath && (wcsstr(pInfo->bstrLogicalPath, bstrFullPath) == pInfo->bstrLogicalPath));
if (bSaveComponent)
{
for(UINT iFile = 0; iFile < pInfo->cFileCount; iFile++)
{
CComPtr<IVssWMFiledesc> pFiledesc;
CHECK_SUCCESS(pComponent->GetFile(iFile, &pFiledesc));
SaveDataFiles(saveInfo, pFiledesc);
}
for(iFile = 0; iFile < pInfo->cDatabases; iFile++)
{
CComPtr<IVssWMFiledesc> pFiledesc;
CHECK_SUCCESS(pComponent->GetDatabaseFile(iFile, &pFiledesc));
SaveDataFiles(saveInfo, pFiledesc);
}
for(iFile = 0; iFile < pInfo->cLogFiles; iFile++)
{
CComPtr<IVssWMFiledesc> pFiledesc;
CHECK_SUCCESS(pComponent->GetDatabaseLogFile(iFile, &pFiledesc));
SaveDataFiles(saveInfo, pFiledesc);
}
}
pComponent->FreeComponentInfo(pInfo);
pInfo = NULL;
pComponent = NULL;
}
}
catch(...)
{
pComponent->FreeComponentInfo(pInfo);
throw;
}
}
HANDLE OpenMetadataFile(VSS_ID idInstance, BOOL fWrite)
{
// create name of saved metadata file
CComBSTR bstr;
CComBSTR bstrId = idInstance;
bstr.Append(g_wszSavedFilesDirectory);
bstr.Append(L"WRITER");
bstr.Append(bstrId);
bstr.Append(L".xml");
// create and write metadata file
HANDLE hFile = CreateFile
(
bstr,
GENERIC_READ|GENERIC_WRITE,
0,
NULL,
fWrite ? CREATE_ALWAYS : OPEN_EXISTING,
0,
NULL
);
if (hFile == INVALID_HANDLE_VALUE)
{
DWORD dwErr = GetLastError();
Error(HRESULT_FROM_WIN32(dwErr), L"CreateFile failed due to error %d.\n", dwErr);
}
return hFile;
}
void SaveFiles
(
IVssBackupComponents *pvbc,
VSS_ID *rgSnapshotId,
UINT cSnapshots
)
{
SAVE_INFO saveInfo;
HRESULT hr;
unsigned cWriterComponents;
unsigned cWriters;
if (g_wszSavedFilesDirectory[0] != L'\0')
{
for(UINT iSnapshot = 0; iSnapshot < cSnapshots; iSnapshot++)
{
VSS_SNAPSHOT_PROP prop;
pvbc->GetSnapshotProperties(rgSnapshotId[iSnapshot], &prop);
CoTaskMemFree(prop.m_pwszOriginatingMachine);
CoTaskMemFree(prop.m_pwszServiceMachine);
CoTaskMemFree(prop.m_pwszExposedName);
CoTaskMemFree(prop.m_pwszExposedPath);
saveInfo.mapSnapshots.Add(prop.m_pwszOriginalVolumeName, prop.m_pwszSnapshotDeviceObject);
}
}
CHECK_SUCCESS(pvbc->GetWriterComponentsCount(&cWriterComponents));
CHECK_SUCCESS(pvbc->GetWriterMetadataCount(&cWriters));
saveInfo.pvbc = pvbc;
for(unsigned iWriter = 0; iWriter < cWriterComponents; iWriter++)
{
CComPtr<IVssWriterComponentsExt> pWriter;
CComPtr<IVssExamineWriterMetadata> pMetadata = NULL;
CHECK_SUCCESS(pvbc->GetWriterComponents(iWriter, &pWriter));
unsigned cComponents;
CHECK_SUCCESS(pWriter->GetComponentCount(&cComponents));
VSS_ID idWriter, idInstance;
CHECK_SUCCESS(pWriter->GetWriterInfo(&idInstance, &idWriter));
if (g_wszSavedFilesDirectory[0] != L'\0')
{
for(unsigned iWriter = 0; iWriter < cWriters; iWriter++)
{
VSS_ID idInstanceMetadata;
CHECK_SUCCESS(pvbc->GetWriterMetadata(iWriter, &idInstanceMetadata, &pMetadata));
if (idInstance == idInstanceMetadata)
break;
pMetadata = NULL;
}
// save metadata
CComBSTR bstrMetadata;
CHECK_SUCCESS(pMetadata->SaveAsXML(&bstrMetadata));
CVssAutoWin32Handle hFile = OpenMetadataFile(idInstance, true);
DWORD cbWritten;
if (!WriteFile(hFile, bstrMetadata, (UINT) wcslen(bstrMetadata)*sizeof(WCHAR), &cbWritten, NULL))
{
CloseHandle(hFile);
DWORD dwErr = GetLastError();
Error(HRESULT_FROM_WIN32(dwErr), L"WriteFile failed due to error %d.\n", dwErr);
}
BS_ASSERT(pMetadata);
saveInfo.pMetadata = pMetadata;
}
for(unsigned iComponent = 0; iComponent < cComponents; iComponent++)
{
CComPtr<IVssComponent> pComponent;
CHECK_SUCCESS(pWriter->GetComponent(iComponent, &pComponent));
VSS_COMPONENT_TYPE ct;
CComBSTR bstrLogicalPath;
CComBSTR bstrComponentName;
CHECK_NOFAIL(pComponent->GetLogicalPath(&bstrLogicalPath));
CHECK_SUCCESS(pComponent->GetComponentType(&ct));
CHECK_SUCCESS(pComponent->GetComponentName(&bstrComponentName));
CComBSTR bstrStamp;
CHECK_NOFAIL(pComponent->GetBackupStamp(&bstrStamp));
if (bstrStamp)
wprintf(L"Backup stamp for component %s = %s\n", bstrComponentName, bstrStamp);
if (g_wszSavedFilesDirectory[0] != L'\0')
{
saveInfo.pComponent = pComponent;
SaveComponentFiles(saveInfo);
}
CHECK_SUCCESS
(
pvbc->SetBackupSucceeded
(
idInstance,
idWriter,
ct,
bstrLogicalPath,
bstrComponentName,
true)
);
}
}
}
class CRestoreFile
{
public:
CRestoreFile(CRestoreFile *pFile)
{
m_hDestination = INVALID_HANDLE_VALUE;
m_pNext = pFile;
}
~CRestoreFile()
{
if (m_hDestination != INVALID_HANDLE_VALUE)
CloseHandle(m_hDestination);
}
void SetSourceFile(LPCWSTR wszPath) { m_bstrSourceFile = wszPath; }
void SetDestinationHandle(HANDLE hFile) { m_hDestination = hFile; }
void SetDestinationFile(LPCWSTR wszPath) { m_bstrDestinationPath = wszPath; }
CRestoreFile *m_pNext;
CComBSTR m_bstrSourceFile;
CComBSTR m_bstrDestinationPath;
HANDLE m_hDestination;
};
typedef struct _ALTERNATE_MAPPING
{
CComBSTR bstrPath;
CComBSTR bstrAlternatePath;
CComBSTR bstrFilespec;
bool bRecursive;
} ALTERNATE_MAPPING;
static const COPYBUFSIZE = 1024 * 1024;
class RESTORE_INFO
{
public:
RESTORE_INFO()
{
rgMappings = NULL;
pFile = NULL;
pCopyBuf = NULL;
bRebootRequired = false;
cMappings = 0;
}
~RESTORE_INFO()
{
delete [] rgMappings;
CRestoreFile *pFileT = pFile;
while(pFileT)
{
CRestoreFile *pFileNext = pFileT->m_pNext;
delete pFileT;
pFileT = pFileNext;
}
delete pCopyBuf;
}
VSS_ID idWriter;
VSS_ID idInstance;
VSS_COMPONENT_TYPE ct;
IVssExamineWriterMetadata *pMetadataWriter;
IVssExamineWriterMetadata *pMetadataSaved;
IVssBackupComponents *pvbc;
IVssComponent *pComponent;
LPCWSTR wszLogicalPath;
LPCWSTR wszComponentName;
VSS_RESTOREMETHOD_ENUM method;
bool bRebootRequired;
CRestoreFile *pFile;
unsigned cMappings;
ALTERNATE_MAPPING *rgMappings;
BYTE *pCopyBuf;
};
void CompleteRestore(RESTORE_INFO &info)
{
CRestoreFile *pFile = info.pFile;
while(pFile != NULL)
{
if (pFile->m_hDestination != INVALID_HANDLE_VALUE &&
pFile->m_bstrSourceFile)
{
CVssAutoWin32Handle hSource = CreateFile
(
pFile->m_bstrSourceFile,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL
);
if (hSource == INVALID_HANDLE_VALUE)
{
DWORD dwErr = GetLastError();
Error(HRESULT_FROM_WIN32(dwErr), L"CreateFile failed with error %d.\n", dwErr);
}
DWORD dwSize = GetFileSize(hSource, NULL);
if (dwSize == 0xffffffff)
{
DWORD dwErr = GetLastError();
Error(HRESULT_FROM_WIN32(dwErr), L"GetFileSize failed with error %d.\n", dwErr);
}
while(dwSize > 0)
{
DWORD cb = min(COPYBUFSIZE, dwSize);
DWORD dwRead, dwWritten;
if (!ReadFile(hSource, info.pCopyBuf, cb, &dwRead, NULL))
{
DWORD dwErr = GetLastError();
Error(HRESULT_FROM_WIN32(dwErr), L"ReadFile failed dued to error %d.\n", dwErr);
}
if (!WriteFile(pFile->m_hDestination, info.pCopyBuf, cb, &dwWritten, NULL) ||
dwWritten < cb)
{
DWORD dwErr = GetLastError();
Error(HRESULT_FROM_WIN32(dwErr), L"Write file failed due to error %d.\n", dwErr);
}
dwSize -= cb;
}
if (!SetEndOfFile(pFile->m_hDestination))
{
DWORD dwErr = GetLastError();
Error(HRESULT_FROM_WIN32(dwErr), L"SetEndOfFile failed due to error %d.\n", dwErr);
}
}
info.pFile = pFile->m_pNext;
delete pFile;
pFile = info.pFile;
}
}
void CleanupFailedRestore(RESTORE_INFO &info)
{
CRestoreFile *pFile = info.pFile;
while (pFile != NULL)
{
info.pFile = pFile->m_pNext;
delete pFile;
pFile = info.pFile;
}
}
bool SetupRestoreFile
(
RESTORE_INFO &info,
LPCWSTR wszSavedFile,
LPCWSTR wszRestoreFile
)
{
CRestoreFile *pFile = new CRestoreFile(info.pFile);
if (info.method == VSS_RME_RESTORE_TO_ALTERNATE_LOCATION)
{
DoCopyFile(wszSavedFile, wszRestoreFile);
pFile->SetDestinationFile(wszRestoreFile);
info.pFile = pFile;
return true;
}
// ensure path up to destination file exists
CComBSTR bstrDestinationPath = wszRestoreFile;
LPWSTR wsz = wcsrchr(bstrDestinationPath, L'\\');
*(wsz+1) = L'\0';
DoCopyFile(NULL, bstrDestinationPath);
if (info.method == VSS_RME_RESTORE_AT_REBOOT)
{
*wsz = L'\0';
CComBSTR bstrTempFileName((UINT) wcslen(bstrDestinationPath) + MAX_PATH);
if (!GetTempFileName(bstrDestinationPath, L"TBCK", 0, bstrTempFileName))
{
DWORD dwErr = GetLastError();
Error(HRESULT_FROM_WIN32(dwErr), L"GetTempFileName failed due to error %d.\n", dwErr);
}
if (!CopyFile(wszSavedFile, bstrTempFileName, FALSE))
{
DWORD dwErr = GetLastError();
Error(HRESULT_FROM_WIN32(dwErr), L"CopyFile failed due to error %d.\n", dwErr);
}
if (!MoveFileEx
(
bstrTempFileName,
wszRestoreFile,
MOVEFILE_DELAY_UNTIL_REBOOT|MOVEFILE_REPLACE_EXISTING
))
{
DWORD dwErr = GetLastError();
Error(HRESULT_FROM_WIN32(dwErr), L"MoveFileEx failed due to error %d.\n", dwErr);
}
info.bRebootRequired = true;
}
else if (info.method == VSS_RME_RESTORE_IF_NOT_THERE)
{
HANDLE hFile = CreateFile
(
wszRestoreFile,
GENERIC_WRITE,
0,
NULL,
CREATE_NEW,
0,
NULL
);
// assume if the create fails
if (hFile == INVALID_HANDLE_VALUE)
{
DWORD dwErr = GetLastError();
if (dwErr == ERROR_FILE_EXISTS)
return false;
else
Error(HRESULT_FROM_WIN32(dwErr), L"CreateFile failed due to error %d.\n", dwErr);
}
pFile->SetDestinationHandle(hFile);
}
else if (info.method == VSS_RME_RESTORE_IF_CAN_REPLACE)
{
HANDLE hFile = CreateFile
(
wszRestoreFile,
GENERIC_WRITE|GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
0,
NULL
);
if (hFile == INVALID_HANDLE_VALUE)
{
DWORD dwErr = GetLastError();
if (dwErr == ERROR_SHARING_VIOLATION ||
dwErr == ERROR_USER_MAPPED_FILE ||
dwErr == ERROR_LOCK_VIOLATION)
return false;
else
Error(HRESULT_FROM_WIN32(dwErr), L"CreateFile failed due to error %d.\n", dwErr);
}
pFile->SetDestinationHandle(hFile);
pFile->SetSourceFile(wszSavedFile);
}
info.pFile = pFile;
return true;
}
void TranslateRestorePath
(
RESTORE_INFO &info,
CComBSTR &bstrRP,
LPCWSTR wszFilename
)
{
ALTERNATE_MAPPING *pMapping = NULL;
UINT cwc = 0, cwcMapping = 0;
for(unsigned iMapping = 0; iMapping < info.cMappings; iMapping++)
{
pMapping = &info.rgMappings[iMapping];
cwc = (UINT) wcslen(bstrRP);
cwcMapping = (UINT) wcslen(pMapping->bstrPath);
if (cwc < cwcMapping)
continue;
if (_wcsnicmp(bstrRP, pMapping->bstrPath, cwcMapping) != 0)
continue;
if (cwcMapping != cwc && !pMapping->bRecursive)
continue;
BOOL bReplacePath = FALSE;
LPCWSTR wszFilespec = pMapping->bstrFilespec;
if (wcscmp(wszFilespec, L"*") == 0 ||
wcscmp(wszFilespec, L"*.*") == 0)
bReplacePath = true;
else if (wcschr(wszFilespec, L'*') == NULL)
bReplacePath = _wcsicmp(wszFilespec, wszFilename) == 0;
else if (wcsncmp(wszFilespec, L"*.", 2) == 0)
{
LPCWSTR wszSuffix = wcschr(wszFilename, L'.');
if (wszSuffix == NULL)
bReplacePath = wcslen(wszFilespec) == 2;
else
bReplacePath = _wcsicmp(wszSuffix, wszFilespec + 1) == 0;
}
else
{
UINT cwcFilespec = (UINT) wcslen(wszFilespec);
if (cwcFilespec > 2 &&
_wcsicmp(wszFilespec + cwcFilespec - 2, L".*") == 0)
{
if (wcslen(wszFilename) >= cwcFilespec - 1)
bReplacePath = _wcsnicmp(wszFilename, wszFilespec, cwcFilespec - 1) == 0;
}
}
if (bReplacePath)
{
if (cwcMapping == cwc)
bstrRP = pMapping->bstrAlternatePath;
else
{
CComBSTR bstr;
bstr.Append(pMapping->bstrAlternatePath);
bstr.Append(bstrRP + cwcMapping);
bstrRP = bstr;
}
break;
}
}
}
bool SetupRestoreFilesMatchingFilespec
(
RESTORE_INFO &info,
LPCWSTR wszSourcePath,
LPCWSTR wszRestorePath,
LPCWSTR wszFilespec
)
{
CComBSTR bstrSP = wszSourcePath;
bstrSP.Append(L"\\");
bstrSP.Append(wszFilespec);
WIN32_FIND_DATA findData;
HANDLE hFile = FindFirstFile(bstrSP, &findData);
if (hFile == INVALID_HANDLE_VALUE)
return true;
try
{
do
{
if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
{
CComBSTR bstrRP = wszRestorePath;
bstrSP = wszSourcePath;
bstrSP.Append(L"\\");
bstrSP.Append(findData.cFileName);
if (info.method == VSS_RME_RESTORE_TO_ALTERNATE_LOCATION)
TranslateRestorePath(info, bstrRP, findData.cFileName);
bstrRP.Append(L"\\");
bstrRP.Append(findData.cFileName);
if (!SetupRestoreFile(info, bstrSP, bstrRP))
return false;
}
} while(FindNextFile(hFile, &findData));
FindClose(hFile);
}
catch(...)
{
FindClose(hFile);
throw;
}
return true;
}
bool RecursiveRestoreFiles
(
RESTORE_INFO &info,
LPCWSTR wszSavedPath,
LPCWSTR wszPath,
LPCWSTR wszFilespec
)
{
CComBSTR bstrSP = wszSavedPath;
bstrSP.Append(L"\\*.*");
WIN32_FIND_DATA findData;
HANDLE hFile = FindFirstFile(bstrSP, &findData);
if (hFile == INVALID_HANDLE_VALUE)
return true;
try
{
do
{
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if (wcscmp(findData.cFileName, L".") == 0 ||
wcscmp(findData.cFileName, L"..") == 0)
continue;
bstrSP = wszSavedPath;
bstrSP.Append(L"\\");
bstrSP.Append(findData.cFileName);
CComBSTR bstrRP = wszPath;
bstrRP.Append(L"\\");
bstrRP.Append(findData.cFileName);
if (!SetupRestoreFilesMatchingFilespec(info, bstrSP, bstrRP, wszFilespec))
return false;
if (!RecursiveRestoreFiles(info, bstrSP, bstrRP, wszFilespec))
return false;
}
} while(FindNextFile(hFile, &findData));
FindClose(hFile);
}
catch(...)
{
FindClose(hFile);
throw;
}
return true;
}
bool SetupRestoreDataFiles(RESTORE_INFO &info, IVssWMFiledesc *pFiledesc)
{
HRESULT hr;
CComBSTR bstrPath;
CComBSTR bstrFilespec;
bool bRecursive;
CHECK_SUCCESS(pFiledesc->GetPath(&bstrPath));
CHECK_SUCCESS(pFiledesc->GetFilespec(&bstrFilespec));
CHECK_NOFAIL(pFiledesc->GetRecursive(&bRecursive));
CComBSTR bstrSavedPath;
BuildSavedPath(bstrPath, bstrSavedPath);
if (!SetupRestoreFilesMatchingFilespec(info, bstrSavedPath, bstrPath, bstrFilespec))
return false;
if (bRecursive)
return RecursiveRestoreFiles(info, bstrSavedPath, bstrPath, bstrFilespec);
return true;
}
bool SetupRestoreDataFilesForComponent(RESTORE_INFO& info, IVssWMComponent* pComponent)
{
HRESULT hr = S_OK;
PVSSCOMPONENTINFO pInfo = NULL;
CHECK_SUCCESS(pComponent->GetComponentInfo(&pInfo));
for(UINT iFile = 0; iFile < pInfo->cFileCount; iFile++)
{
CComPtr<IVssWMFiledesc> pFiledesc;
CHECK_SUCCESS(pComponent->GetFile(iFile, &pFiledesc));
if (!SetupRestoreDataFiles(info, pFiledesc))
{
pComponent->FreeComponentInfo(pInfo);
return false;
}
}
for(iFile = 0; iFile < pInfo->cDatabases; iFile++)
{
CComPtr<IVssWMFiledesc> pFiledesc;
CHECK_SUCCESS(pComponent->GetDatabaseFile(iFile, &pFiledesc));
if (!SetupRestoreDataFiles(info, pFiledesc))
{
pComponent->FreeComponentInfo(pInfo);
return false;
}
}
for(iFile = 0; iFile < pInfo->cLogFiles; iFile++)
{
CComPtr<IVssWMFiledesc> pFiledesc;
CHECK_SUCCESS(pComponent->GetDatabaseLogFile(iFile, &pFiledesc));
if (!SetupRestoreDataFiles(info, pFiledesc))
{
pComponent->FreeComponentInfo(pInfo);
return false;
}
}
pComponent->FreeComponentInfo(pInfo);
return true;
}
void LoadMetadataFile(VSS_ID idInstance, IVssExamineWriterMetadata **ppMetadataSaved)
{
HRESULT hr;
// load saved metadata
CVssAutoWin32Handle hFile = OpenMetadataFile(idInstance, false);
DWORD dwSize = GetFileSize(hFile, NULL);
if (dwSize == 0xffffffff)
{
DWORD dwErr = GetLastError();
Error(HRESULT_FROM_WIN32(dwErr), L"GetFileSize failed with error %d.\n", dwErr);
}
CComBSTR bstrXML(dwSize/sizeof(WCHAR));
DWORD dwRead;
if(!ReadFile(hFile, bstrXML, dwSize, &dwRead, NULL))
{
DWORD dwErr = GetLastError();
Error(HRESULT_FROM_WIN32(dwErr), L"ReadFile failed with error %d.\n", dwErr);
}
// null terminate XML string
bstrXML[dwSize/sizeof(WCHAR)] = L'\0';
CHECK_SUCCESS(CreateVssExamineWriterMetadata(bstrXML, ppMetadataSaved));
}
void RestoreComponentFiles(RESTORE_INFO &info)
{
HRESULT hr;
PVSSCOMPONENTINFO pInfo = NULL;
CComPtr<IVssWMComponent> pComponent;
VSS_FILE_RESTORE_STATUS status = VSS_RS_NONE;
try
{
CComBSTR bstrUserProcedure;
CComBSTR bstrService;
bool bRebootRequired;
VSS_WRITERRESTORE_ENUM writerRestore;
IVssExamineWriterMetadata *pMetadata;
UINT cIncludeFiles, cExcludeFiles, cComponents;
CHECK_SUCCESS(info.pMetadataSaved->GetFileCounts(&cIncludeFiles, &cExcludeFiles, &cComponents));
for (UINT iComponent = 0; iComponent < cComponents; iComponent++)
{
CHECK_SUCCESS(info.pMetadataSaved->GetComponent(iComponent, &pComponent));
CHECK_SUCCESS(pComponent->GetComponentInfo(&pInfo));
if (wcscmp(pInfo->bstrComponentName, info.wszComponentName) == 0)
{
if ((!info.wszLogicalPath && !pInfo->bstrLogicalPath) ||
(info.wszLogicalPath && pInfo->bstrLogicalPath &&
wcscmp(info.wszLogicalPath, pInfo->bstrLogicalPath) == 0))
break;
}
pComponent->FreeComponentInfo(pInfo);
pInfo = NULL;
pComponent = NULL;
}
pMetadata = info.pMetadataSaved;
BS_ASSERT(pComponent != NULL);
CHECK_NOFAIL(pMetadata->GetRestoreMethod
(
&info.method,
&bstrService,
&bstrUserProcedure,
&writerRestore,
&bRebootRequired,
&info.cMappings
));
// cannot do anything with custom method
if (info.method == VSS_RME_CUSTOM)
{
pComponent->FreeComponentInfo(pInfo);
return;
}
BS_ASSERT(info.method != VSS_RME_STOP_RESTORE_START);
if (info.rgMappings == NULL)
{
if (info.cMappings > 0)
{
info.rgMappings = new ALTERNATE_MAPPING[info.cMappings];
if (info.rgMappings == NULL)
Error(E_OUTOFMEMORY, L"OutOfMemory");
}
for(unsigned iMapping = 0; iMapping < info.cMappings; iMapping++)
{
CComPtr<IVssWMFiledesc> pFiledesc;
CHECK_SUCCESS(pMetadata->GetAlternateLocationMapping(iMapping, &pFiledesc));
CHECK_SUCCESS(pFiledesc->GetPath(&info.rgMappings[iMapping].bstrPath));
DoExpandEnvironmentStrings(info.rgMappings[iMapping].bstrPath);
CHECK_SUCCESS(pFiledesc->GetAlternateLocation(&info.rgMappings[iMapping].bstrAlternatePath));
DoExpandEnvironmentStrings(info.rgMappings[iMapping].bstrAlternatePath);
CHECK_SUCCESS(pFiledesc->GetFilespec(&info.rgMappings[iMapping].bstrFilespec));
CHECK_SUCCESS(pFiledesc->GetRecursive(&info.rgMappings[iMapping].bRecursive));
}
}
if (info.method == VSS_RME_RESTORE_IF_NOT_THERE ||
info.method == VSS_RME_RESTORE_IF_CAN_REPLACE)
{
if (info.pCopyBuf == NULL)
{
info.pCopyBuf = new BYTE[COPYBUFSIZE];
if (info.pCopyBuf == NULL)
Error(E_OUTOFMEMORY, L"Out of Memory");
}
}
_retry:
info.pFile = NULL;
bool bFailRestore = false;
// setup restore data files for the current component
bFailRestore = !SetupRestoreDataFilesForComponent(info, pComponent);
// setup restore data files for all subcomponents
UINT cSubcomponents = 0;
CHECK_SUCCESS(info.pComponent->GetRestoreSubcomponentCount(&cSubcomponents));
for (UINT iSubcomponent = 0; !bFailRestore && iSubcomponent < cSubcomponents; iSubcomponent++)
{
CComBSTR bstrSubLogicalPath, bstrSubName;
bool foo;
CHECK_SUCCESS(info.pComponent->GetRestoreSubcomponent(iSubcomponent, &bstrSubLogicalPath,
&bstrSubName, &foo));
CComPtr<IVssWMComponent> pSubcomponent;
if (!FindComponent(pMetadata, bstrSubLogicalPath, bstrSubName, &pSubcomponent))
Error(E_UNEXPECTED, L"an invalid subcomponent was selected");
bFailRestore = !SetupRestoreDataFilesForComponent(info, pSubcomponent);
}
// calculate the full path to the current component
CComBSTR fullPath = info.wszLogicalPath;
if (fullPath)
fullPath += L"\\";
fullPath += info.wszComponentName;
if (!fullPath)
Error(E_OUTOFMEMORY, L"Out of memory!");
// setup restore data files for all subcomponents
for (UINT iComponent = 0; !cSubcomponents && !bFailRestore && iComponent < cComponents; iComponent++)
{
CComPtr<IVssWMComponent> pCurrentComponent;
PVSSCOMPONENTINFO pCurrentInfo;
CHECK_SUCCESS(pMetadata->GetComponent(iComponent, &pCurrentComponent));
CHECK_SUCCESS(pCurrentComponent->GetComponentInfo(&pCurrentInfo));
if (pCurrentInfo->bstrLogicalPath &&
wcsstr(pCurrentInfo->bstrLogicalPath, fullPath) == pCurrentInfo->bstrLogicalPath)
{
bFailRestore = !SetupRestoreDataFilesForComponent(info, pCurrentComponent);
}
pCurrentComponent->FreeComponentInfo(pCurrentInfo);
}
if (!bFailRestore)
{
status = VSS_RS_FAILED;
CompleteRestore(info);
status = VSS_RS_ALL;
if (bRebootRequired)
info.bRebootRequired = true;
}
else
{
CleanupFailedRestore(info);
if ((info.method == VSS_RME_RESTORE_IF_NOT_THERE ||
info.method == VSS_RME_RESTORE_IF_CAN_REPLACE) &&
info.cMappings > 0)
{
info.method = VSS_RME_RESTORE_TO_ALTERNATE_LOCATION;
goto _retry;
}
}
pComponent->FreeComponentInfo(pInfo);
pInfo = NULL;
pComponent = NULL;
}
catch(...)
{
pComponent->FreeComponentInfo(pInfo);
throw;
}
CHECK_SUCCESS(info.pvbc->SetFileRestoreStatus
(
info.idWriter,
info.ct,
info.wszLogicalPath,
info.wszComponentName,
status
));
}
void RestoreFiles(IVssBackupComponents *pvbc, const CSimpleMap<VSS_ID, HRESULT>& failedWriters)
{
RESTORE_INFO info;
HRESULT hr;
UINT cWriterComponents = 0, cWriters = 0;
info.pvbc = pvbc;
CHECK_SUCCESS(pvbc->GetWriterComponentsCount(&cWriterComponents));
CHECK_SUCCESS(pvbc->GetWriterMetadataCount(&cWriters));
info.pvbc = pvbc;
for(unsigned iWriter = 0; iWriter < cWriterComponents; iWriter++)
{
CComPtr<IVssWriterComponentsExt> pWriter;
CComPtr<IVssExamineWriterMetadata> pMetadata = NULL;
CComPtr<IVssExamineWriterMetadata> pMetadataSaved = NULL;
CHECK_SUCCESS(pvbc->GetWriterComponents(iWriter, &pWriter));
unsigned cComponents;
CHECK_SUCCESS(pWriter->GetComponentCount(&cComponents));
for(unsigned iComponent = 0; iComponent < cComponents; iComponent++)
{
CComPtr<IVssComponent> pComponent;
bool bSelectedForRestore = false;
CHECK_SUCCESS(pWriter->GetComponent(iComponent, &pComponent));
CHECK_NOFAIL(pComponent->IsSelectedForRestore(&bSelectedForRestore));
if (bSelectedForRestore)
break;
UINT cSubcomponents = 0;
CHECK_SUCCESS(pComponent->GetRestoreSubcomponentCount(&cSubcomponents));
if (cSubcomponents > 0)
break;
CComBSTR bstrOptions;
CHECK_NOFAIL(pComponent->GetRestoreOptions(&bstrOptions));
if (bstrOptions.Length() != 0 && wcscmp(bstrOptions, L"RESTORE") == 0)
break;
}
if (iComponent >= cComponents)
continue;
CHECK_SUCCESS(pWriter->GetWriterInfo(&info.idInstance, &info.idWriter));
for(unsigned iWriter = 0; iWriter < cWriters; iWriter++)
{
VSS_ID idInstance, idWriter;
CComBSTR bstrWriterName;
VSS_USAGE_TYPE usage;
VSS_SOURCE_TYPE source;
CHECK_SUCCESS(pvbc->GetWriterMetadata(iWriter, &idInstance, &pMetadata));
CHECK_SUCCESS
(
pMetadata->GetIdentity
(
&idInstance,
&idWriter,
&bstrWriterName,
&usage,
&source
)
);
if (idWriter == info.idWriter)
break;
pMetadata = NULL;
}
// load saved metadata
LoadMetadataFile(info.idInstance, &pMetadataSaved);
info.pMetadataWriter = pMetadata;
info.pMetadataSaved = pMetadataSaved;
bool bWriterFailed = failedWriters.Lookup(info.idInstance) != NULL;
for(unsigned iComponent = 0; iComponent < cComponents; iComponent++)
{
CComPtr<IVssComponent> pComponent;
CHECK_SUCCESS(pWriter->GetComponent(iComponent, &pComponent));
bool bSelectedForRestore = false;
CHECK_NOFAIL(pComponent->IsSelectedForRestore(&bSelectedForRestore));
UINT cSubcomponents = 0;
CHECK_SUCCESS(pComponent->GetRestoreSubcomponentCount(&cSubcomponents));
if (!bSelectedForRestore && cSubcomponents == 0)
{
// BUGBUG: huge hack to fix the AD case. We eventually need to
// BUGBUG: do something better here
CComBSTR bstrOptions;
CHECK_NOFAIL(pComponent->GetRestoreOptions(&bstrOptions));
if (bstrOptions.Length() == 0 || wcscmp(bstrOptions, L"RESTORE") != 0)
continue;
}
CComBSTR bstrLogicalPath;
CComBSTR bstrComponentName;
CHECK_NOFAIL(pComponent->GetLogicalPath(&bstrLogicalPath));
CHECK_SUCCESS(pComponent->GetComponentType(&info.ct));
CHECK_SUCCESS(pComponent->GetComponentName(&bstrComponentName));
CComBSTR bstrPreRestoreFailure;
CHECK_NOFAIL(pComponent->GetPreRestoreFailureMsg(&bstrPreRestoreFailure));
if (bstrPreRestoreFailure)
{
wprintf
(
L"Not restoring Component %s\\%s because PreRestore failed:\n%s\n",
bstrLogicalPath,
bstrComponentName,
bstrPreRestoreFailure
);
continue;
}
else if (bWriterFailed)
{
wprintf
(
L"Not restoring Component %s\\%s because PreRestore failed:\n\n",
bstrLogicalPath,
bstrComponentName
);
continue;
}
info.pComponent = pComponent;
info.wszLogicalPath = bstrLogicalPath;
info.wszComponentName = bstrComponentName;
RestoreComponentFiles(info);
}
// mappings are on a per writer basis and need to be cleared
// when advancing to a new writer
delete [] info.rgMappings;
info.rgMappings = NULL;
info.cMappings = 0;
}
if (info.bRebootRequired)
wprintf(L"\n\n!!REBOOT is Required to complete the restore operation.\n\n");
}