|
|
//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: backup.cpp
//
// Contents: Cert Server client database backup APIs
//
//---------------------------------------------------------------------------
#include <pch.cpp>
#pragma hdrstop
#include "certsrvd.h"
#include "csdisp.h"
#include "certadmp.h"
#define __dwFILE__ __dwFILE_CERTADM_BACKUP_CPP__
#if DBG
#define _CERTBCLI_TYPECHECK
#endif
#include <certbcli.h>
WCHAR g_wszBackupAnnotation[] = L"backup"; WCHAR g_wszRestoreAnnotation[] = L"restore";
HRESULT AllocateContext( IN WCHAR const *pwszConfig, OUT CSBACKUPCONTEXT **ppcsbc) { HRESULT hr; WCHAR *pwszT = NULL;
CSASSERT(NULL != pfnCertSrvIsServerOnline); pwszT = (WCHAR *) LocalAlloc( LMEM_FIXED, (wcslen(pwszConfig) + 1) * sizeof(WCHAR)); if (NULL == pwszT) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } wcscpy(pwszT, pwszConfig); *ppcsbc = (CSBACKUPCONTEXT *) LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, sizeof(**ppcsbc)); if (NULL == *ppcsbc) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } (*ppcsbc)->pwszConfig = pwszT; pwszT = NULL; hr = S_OK;
error: if (NULL != pwszT) { LocalFree(pwszT); } return(hr); }
VOID ReleaseContext( IN OUT CSBACKUPCONTEXT *pcsbc) { CSASSERT(NULL != pcsbc); if (NULL != pcsbc->pwszConfig) { LocalFree(const_cast<WCHAR *>(pcsbc->pwszConfig)); pcsbc->pwszConfig = NULL; } if (NULL != pcsbc->pICertAdminD) { CloseAdminServer(&pcsbc->pICertAdminD); CSASSERT(NULL == pcsbc->pICertAdminD); } if (NULL != pcsbc->pbReadBuffer) { VirtualFree(pcsbc->pbReadBuffer, 0, MEM_RELEASE); } LocalFree(pcsbc); }
HRESULT OpenAdminServer( IN WCHAR const *pwszConfig, OUT WCHAR const **ppwszAuthority, OUT DWORD *pdwServerVersion, OUT ICertAdminD2 **ppICertAdminD) { HRESULT hr; BOOL fCoInitialized = FALSE;
hr = CoInitialize(NULL); if (RPC_E_CHANGED_MODE == hr) { _PrintError(hr, "CoInitialize"); hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); } if (S_OK != hr && S_FALSE != hr) { _JumpError(hr, error, "CoInitialize"); } fCoInitialized = TRUE;
*pdwServerVersion = 0; hr = myOpenAdminDComConnection( pwszConfig, ppwszAuthority, NULL, pdwServerVersion, ppICertAdminD); _JumpIfError(hr, error, "myOpenDComConnection");
CSASSERT(0 != *pdwServerVersion);
error: if (S_OK != hr && fCoInitialized) { CoUninitialize(); } return(hr); }
VOID CloseAdminServer( IN OUT ICertAdminD2 **ppICertAdminD) { myCloseDComConnection((IUnknown **) ppICertAdminD, NULL); CoUninitialize(); }
//+--------------------------------------------------------------------------
// CertSrvIsServerOnline -- check to see if the Cert Server is Online on the
// given server. This call is guaranteed to return quickly.
//
// Parameters:
// [in] pwszConfig - name of the server to check
// [out] pfServerOnline - pointer to receive the bool result
// (TRUE if Cert Server is online; FALSE, otherwise)
// Returns:
// S_OK if the call executed successfully;
// Failure code otherwise.
//+--------------------------------------------------------------------------
HRESULT CERTBCLI_API CertSrvIsServerOnlineW( IN WCHAR const *pwszConfig, OPTIONAL OUT BOOL *pfServerOnline) { HRESULT hr; ICertAdminD2 *pICertAdminD = NULL; WCHAR const *pwszAuthority; DWORD State; DWORD dwServerVersion;
if (NULL == pwszConfig) { hr = E_POINTER; _JumpError(hr, error, "NULL parm"); } hr = S_OK; __try { if (NULL != pfServerOnline) { *pfServerOnline = FALSE; } hr = OpenAdminServer( pwszConfig, &pwszAuthority, &dwServerVersion, &pICertAdminD);
// OpenAdminServer etc might get E_ACCESSDENIED -- meaning server down
if (S_OK != hr) { _PrintError(hr, "OpenAdminServer"); if (E_ACCESSDENIED == hr || (HRESULT) ERROR_ACCESS_DENIED == hr) { hr = S_OK; } __leave; } hr = pICertAdminD->GetServerState(pwszAuthority, &State); _LeaveIfError(hr, "GetServerState");
if (NULL != pfServerOnline && 0 != State) { *pfServerOnline = TRUE; } } __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER) { }
error: if (NULL != pICertAdminD) { CloseAdminServer(&pICertAdminD); } return(hr); }
//+--------------------------------------------------------------------------
// CertSrvBackupPrepare -- prepare the DS for the online backup and return a
// Backup Context Handle to be used for subsequent calls to backup
// functions.
//
// Parameters:
// [in] pwszConfig - server name to prepare for online backup
// [in] grbitJet - flag to be passed to jet while backing up dbs
// [in] dwBackupFlags - CSBACKUP_TYPE_FULL or CSBACKUP_TYPE_LOGS_ONLY
// [out] phbc - pointer that will receive the backup context handle
//
// Returns:
// S_OK if the call executed successfully;
// Failure code otherwise.
//---------------------------------------------------------------------------
HRESULT CERTBCLI_API CertSrvBackupPrepareW( IN WCHAR const *pwszConfig, IN ULONG grbitJet, IN ULONG dwBackupFlags, OUT HCSBC *phbc) { HRESULT hr; CSBACKUPCONTEXT *pcsbc = NULL;
if (NULL == pwszConfig || NULL == phbc) { hr = E_POINTER; _JumpError(hr, error, "NULL parm"); } *phbc = NULL; if (CSBACKUP_TYPE_LOGS_ONLY == dwBackupFlags) { grbitJet |= JET_bitBackupIncremental; } else if (CSBACKUP_TYPE_FULL != dwBackupFlags) { hr = E_INVALIDARG; _JumpError(hr, error, "dwBackupFlags"); }
hr = S_OK; __try { hr = AllocateContext(pwszConfig, &pcsbc); _LeaveIfError(hr, "AllocateContext");
hr = OpenAdminServer( pcsbc->pwszConfig, &pcsbc->pwszAuthority, &pcsbc->dwServerVersion, &pcsbc->pICertAdminD); _LeaveIfError(hr, "OpenAdminServer");
hr = pcsbc->pICertAdminD->BackupPrepare( pcsbc->pwszAuthority, grbitJet, dwBackupFlags, g_wszBackupAnnotation, 0); // dwClientIdentifier
_LeaveIfError(hr, "BackupPrepare");
*phbc = (HCSBC) pcsbc; pcsbc = NULL; } __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER) { }
error: if (NULL != pcsbc) { ReleaseContext(pcsbc); } return(hr); }
// Return the length of a double '\0' terminated string -- includes the
// trailing '\0's.
DWORD mySzzLen( CHAR const *pszz) { CHAR const *psz; DWORD cb;
psz = pszz; do { cb = strlen(psz); psz += cb + 1; } while (0 != cb); return SAFE_SUBTRACT_POINTERS(psz, pszz); // includes double trailing '\0's
}
HRESULT myLocalAllocCopy( IN VOID *pbIn, IN DWORD cbIn, OUT VOID **pbOut) { HRESULT hr; *pbOut = LocalAlloc(LMEM_FIXED, cbIn); if (NULL == *pbOut) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } CopyMemory(*pbOut, pbIn, cbIn); hr = S_OK;
error: return(hr); }
HRESULT BackupRestoreGetFileList( IN DWORD FileListType, IN HCSBC hbc, OUT WCHAR **ppwszzFileList, OUT DWORD *pcbList) { HRESULT hr; CSBACKUPCONTEXT *pcsbc; WCHAR *pwszzFileList = NULL; LONG cwcList; DWORD cbList;
if (NULL == hbc) { hr = E_HANDLE; _JumpError(hr, error, "NULL handle"); } if (NULL != ppwszzFileList) { *ppwszzFileList = NULL; } if (NULL != pcbList) { *pcbList = 0; } if (NULL == ppwszzFileList || NULL == pcbList) { hr = E_POINTER; _JumpError(hr, error, "NULL parm"); } pcsbc = (CSBACKUPCONTEXT *) hbc;
hr = S_OK; __try { if (NULL == pcsbc->pICertAdminD) { hr = OpenAdminServer( pcsbc->pwszConfig, &pcsbc->pwszAuthority, &pcsbc->dwServerVersion, &pcsbc->pICertAdminD); _LeaveIfError(hr, "OpenAdminServer"); } CSASSERT(NULL != pcsbc->pICertAdminD);
if (FLT_DBFILES == FileListType) { hr = pcsbc->pICertAdminD->BackupGetAttachmentInformation( &pwszzFileList, &cwcList); _LeaveIfError(hr, "BackupGetAttachmentInformation"); } else if (FLT_LOGFILES == FileListType) { hr = pcsbc->pICertAdminD->BackupGetBackupLogs( &pwszzFileList, &cwcList); _LeaveIfError(hr, "BackupGetBackupLogs"); } else if (FLT_DYNAMICFILES == FileListType) { hr = pcsbc->pICertAdminD->BackupGetDynamicFiles( &pwszzFileList, &cwcList); _LeaveIfError(hr, "BackupGetDynamicFileList"); } else { CSASSERT(FLT_RESTOREDBLOCATIONS == FileListType); hr = pcsbc->pICertAdminD->RestoreGetDatabaseLocations( &pwszzFileList, &cwcList); _LeaveIfError(hr, "RestoreGetDatabaseLocations"); }
cbList = cwcList * sizeof(WCHAR); myRegisterMemAlloc(pwszzFileList, cbList, CSM_COTASKALLOC);
hr = myLocalAllocCopy(pwszzFileList, cbList, (VOID **) ppwszzFileList); _JumpIfError(hr, error, "myLocalAllocCopy");
*pcbList = cbList; } __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER) { }
error: if (NULL != pwszzFileList) { CoTaskMemFree(pwszzFileList); } return(hr); }
//+--------------------------------------------------------------------------
// CertSrvBackupGetDatabaseNames -- return the list of data bases that need to
// be backed up for the given backup context The information returned in
// ppwszzFileList should not be interpreted, as it only has meaning on
// the server being backed up.
//
// This API will allocate a buffer of sufficient size to hold the entire
// attachment list, which must be later freed with CertSrvBackupFree.
//
// Parameters:
// [in] hbc - backup context handle
// [out] ppwszzFileList - pointer that will receive the pointer to the
// attachment info; allocated memory should be freed using
// CertSrvBackupFree() API by the caller when it is no longer
// needed; ppwszzFileList info is an array of null-terminated
// filenames and the list is terminated by two L'\0's.
// [out] pcbList - will receive the number of bytes returned
//
// Returns:
// S_OK if the call executed successfully;
// Failure code otherwise.
//---------------------------------------------------------------------------
HRESULT CERTBCLI_API CertSrvBackupGetDatabaseNamesW( IN HCSBC hbc, OUT WCHAR **ppwszzFileList, OUT DWORD *pcbList) { HRESULT hr;
hr = BackupRestoreGetFileList(FLT_DBFILES, hbc, ppwszzFileList, pcbList); _JumpIfError(hr, error, "BackupRestoreGetFileList");
error: return(hr); }
//+--------------------------------------------------------------------------
// CertSrvBackupGetDynamicFileList -- return the list of dynamic files that
// need to be backed up for the given backup context The information
// returned in ppwszzFileList should not be interpreted, as it only has
// meaning on the server being backed up.
//
// This API will allocate a buffer of sufficient size to hold the entire
// attachment list, which must be later freed with CertSrvBackupFree.
//
// Parameters:
// [in] hbc - backup context handle
// [out] ppwszzFileList - pointer that will receive the pointer to the
// attachment info; allocated memory should be freed using
// CertSrvBackupFree() API by the caller when it is no longer
// needed; ppwszzFileList info is an array of null-terminated
// filenames and the list is terminated by two L'\0's.
// [out] pcbList - will receive the number of bytes returned
//
// Returns:
// S_OK if the call executed successfully;
// Failure code otherwise.
//---------------------------------------------------------------------------
HRESULT CERTBCLI_API CertSrvBackupGetDynamicFileListW( IN HCSBC hbc, OUT WCHAR **ppwszzFileList, OUT DWORD *pcbList) { HRESULT hr;
hr = BackupRestoreGetFileList( FLT_DYNAMICFILES, hbc, ppwszzFileList, pcbList); _JumpIfError(hr, error, "BackupRestoreGetFileList");
error: return(hr); }
#define CBREADMIN (64 * 1024) // 64k minimum buffer
#define CBREADDEFAULT (512 * 1024) // 512k recommended
#define CBREADMAX (4 * 1024 * 1024) // 4mb maximum buffer
HRESULT BufferAllocate( IN DWORD cbHintSize, OUT BYTE **ppbBuffer, OUT DWORD *pcbBuffer) { HRESULT hr; DWORD cb;
*ppbBuffer = NULL; if (0 == cbHintSize) { // at 512k the server begins doing efficient backups
cbHintSize = CBREADDEFAULT; } else if (CBREADMIN > cbHintSize) { cbHintSize = CBREADMIN; }
for (cb = CBREADMAX; (cb >> 1) >= cbHintSize; cb >>= 1) ;
while (TRUE) { *ppbBuffer = (BYTE *) VirtualAlloc( NULL, cb, MEM_COMMIT, PAGE_READWRITE); if (NULL != *ppbBuffer) { break; } hr = myHLastError(); CSASSERT(S_OK == hr); _PrintError(hr, "VirtualAlloc");
cb >>= 1; if (CBREADMIN > cb) { goto error; } } *pcbBuffer = cb; hr = S_OK;
error: return(hr); }
//+--------------------------------------------------------------------------
// CertSrvBackupOpenFile -- open a remote file for backup, and perform whatever
// client and server side operations to prepare for the backup.
// It takes in a hint of the size of the buffer that will later be passed
// into the CertSrvBackupRead API that can be used to optimize the network
// traffic for the API.
//
// Parameters:
// [in] hbc - backup context handle
// [in] pwszPath - name of the attachment to be opened for read
// [in] cbReadHintSize - suggested size in bytes that might be used
// during the subsequent reads on this attachment
// [out] pliFileSize - pointer to a large integer that would receive the
// size in bytes of the given attachment
// Returns:
// S_OK if the call executed successfully;
// Failure code otherwise.
//---------------------------------------------------------------------------
HRESULT CERTBCLI_API CertSrvBackupOpenFileW( IN HCSBC hbc, IN WCHAR const *pwszPath, IN DWORD cbReadHintSize, OUT LARGE_INTEGER *pliFileSize) { HRESULT hr; CSBACKUPCONTEXT *pcsbc;
if (NULL == hbc) { hr = E_HANDLE; _JumpError(hr, error, "NULL handle"); } if (NULL == pwszPath || NULL == pliFileSize) { hr = E_POINTER; _JumpError(hr, error, "NULL parm"); } pcsbc = (CSBACKUPCONTEXT *) hbc; if (pcsbc->fFileOpen) { hr = HRESULT_FROM_WIN32(ERROR_BUSY); _JumpError(hr, error, "File already open"); }
hr = S_OK; __try { hr = pcsbc->pICertAdminD->BackupOpenFile( pwszPath, (ULONGLONG *) pliFileSize); _LeaveIfErrorStr(hr, "BackupOpenFile", pwszPath);
if (NULL == pcsbc->pbReadBuffer) { hr = BufferAllocate( cbReadHintSize, &pcsbc->pbReadBuffer, &pcsbc->cbReadBuffer); _LeaveIfError(hr, "BufferAllocate"); } pcsbc->fFileOpen = TRUE; pcsbc->cbCache = 0; } __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER) { }
error: return(hr); }
//+--------------------------------------------------------------------------
// CertSrvBackupRead -- read the currently open attachment bytes into the given
// buffer. The client application is expected to call this function
// repeatedly until it gets the entire file (the application would have
// received the file size through the CertSrvBackupOpenFile call before.
//
// Parameters:
// [in] hbc - backup context handle
// [in] pvBuffer - pointer to the buffer that would receive the read data.
// [in] cbBuffer - specifies the size of the above buffer
// [out] pcbRead - pointer to receive the actual number of bytes read.
//
// Returns:
// HRESULT - The status of the operation.
// S_OK if successful.
// ERROR_END_OF_FILE if the end of file was reached while being backed up
// Other Win32 and RPC error code.
//
// Note:
// It is important to realize that pcbRead may be less than cbBuffer.
// This does not indicate an error, some transports may choose to fragment
// the buffer being transmitted instead of returning the entire buffers
// worth of data.
//---------------------------------------------------------------------------
HRESULT CERTBCLI_API CertSrvBackupRead( IN HCSBC hbc, IN VOID *pvBuffer, IN DWORD cbBuffer, OUT DWORD *pcbRead) { HRESULT hr; CSBACKUPCONTEXT *pcsbc; BYTE *pbBuffer = (BYTE *) pvBuffer; DWORD cbRead; DWORD cb;
hr = E_HANDLE; if (NULL == hbc) { _JumpError(hr, error, "NULL handle"); } if (NULL == pvBuffer || NULL == pcbRead) { hr = E_POINTER; _JumpError(hr, error, "NULL parm"); } *pcbRead = 0; pcsbc = (CSBACKUPCONTEXT *) hbc; if (NULL == pcsbc->pbReadBuffer) { _JumpError(hr, error, "NULL buffer"); } if (!pcsbc->fFileOpen) { _JumpError(hr, error, "File not open"); }
while (TRUE) { if (0 != pcsbc->cbCache) { cb = min(pcsbc->cbCache, cbBuffer); CopyMemory(pbBuffer, pcsbc->pbCache, cb); pbBuffer += cb; cbBuffer -= cb; pcsbc->pbCache += cb; pcsbc->cbCache -= cb; *pcbRead += cb; } hr = S_OK; if (0 == cbBuffer) { break; // request satisfied
}
pcsbc->cbCache = 0; cbRead = 0; __try { hr = pcsbc->pICertAdminD->BackupReadFile( pcsbc->pbReadBuffer, pcsbc->cbReadBuffer, (LONG *) &cbRead); _LeaveIfError(hr, "BackupReadFile"); } __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER) { } if (S_OK != hr || 0 == cbRead) { break; // EOF
} pcsbc->cbCache = cbRead; pcsbc->pbCache = pcsbc->pbReadBuffer; }
error: return(hr); }
//+--------------------------------------------------------------------------
// CertSrvBackupClose -- called by the application after it completes reading
// all the data in the currently opened attachement.
//
// Parameters:
// [in] hbc - backup context handle
//
// Returns:
// S_OK if the call executed successfully;
// Failure code otherwise.
//---------------------------------------------------------------------------
HRESULT CERTBCLI_API CertSrvBackupClose( IN HCSBC hbc) { HRESULT hr; CSBACKUPCONTEXT *pcsbc;
hr = E_HANDLE; if (NULL == hbc) { _JumpError(hr, error, "NULL handle"); } pcsbc = (CSBACKUPCONTEXT *) hbc; if (!pcsbc->fFileOpen) { _JumpError(hr, error, "File not open"); }
__try { hr = pcsbc->pICertAdminD->BackupCloseFile(); _LeaveIfError(hr, "BackupCloseFile"); } __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER) { }
// Clear flag even on failure...
pcsbc->fFileOpen = FALSE;
error: return(hr); }
//+--------------------------------------------------------------------------
// CertSrvBackupGetBackupLogs -- return the list of log files that need to be
// backed up for the given backup context
//
// This API will allocate a buffer of sufficient size to hold the entire
// backup log list, which must be later freed with CertSrvBackupFree.
//
// Parameters:
// [in] hbc - backup context handle
// [out] pszBackupLogFiles - pointer that will receive the pointer to the
// list of log files; allocated memory should be freed using
// CertSrvBackupFree() API by the caller when it is no longer
// needed; Log files are returned in an array of null-terminated
// filenames and the list is terminated by two L'\0's.
// [out] pcbList - will receive the number of bytes returned
//
// Returns:
// S_OK if the call executed successfully;
// Failure code otherwise.
//---------------------------------------------------------------------------
HRESULT CERTBCLI_API CertSrvBackupGetBackupLogsW( IN HCSBC hbc, OUT WCHAR **ppwszzFileList, OUT DWORD *pcbList) { HRESULT hr;
hr = BackupRestoreGetFileList( FLT_LOGFILES, hbc, ppwszzFileList, pcbList); _JumpIfError(hr, error, "BackupRestoreGetFileList");
error: return(hr); }
//+--------------------------------------------------------------------------
// CertSrvBackupTruncateLogs -- terminate the backup operation. Called when
// the backup has completed successfully.
//
// Parameters:
// [in] hbc - backup context handle
//
// Returns:
// S_OK if the call executed successfully;
// Failure code otherwise.
//
// Note:
// Again, this API may have to take a grbit parameter to be passed to the
// server to indicate the backup type.
//---------------------------------------------------------------------------
HRESULT CERTBCLI_API CertSrvBackupTruncateLogs( IN HCSBC hbc) { HRESULT hr; CSBACKUPCONTEXT *pcsbc;
if (NULL == hbc) { hr = E_HANDLE; _JumpError(hr, error, "NULL handle"); } pcsbc = (CSBACKUPCONTEXT *) hbc;
hr = S_OK; __try { hr = pcsbc->pICertAdminD->BackupTruncateLogs(); _LeaveIfError(hr, "BackupTruncateLogs"); } __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER) { }
error: return(hr); }
//+--------------------------------------------------------------------------
// CertSrvBackupEnd -- clean up after a backup operation has been performed.
// This API will close outstanding binding handles, and do whatever is
// necessary to clean up after successful/unsuccesful backup attempts.
//
// Parameters:
// [in] hbc - backup context handle of the backup session
//
// Returns:
// S_OK if the call executed successfully;
// Failure code otherwise.
//---------------------------------------------------------------------------
HRESULT CERTBCLI_API CertSrvBackupEnd( IN HCSBC hbc) { HRESULT hr; CSBACKUPCONTEXT *pcsbc;
if (NULL == hbc) { hr = E_HANDLE; _JumpError(hr, error, "NULL handle"); } pcsbc = (CSBACKUPCONTEXT *) hbc;
hr = S_OK; __try { hr = pcsbc->pICertAdminD->BackupEnd(); _LeaveIfError(hr, "BackupEnd");
ReleaseContext((CSBACKUPCONTEXT *) hbc); hr = S_OK; } __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER) { }
error: return(hr); }
//+--------------------------------------------------------------------------
// CertSrvBackupFree -- free any buffer allocated by certbcli.dll APIs.
//
// Parameters:
// [in] pv - pointer to the buffer that is to be freed.
//
// Returns:
// None.
//---------------------------------------------------------------------------
VOID CERTBCLI_API CertSrvBackupFree( IN VOID *pv) { LocalFree(pv); }
|