//+-------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1996 - 1999 // // File: restore.cpp // // Contents: Cert Server client database restore APIs // //--------------------------------------------------------------------------- #include #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); }