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.
 
 
 
 
 
 

1208 lines
30 KiB

//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: restore.cpp
//
// Contents: Cert Server client database restore APIs
//
//---------------------------------------------------------------------------
#include <pch.cpp>
#pragma hdrstop
#include "certsrvd.h"
#include "csdisp.h"
#include "certadmp.h"
#define __dwFILE__ __dwFILE_CERTADM_RESTORE_CPP__
extern WCHAR g_wszRestoreAnnotation[];
//+--------------------------------------------------------------------------
// CertSrvServerControl -- send a control command to the cert server.
//
// Parameters:
// [in] pwszConfig - name or config string of the server to control
// [in] dwControlFlags - control command and flags
// [out] pcbOut - pointer to receive the size of command output data
// [out] ppbOut - pointer to receive command output data. Use the
// CertSrvBackupFree() API to free the buffer.
//
// Returns:
// S_OK if the call executed successfully;
// Failure code otherwise.
//+--------------------------------------------------------------------------
HRESULT
CERTBCLI_API
CertSrvServerControlW(
IN WCHAR const *pwszConfig,
IN DWORD dwControlFlags,
OPTIONAL OUT DWORD *pcbOut,
OPTIONAL OUT BYTE **ppbOut)
{
HRESULT hr;
ICertAdminD2 *pICertAdminD = NULL;
DWORD dwServerVersion;
WCHAR const *pwszAuthority;
CERTTRANSBLOB ctbOut = { 0, NULL };
if (NULL != pcbOut)
{
*pcbOut = 0;
}
if (NULL != ppbOut)
{
*ppbOut = NULL;
}
if (NULL == pwszConfig)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
hr = S_OK;
__try
{
hr = OpenAdminServer(
pwszConfig,
&pwszAuthority,
&dwServerVersion,
&pICertAdminD);
_LeaveIfError(hr, "OpenAdminServer");
hr = pICertAdminD->ServerControl(
pwszAuthority,
dwControlFlags,
&ctbOut);
_LeaveIfError(hr, "ServerControl");
if (NULL != ctbOut.pb && NULL != ppbOut)
{
*ppbOut = (BYTE *) LocalAlloc(LMEM_FIXED, ctbOut.cb);
if (NULL == *ppbOut)
{
hr = E_OUTOFMEMORY;
_LeaveError(hr, "LocalAlloc");
}
CopyMemory(*ppbOut, ctbOut.pb, ctbOut.cb);
if (NULL != pcbOut)
{
*pcbOut = ctbOut.cb;
}
}
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
}
error:
if (NULL != ctbOut.pb)
{
CoTaskMemFree(ctbOut.pb);
}
if (NULL != pICertAdminD)
{
CloseAdminServer(&pICertAdminD);
}
return(hr);
}
//+--------------------------------------------------------------------------
// CertSrvRestorePrepare -- indicate beginning of a restore session.
//
// Parameters:
// [in] pwszConfig - name of the server into which the restore
// operation is going to be performed.
// [in] dwRestoreFlags - Or'ed combination of RESTORE_TYPE_* flags; 0 if
// no special flags are to be specified
// [out] phbc - pointer to receive the backup context handle which is to
// be passed to the subsequent restore APIs
//
// Returns:
// S_OK if the call executed successfully;
// Failure code otherwise.
//---------------------------------------------------------------------------
HRESULT
CERTBCLI_API
CertSrvRestorePrepareW(
IN WCHAR const *pwszConfig,
IN ULONG dwRestoreFlags,
OUT HCSBC *phbc)
{
HRESULT hr;
CSBACKUPCONTEXT *pcsbc = NULL;
if (NULL == pwszConfig || NULL == phbc)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
*phbc = NULL;
if (~CSRESTORE_TYPE_FULL & dwRestoreFlags)
{
hr = E_INVALIDARG;
_JumpError(hr, error, "dwRestoreFlags");
}
hr = AllocateContext(pwszConfig, &pcsbc);
_JumpIfError(hr, error, "AllocateContext");
pcsbc->RestoreFlags = dwRestoreFlags;
*phbc = (HCSBC) pcsbc;
pcsbc = NULL;
error:
if (NULL != pcsbc)
{
ReleaseContext(pcsbc);
}
return(hr);
}
//+--------------------------------------------------------------------------
// CertSrvRestoreGetDatabaseLocations -- called both at backup time as well as at
// restore time to get data base locations for different types of files.
//
// Parameters:
// [in] hbc - backup context handle which would have been obtained
// through CertSrvBackupPrepare in the backup case and through
// CertSrvRestorePrepare in the restore case.
// [out] ppwszzFileList - pointer that will receive the pointer
// to the list of database locations; allocated memory should be
// freed using CertSrvBackupFree() API by the caller when it is no
// longer needed; locations are returned in an array of null
// terminated names and and the list is terminated by two L'\0's.
// The first character of each name is the BFT character that
// indicates the type of the file and the rest of the name tells
// gives the path into which that particular type of file should
// be restored.
// [out] pcbList - will receive the number of bytes returned
//
// Returns:
// S_OK if the call executed successfully;
// Failure code otherwise.
//
// Note:
// This API returns only the fully qualified path of the databases, not the
// name of the databases.
//---------------------------------------------------------------------------
HRESULT
CERTBCLI_API
CertSrvRestoreGetDatabaseLocationsW(
IN HCSBC hbc,
OUT WCHAR **ppwszzFileList,
OUT DWORD *pcbList)
{
HRESULT hr;
if (NULL == hbc)
{
hr = E_HANDLE;
_JumpError(hr, error, "NULL handle");
}
if (NULL == ppwszzFileList || NULL == pcbList)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
hr = S_OK;
__try
{
hr = BackupRestoreGetFileList(
FLT_RESTOREDBLOCATIONS,
hbc,
ppwszzFileList,
pcbList);
_LeaveIfError(hr, "BackupRestoreGetFileList");
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
}
error:
return(hr);
}
HRESULT
CleanupOldLogs(
OPTIONAL IN WCHAR const *pwszConfig,
OPTIONAL IN HKEY hkey,
OPTIONAL IN WCHAR const *pwszLogPath,
IN ULONG genLow,
IN ULONG genHigh)
{
HRESULT hr;
DWORD cb;
DWORD dwType;
HANDLE hFind = INVALID_HANDLE_VALUE;
WCHAR *pwsz;
WCHAR *pwszLogPathUNC = NULL;
WCHAR *pwszLogPathLocal = NULL;
WCHAR *pwszLogPathWild = NULL;
WIN32_FIND_DATA wfd;
WCHAR wszServer[MAX_PATH];
WCHAR wszLogFileName[2 * MAX_PATH]; // UNC logfile name
WCHAR *pwszFileName; // filename (edb0006A.log)
if (genHigh < genLow)
{
hr = E_INVALIDARG;
_JumpError(hr, error, "bad parm");
}
wszServer[0] = L'\0';
if (NULL != pwszConfig)
{
// Allow UNC-style config strings: \\server\CAName
while (L'\\' == *pwszConfig)
{
pwszConfig++;
}
wcscpy(wszServer, pwszConfig);
pwsz = wcschr(wszServer, L'\\');
if (NULL != pwsz)
{
*pwsz = L'\0';
}
}
// If the Log Path wasn't passed in, fetch it from the server's registry
if (NULL == pwszLogPath)
{
if (NULL == hkey)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
cb = sizeof(wszLogFileName);
hr = RegQueryValueEx(
hkey,
wszREGDBLOGDIRECTORY,
0,
&dwType,
(BYTE *) wszLogFileName,
&cb);
_JumpIfError(hr, error, "RegQueryValueEx");
// Assume remote access -- convert to UNC path
hr = myConvertLocalPathToUNC(
wszServer,
wszLogFileName,
&pwszLogPathUNC);
_JumpIfError(hr, error, "myConvertLocalPathToUNC");
pwszLogPath = pwszLogPathUNC;
}
// If local machine -- convert UNC path to Local Path
if (NULL == pwszConfig)
{
hr = myConvertUNCPathToLocal(pwszLogPath, &pwszLogPathLocal);
_JumpIfError(hr, error, "myConvertUNCPathToLocal");
pwszLogPath = pwszLogPathLocal;
}
// copy the LogPath -- it's of the form "\\server\c$\winnt\ntlog" or
// "c:\winnt\ntlog", possibly with a trailing backslash
//
// make two copies of the logpath - one to pass a wildcard string for
// searching and other to create filenames with full path for the logfiles
hr = myBuildPathAndExt(
pwszLogPath,
L"edb*.log",
NULL, // pwszExt
&pwszLogPathWild);
_JumpIfError(hr, error, "myBuildPathAndExt");
// make pwszFileName point past the last backslash in wszLogFileName
wcscpy(wszLogFileName, pwszLogPathWild);
pwszFileName = wcsrchr(wszLogFileName, L'\\');
CSASSERT(NULL != pwszFileName);
pwszFileName++;
hFind = FindFirstFile(pwszLogPathWild, &wfd);
if (INVALID_HANDLE_VALUE != hFind)
{
do
{
// wfd.cFileName points to the name of edb*.log file found
ULONG ulLogNo = wcstoul(wfd.cFileName + 3, NULL, 16);
if (ulLogNo < genLow || ulLogNo > genHigh)
{
// This is an old logfile which was not copied down by ntbackup
// -- clean it up. First append the filename to the logpath
// (Note: pwszFileName already points past the end of the final
// backslash in logpath). Then delete the file by passing in
// the full path.
wcscpy(pwszFileName, wfd.cFileName);
//printf("Deleting: %ws\n", wszLogFileName);
if (!DeleteFile(wszLogFileName))
{
// Unable to delete the old logfile; not cleaning up will
// cause problems later. Return failure code.
hr = myHLastError();
_JumpError(hr, error, "DeleteFile");
}
}
} while (FindNextFile(hFind, &wfd));
hr = myHLastError();
if (HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES) != hr)
{
// we came out of the loop for some unexpected error -- return the
// error code.
_JumpError(hr, error, "FindNextFile");
}
}
hr = S_OK;
error:
if (NULL != pwszLogPathUNC)
{
LocalFree(pwszLogPathUNC);
}
if (NULL != pwszLogPathLocal)
{
LocalFree(pwszLogPathLocal);
}
if (NULL != pwszLogPathWild)
{
LocalFree(pwszLogPathWild);
}
if (INVALID_HANDLE_VALUE != hFind)
{
FindClose(hFind);
}
return(hr);
}
//+--------------------------------------------------------------------------
// CertSrvRestoreRegister -- register a restore operation. It will interlock all
// subsequent restore operations, and will prevent the restore target from
// starting until the call to CertSrvRestoreRegisterComplete is made.
//
// Parameters:
// [in] hbc - backup context handle for the restore session.
// [in] pwszCheckPointFilePath - path to restore the check point files
// [in] pwszLogPath - path where the log files are restored
// [in] rgrstmap - restore map
// [in] crstmap - tells if there is a new restore map
// [in] pwszBackupLogPath - path where the backup logs are located
// [in] genLow - Lowest log# that was restored in this restore session
// [in] genHigh - Highest log# that was restored in this restore session
//
// Returns:
// S_OK if the call executed successfully;
// Failure code otherwise.
//---------------------------------------------------------------------------
HRESULT
CERTBCLI_API
CertSrvRestoreRegisterW(
OPTIONAL IN HCSBC hbc,
OPTIONAL IN WCHAR const *pwszCheckPointFilePath,
OPTIONAL IN WCHAR const *pwszLogPath,
OPTIONAL IN CSEDB_RSTMAPW rgrstmap[],
IN LONG crstmap,
OPTIONAL IN WCHAR const *pwszBackupLogPath,
IN ULONG genLow,
IN ULONG genHigh)
{
HRESULT hr;
WCHAR const *pwszConfig = NULL;
HKEY hkey = NULL;
HKEY hkeyRestore = NULL;
WCHAR *pwszPath = NULL;
DWORD cwcRstMap;
WCHAR *pwszRstMap = NULL;
WCHAR *pwsz;
LONG i;
DWORD dwDisposition;
DWORD dwType;
DWORD cbGen;
ULONG genCurrent;
BOOLEAN fDatabaseRecovered = FALSE;
#if DBG_CERTSRV
if (NULL != getenv("certsrv_CertSrvRestoreRegisterThroughFile"))
{
hr = E_ACCESSDENIED;
_JumpError(hr, error, "force CertSrvRestoreRegisterThroughFile");
}
#endif
if (0 != crstmap && NULL == rgrstmap)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
if (NULL != hbc)
{
CSBACKUPCONTEXT *pcsbc = (CSBACKUPCONTEXT *) hbc;
pwszConfig = pcsbc->pwszConfig;
}
hr = myRegOpenRelativeKey(
pwszConfig,
L"",
RORKF_CREATESUBKEYS,
&pwszPath,
NULL, // ppwszName
&hkey);
// If the registry key doesn't exist, and we're restoring the local
// machine, create it now. The rest of the registry will be restored
// prior to starting the cert server to recover the cert server database.
if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
{
BOOL fLocal = TRUE;
if (NULL != pwszConfig)
{
hr = myIsConfigLocal(pwszConfig, NULL, &fLocal);
_JumpIfErrorStr(hr, error, "myIsConfigLocal", pwszConfig);
}
if (fLocal)
{
hr = RegCreateKeyEx(
HKEY_LOCAL_MACHINE,
wszREGKEYCONFIGPATH,
0, // Reserved
NULL, // lpClass
0, // dwOptions
KEY_ALL_ACCESS,
NULL,
&hkey,
&dwDisposition);
_JumpIfError(hr, error, "RegCreateKeyEx");
}
else
{
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
}
}
_JumpIfErrorStr(hr, error, "myRegOpenRelativeKey", pwszConfig);
hr = RegCreateKeyEx(
hkey,
wszREGKEYRESTOREINPROGRESS,
0, // Reserved
NULL, // lpClass
0, // dwOptions
KEY_ALL_ACCESS,
NULL,
&hkeyRestore,
&dwDisposition);
_JumpIfError(hr, error, "RegCreateKeyEx");
// Seed the restore-in-progress in the registry.
hr = CERTSRV_E_SERVER_SUSPENDED;
hr = RegSetValueEx(
hkeyRestore,
wszREGRESTORESTATUS,
0,
REG_DWORD,
(BYTE *) &hr,
sizeof(DWORD));
_JumpIfError(hr, error, "RegSetValueEx");
// We've now interlocked other restore operations from coming in from other
// machines.
if (0 != crstmap)
{
// Full backup:
//
// The restore map should only be set on a full backup. If there's
// already a restore map size (or restore map), then this full backup
// is overriding a previously incomplete full backup.
// Save away the size of the restore map.
hr = RegSetValueEx(
hkeyRestore,
wszREGRESTOREMAPCOUNT,
0,
REG_DWORD,
(BYTE *) &crstmap,
sizeof(DWORD));
// We now need to convert the restore map into one that we can put
// into the registry. First figure out how big it will be.
cwcRstMap = 1;
for (i = 0 ; i < crstmap ; i++)
{
cwcRstMap +=
myLocalPathwcslen(rgrstmap[i].pwszDatabaseName) + 1 +
myLocalPathwcslen(rgrstmap[i].pwszNewDatabaseName) + 1;
}
pwszRstMap = (WCHAR *) LocalAlloc(
LMEM_FIXED,
cwcRstMap * sizeof(WCHAR));
if (NULL == pwszRstMap)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
pwsz = pwszRstMap;
for (i = 0 ; i < crstmap ; i++)
{
myLocalPathwcscpy(pwsz, rgrstmap[i].pwszDatabaseName);
pwsz += wcslen(pwsz) + 1;
myLocalPathwcscpy(pwsz, rgrstmap[i].pwszNewDatabaseName);
pwsz += wcslen(pwsz) + 1;
}
*pwsz++ = L'\0';
hr = RegSetValueEx(
hkeyRestore,
wszREGRESTOREMAP,
0,
REG_MULTI_SZ,
(BYTE *) pwszRstMap,
SAFE_SUBTRACT_POINTERS(
(BYTE *) pwsz,
(BYTE *) pwszRstMap));
}
else
{
// Incremental backup:
//
// Fail if no restore map exists -- Insist that a full backup be in
// progress...
cbGen = sizeof(genCurrent);
hr = RegQueryValueEx(
hkeyRestore,
wszREGRESTOREMAPCOUNT,
0,
&dwType,
(BYTE *) &genCurrent,
&cbGen);
_JumpIfError(hr, error, "RegQueryValueEx");
// Expand genLow and genHigh to include previously registered log files
cbGen = sizeof(genCurrent);
hr = RegQueryValueEx(
hkeyRestore,
wszREGLOWLOGNUMBER,
0,
&dwType,
(BYTE *) &genCurrent,
&cbGen);
if (S_OK == hr &&
REG_DWORD == dwType &&
sizeof(genCurrent) == cbGen &&
genLow > genCurrent)
{
genLow = genCurrent;
}
cbGen = sizeof(genCurrent);
hr = RegQueryValueEx(
hkeyRestore,
wszREGHIGHLOGNUMBER,
0,
&dwType,
(BYTE *) &genCurrent,
&cbGen);
if (S_OK == hr &&
REG_DWORD == dwType &&
sizeof(genCurrent) == cbGen &&
genHigh < genCurrent)
{
genHigh = genCurrent;
}
}
hr = RegSetValueEx(
hkeyRestore,
wszREGLOWLOGNUMBER,
0,
REG_DWORD,
(BYTE *) &genLow,
sizeof(DWORD));
_JumpIfError(hr, error, "RegSetValueEx");
hr = RegSetValueEx(
hkeyRestore,
wszREGHIGHLOGNUMBER,
0,
REG_DWORD,
(BYTE *) &genHigh,
sizeof(DWORD));
_JumpIfError(hr, error, "RegSetValueEx");
if (NULL != pwszBackupLogPath)
{
hr = mySetRegistryLocalPathString(
hkeyRestore,
wszREGBACKUPLOGDIRECTORY,
pwszBackupLogPath);
_JumpIfError(hr, error, "mySetRegistryLocalPathString");
}
if (NULL != pwszCheckPointFilePath)
{
hr = mySetRegistryLocalPathString(
hkeyRestore,
wszREGCHECKPOINTFILE,
pwszCheckPointFilePath);
_JumpIfError(hr, error, "mySetRegistryLocalPathString");
}
if (NULL != pwszLogPath)
{
hr = mySetRegistryLocalPathString(
hkeyRestore,
wszREGLOGPATH,
pwszLogPath);
_JumpIfError(hr, error, "mySetRegistryLocalPathString");
}
// Reset the "database recovered" bit.
hr = RegSetValueEx(
hkeyRestore,
wszREGDATABASERECOVERED,
0,
REG_BINARY,
(BYTE *) &fDatabaseRecovered,
sizeof(BOOLEAN));
_JumpIfError(hr, error, "RegSetValueEx");
// We have successfully registered the restore, now cleanup any
// pre-existing logfiles in the logdir to avoid JetExternalRestore using
// logfiles that are not specified by the low and high log numbers.
hr = CleanupOldLogs(pwszConfig, hkey, pwszLogPath, genLow, genHigh);
_JumpIfError(hr, error, "CleanupOldLogs");
error:
if (NULL != pwszRstMap)
{
LocalFree(pwszRstMap);
}
if (NULL != hkeyRestore)
{
RegCloseKey(hkeyRestore);
}
if (NULL != hkey)
{
RegCloseKey(hkey);
}
if (NULL != pwszPath)
{
LocalFree(pwszPath);
}
hr = myHError(hr);
return hr;
}
//+--------------------------------------------------------------------------
// CertSrvRestoreRegisterComplete -- indicate that a previously registered restore
// is complete.
//
// Parameters:
// [in] hbc - backup context handle
// [in] hrRestoreState - success code if the restore was successful
//
// Returns:
// S_OK if the call executed successfully;
// Failure code otherwise.
//---------------------------------------------------------------------------
HRESULT
CERTBCLI_API
CertSrvRestoreRegisterComplete(
OPTIONAL IN HCSBC hbc,
IN HRESULT hrRestore)
{
HRESULT hr;
WCHAR const *pwszConfig = NULL;
HKEY hkey = NULL;
HKEY hkeyRestore = NULL;
WCHAR *pwszPath = NULL;
DWORD dwDisposition;
if (NULL != hbc)
{
CSBACKUPCONTEXT *pcsbc = (CSBACKUPCONTEXT *) hbc;
pwszConfig = pcsbc->pwszConfig;
}
if (S_OK != hrRestore && SUCCEEDED(hrRestore))
{
hr = E_INVALIDARG;
_JumpError(hr, error, "hrRestore");
}
hr = myRegOpenRelativeKey(
pwszConfig,
L"",
RORKF_CREATESUBKEYS,
&pwszPath,
NULL, // ppwszName
&hkey);
_JumpIfErrorStr(hr, error, "myRegOpenRelativeKey", pwszConfig);
hr = RegCreateKeyEx(
hkey,
wszREGKEYRESTOREINPROGRESS,
0, // Reserved
NULL, // lpClass
0, // dwOptions
KEY_ALL_ACCESS,
NULL,
&hkeyRestore,
&dwDisposition);
_JumpIfError(hr, error, "RegCreateKeyEx");
// If the restore status is not S_OK, then set the status to the error.
// If the restore status is success, then clear the restore-in-progress
// indicator.
if (S_OK != hrRestore)
{
hr = RegSetValueEx(
hkeyRestore,
wszREGRESTORESTATUS,
0,
REG_DWORD,
(BYTE *) &hrRestore,
sizeof(DWORD));
_JumpIfError(hr, error, "RegSetValueEx");
}
else
{
hr = RegDeleteValue(hkeyRestore, wszREGRESTORESTATUS);
_JumpIfError(hr, error, "RegDeleteValue");
}
error:
if (NULL != hkeyRestore)
{
RegCloseKey(hkeyRestore);
}
if (NULL != hkey)
{
RegCloseKey(hkey);
}
if (NULL != pwszPath)
{
LocalFree(pwszPath);
}
return(hr);
}
//+--------------------------------------------------------------------------
// CertSrvRestoreEnd -- end a restore session
//
// Parameters:
// [in] hbc - backup context handle
//
// Returns:
// S_OK if the call executed successfully;
// Failure code otherwise.
//---------------------------------------------------------------------------
HRESULT
CERTBCLI_API
CertSrvRestoreEnd(
IN HCSBC hbc)
{
HRESULT hr;
if (NULL == hbc)
{
hr = E_HANDLE;
_JumpError(hr, error, "NULL handle");
}
hr = S_OK;
__try
{
ReleaseContext((CSBACKUPCONTEXT *) hbc);
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
}
error:
return(hr);
}
HRESULT
rsGetRestoreDataDWORD(
IN LPCWSTR pwszRestoreFile,
IN LPCWSTR pwszName,
OUT DWORD *pdwData)
{
WCHAR buffer[cwcDWORDSPRINTF];
GetPrivateProfileString(
wszRESTORE_SECTION,
pwszName,
L"",
buffer,
ARRAYSIZE(buffer),
pwszRestoreFile);
if (0 == wcscmp(buffer, L""))
{
return(S_FALSE);
}
*pdwData = _wtoi(buffer);
return(S_OK);
}
HRESULT
CERTBCLI_API
CertSrvRestoreRegisterThroughFile(
IN HCSBC hbc,
OPTIONAL IN WCHAR const *pwszCheckPointFilePath,
OPTIONAL IN WCHAR const *pwszLogPath,
OPTIONAL IN CSEDB_RSTMAPW rgrstmap[],
IN LONG crstmap,
OPTIONAL IN WCHAR const *pwszBackupLogPath,
IN ULONG genLow,
IN ULONG genHigh)
{
HRESULT hr = S_OK;
WCHAR const *pwszConfig = NULL;
LONG i;
DWORD dwType;
ULONG genCurrent;
BOOLEAN fDatabaseRecovered = FALSE;
WCHAR wszLogPath[MAX_PATH+1];
WCHAR wszFormat[256]; // must fit MAXDWORD
WCHAR wszKeyName[256]; // must fit RestoreMapN
LPWSTR pwszLogPathUNC = NULL;
HKEY hkey = NULL;
LPWSTR pwszPath = NULL;
LPWSTR pwszRestoreFile = NULL;
LPWSTR pwszServer = NULL;
LPWSTR pwszAuthority = NULL;
if (!hbc ||
(0 != crstmap && NULL == rgrstmap))
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
pwszConfig = ((CSBACKUPCONTEXT *) hbc)->pwszConfig;
if (NULL == pwszLogPath)
{
DWORD cb;
hr = myRegOpenRelativeKey(
pwszConfig,
L"",
0,
&pwszPath,
NULL, // ppwszName
&hkey);
_JumpIfError(hr, error, "RegQueryValueEx");
cb = sizeof(wszLogPath);
hr = RegQueryValueEx(
hkey,
wszREGDBLOGDIRECTORY,
0,
&dwType,
(BYTE *) wszLogPath,
&cb);
_JumpIfError(hr, error, "RegQueryValueEx");
pwszLogPath = wszLogPath;
}
if (L'\\' != pwszLogPath[0] || L'\\' != pwszLogPath[1])
{
// local path - convert to UNC for the INI file
if (NULL != pwszConfig) // if remote access
{
hr = mySplitConfigString(pwszConfig, &pwszServer, &pwszAuthority);
_JumpIfError(hr, error, "mySplitConfigString");
}
else // else local machine
{
hr = myGetMachineDnsName(&pwszServer);
_JumpIfError(hr, error, "myGetMachineDnsName");
}
hr = myConvertLocalPathToUNC(pwszServer, pwszLogPath, &pwszLogPathUNC);
_JumpIfError(hr, error, "myConvertLocalPathToUNC");
}
pwszRestoreFile = (LPWSTR) LocalAlloc(
LMEM_FIXED,
sizeof(WCHAR) * (
wcslen(pwszLogPath) +
wcslen(wszRESTORE_FILENAME) +
2));
_JumpIfAllocFailed(pwszRestoreFile, error);
wcscpy(pwszRestoreFile, pwszLogPath);
wcscat(pwszRestoreFile, L"\\");
wcscat(pwszRestoreFile, wszRESTORE_FILENAME);
wsprintf(wszFormat, L"%d", CERTSRV_E_SERVER_SUSPENDED);
if (!WritePrivateProfileString(
wszRESTORE_SECTION,
wszREGRESTORESTATUS,
wszFormat,
pwszRestoreFile))
{
hr = myHLastError();
_JumpError(hr, error, "WritePrivateProfileString");
}
if (0 != crstmap)
{
// Full backup:
//
// The restore map should only be set on a full backup. If there's
// already a restore map size (or restore map), then this full backup
// is overriding a previously incomplete full backup.
wsprintf(wszFormat, L"%d", crstmap);
if (!WritePrivateProfileString(
wszRESTORE_SECTION,
wszREGRESTOREMAPCOUNT,
wszFormat,
pwszRestoreFile))
{
hr = myHLastError();
_JumpError(hr, error, "WritePrivateProfileString");
}
for (i = 0 ; i < crstmap ; i++)
{
WCHAR wszPath[MAX_PATH];
wsprintf(wszKeyName, L"%ws%d", wszREGRESTOREMAP, i);
myLocalPathwcscpy(wszPath, rgrstmap[i].pwszDatabaseName);
if (!WritePrivateProfileString(
wszRESTORE_SECTION,
wszKeyName,
wszPath,
pwszRestoreFile))
{
hr = myHLastError();
_JumpError(hr, error, "WritePrivateProfileInt");
}
wsprintf(
wszKeyName,
L"%ws%ws%d",
wszREGRESTOREMAP,
wszRESTORE_NEWLOGSUFFIX,
i);
myLocalPathwcscpy(wszPath, rgrstmap[i].pwszNewDatabaseName);
if (!WritePrivateProfileString(
wszRESTORE_SECTION,
wszKeyName,
wszPath,
pwszRestoreFile))
{
hr = myHLastError();
_JumpError(hr, error, "WritePrivateProfileInt");
}
}
}
else
{
// Incremental backup:
//
// Fail if no restore map exists -- Insist that a full backup be in
// progress...
hr = rsGetRestoreDataDWORD(
pwszRestoreFile,
wszREGRESTOREMAPCOUNT,
&genCurrent);
if (S_FALSE == hr)
{
hr = E_ABORT; // mandatory
}
_JumpIfError(
hr,
error,
"restore ini file invalid, wszREGRESTOREMAPCOUNT not found");
// Expand genLow and genHigh to include previously registered log files
hr = rsGetRestoreDataDWORD(
pwszRestoreFile,
wszREGLOWLOGNUMBER,
&genCurrent);
if (S_OK == hr && genLow > genCurrent)
{
genLow = genCurrent;
}
hr = rsGetRestoreDataDWORD(
pwszRestoreFile,
wszREGHIGHLOGNUMBER,
&genCurrent);
if (S_OK == hr && genHigh < genCurrent)
{
genHigh = genCurrent;
}
}
// dword wszREGLOWLOGNUMBER=genLow
wsprintf(wszFormat, L"%d", genLow);
if (!WritePrivateProfileString(
wszRESTORE_SECTION,
wszREGLOWLOGNUMBER,
wszFormat,
pwszRestoreFile))
{
hr = myHLastError();
_JumpError(hr, error, "WritePrivateProfileString");
}
// dword wszREGHIGHLOGNUMBER=genHigh
wsprintf(wszFormat, L"%d", genHigh);
if (!WritePrivateProfileString(
wszRESTORE_SECTION,
wszREGHIGHLOGNUMBER,
wszFormat,
pwszRestoreFile))
{
hr = myHLastError();
_JumpError(hr, error, "WritePrivateProfileString");
}
// string wszREGBACKUPLOGDIRECTORY=pwszBackupLogPath
if (!WritePrivateProfileString(
wszRESTORE_SECTION,
wszREGBACKUPLOGDIRECTORY,
pwszBackupLogPath,
pwszRestoreFile))
{
hr = myHLastError();
_JumpError(hr, error, "WritePrivateProfileString");
}
// string wszREGCHECKPOINTFILE=pwszCheckPointFilePath
if (!WritePrivateProfileString(
wszRESTORE_SECTION,
wszREGCHECKPOINTFILE,
pwszCheckPointFilePath,
pwszRestoreFile))
{
hr = myHLastError();
_JumpError(hr, error, "WritePrivateProfileString");
}
// string wszREGLOGPATH=pwszLogPath -- always write a UNC path
if (!WritePrivateProfileString(
wszRESTORE_SECTION,
wszREGLOGPATH,
NULL != pwszLogPathUNC? pwszLogPathUNC : pwszLogPath,
pwszRestoreFile))
{
hr = myHLastError();
_JumpError(hr, error, "WritePrivateProfileString");
}
// dword wszREGDATABASERECOVERED=fDatabaseRecovered
wsprintf(wszFormat, L"%d", fDatabaseRecovered);
if (!WritePrivateProfileString(
wszRESTORE_SECTION,
wszREGDATABASERECOVERED,
wszFormat,
pwszRestoreFile))
{
hr = myHLastError();
_JumpError(hr, error, "WritePrivateProfileString");
}
// We have successfully registered the restore, now cleanup any
// pre-existing logfiles in the logdir to avoid JetExternalRestore using
// logfiles that are not specified by the low and high log numbers.
CSASSERT(NULL != pwszLogPath);
hr = CleanupOldLogs(pwszConfig, hkey, pwszLogPath, genLow, genHigh);
_JumpIfError(hr, error, "CleanupOldLogs");
// delete restore status error
if (!WritePrivateProfileString(
wszRESTORE_SECTION,
wszREGRESTORESTATUS,
NULL,
pwszRestoreFile))
{
hr = myHLastError();
_JumpError(hr, error, "WritePrivateProfileString");
}
error:
if (S_OK != hr && NULL != pwszRestoreFile)
{
// in case of failure, try to delete restore file
if (!DeleteFile(pwszRestoreFile))
{
_PrintIfError(myHLastError(), "DeleteFile");
}
}
LOCAL_FREE(pwszPath);
LOCAL_FREE(pwszLogPathUNC);
LOCAL_FREE(pwszRestoreFile);
LOCAL_FREE(pwszServer);
LOCAL_FREE(pwszAuthority);
if (NULL != hkey)
{
RegCloseKey(hkey);
}
return(hr);
}