bEventLevel = 11,
bEventSince = 12,
bEventCancelCommand = 13,
- bEventInitializeVSS = 14
+ bEventInitializeVSS = 14,
+ bEventPrepareVSS = 15,
} bEventType;
typedef struct s_bEvent {
return 0; /* return and terminate command loop */
}
+#ifdef WIN32_VSS
+static bool vss_restore_init_callback(JCR *jcr, int init_type)
+{
+ switch (init_type)
+ {
+ case VSS_INIT_RESTORE_AFTER_INIT:
+ generate_plugin_event(jcr, bEventInitializeVSS);
+ return true;
+ case VSS_INIT_RESTORE_AFTER_GATHER:
+ generate_plugin_event(jcr, bEventPrepareVSS);
+ return true;
+ default:
+ return false;
+ break;
+ }
+}
+#endif
+
/**
* Do a Restore for Director
*
* Scan WHERE (base directory for restore) from command
*/
Dmsg0(150, "restore command\n");
+#if defined(WIN32_VSS)
+
+ /* TODO: this should be given from the director */
+ enable_vss = 1;
+
+ Dmsg2(50, "g_pVSSClient = %p, enable_vss = %d\n", g_pVSSClient, enable_vss);
+ // capture state here, if client is backed up by multiple directors
+ // and one enables vss and the other does not then enable_vss can change
+ // between here and where its evaluated after the job completes.
+ jcr->VSS = g_pVSSClient && enable_vss;
+ if (jcr->VSS) {
+ /* Run only one at a time */
+ P(vss_mutex);
+ }
+#endif
/* Pickup where string */
args = get_memory(dir->msglen+1);
*args = 0;
start_dir_heartbeat(jcr);
generate_daemon_event(jcr, "JobStart");
generate_plugin_event(jcr, bEventStartRestoreJob);
+
+#if defined(WIN32_VSS)
+ /* START VSS ON WIN32 */
+ if (jcr->VSS) {
+ if (g_pVSSClient->InitializeForRestore(jcr, vss_restore_init_callback)) {
+ /* inform user about writer states */
+ int i;
+ for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++) {
+ int msg_type = M_INFO;
+ if (g_pVSSClient->GetWriterState(i) < 1) {
+ msg_type = M_WARNING;
+ jcr->JobErrors++;
+ }
+ if (g_pVSSClient->GetWriterState(i) < 1) {
+ Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PreRestore): %s\n"), g_pVSSClient->GetWriterInfo(i));
+ jcr->JobErrors++;
+ }
+ }
+ } else {
+ berrno be;
+ Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
+ }
+ run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
+ }
+#endif
+
do_restore(jcr);
stop_dir_heartbeat(jcr);
/* Inform Storage daemon that we are done */
sd->signal(BNET_TERMINATE);
+#if defined(WIN32_VSS)
+ /* STOP VSS ON WIN32 */
+ /* tell vss to close the restore session */
+ Dmsg0(0, "About to call CloseRestore\n");
+ if (jcr->VSS) {
+ Dmsg0(0, "Really about to call CloseRestore\n");
+ if (g_pVSSClient->CloseRestore()) {
+ Dmsg0(0, "CloseRestore success\n");
+ /* inform user about writer states */
+ for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
+ int msg_type = M_INFO;
+ if (g_pVSSClient->GetWriterState(i) < 1) {
+ msg_type = M_WARNING;
+ jcr->JobErrors++;
+ }
+ Jmsg(jcr, msg_type, 0, _("VSS Writer (RestoreComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
+ }
+ }
+ else
+ Dmsg1(0, "CloseRestore fail - %08x\n", errno);
+ V(vss_mutex);
+ }
+#endif
+
bail_out:
bfree_and_null(jcr->where);
}
-
+bool VSSClient::InitializeForRestore(JCR *jcr, bool (*VssInitCallback)(JCR *, int))
+{
+ m_jcr = jcr;
+ return Initialize(0, TRUE, VssInitCallback);
+}
bool VSSClient::GetShadowPath(const char *szFilePath, char *szShadowPath, int nBuflen)
{
#ifdef WIN32_VSS
+#define VSS_INIT_RESTORE_AFTER_INIT 1
+#define VSS_INIT_RESTORE_AFTER_GATHER 2
+
// some forward declarations
struct IVssAsync;
// Backup Process
bool InitializeForBackup(JCR *jcr);
+ bool InitializeForRestore(JCR *jcr, bool (*VssInitCallback)(JCR *, int) = NULL);
+ //bool GatherForRestore() = 0;
+ //bool PrepareForRestore() = 0;
virtual bool CreateSnapshots(char* szDriveLetters) = 0;
virtual bool CloseBackup() = 0;
+ virtual bool CloseRestore() = 0;
virtual const char* GetDriverName() = 0;
bool GetShadowPath (const char* szFilePath, char* szShadowPath, int nBuflen);
bool GetShadowPathW (const wchar_t* szFilePath, wchar_t* szShadowPath, int nBuflen); /* nBuflen in characters */
IUnknown *GetVssObject() { return m_pVssObject; };
private:
- virtual bool Initialize(DWORD dwContext, bool bDuringRestore = FALSE) = 0;
+ virtual bool Initialize(DWORD dwContext, bool bDuringRestore = FALSE, bool (*VssInitCallback)(JCR *, int) = NULL) = 0;
virtual bool WaitAndCheckForAsyncOperation(IVssAsync* pAsync) = 0;
virtual void QuerySnapshotSet(GUID snapshotSetID) = 0;
virtual ~VSSClientXP();
virtual bool CreateSnapshots(char* szDriveLetters);
virtual bool CloseBackup();
+ virtual bool CloseRestore();
virtual const char* GetDriverName() { return "VSS WinXP"; };
private:
- virtual bool Initialize(DWORD dwContext, bool bDuringRestore);
+ virtual bool Initialize(DWORD dwContext, bool bDuringRestore, bool (*VssInitCallback)(JCR *, int) = NULL);
virtual bool WaitAndCheckForAsyncOperation(IVssAsync* pAsync);
virtual void QuerySnapshotSet(GUID snapshotSetID);
bool CheckWriterStatus();
virtual ~VSSClient2003();
virtual bool CreateSnapshots(char* szDriveLetters);
virtual bool CloseBackup();
+ virtual bool CloseRestore();
virtual const char* GetDriverName() { return "VSS Win 2003"; };
private:
- virtual bool Initialize(DWORD dwContext, bool bDuringRestore);
+ virtual bool Initialize(DWORD dwContext, bool bDuringRestore, bool (*VssInitCallback)(JCR *, int) = NULL);
virtual bool WaitAndCheckForAsyncOperation(IVssAsync* pAsync);
virtual void QuerySnapshotSet(GUID snapshotSetID);
bool CheckWriterStatus();
virtual ~VSSClientVista();
virtual bool CreateSnapshots(char* szDriveLetters);
virtual bool CloseBackup();
+ virtual bool CloseRestore();
virtual const char* GetDriverName() { return "VSS Vista"; };
private:
- virtual bool Initialize(DWORD dwContext, bool bDuringRestore);
+ virtual bool Initialize(DWORD dwContext, bool bDuringRestore, bool (*VssInitCallback)(JCR *, int) = NULL);
virtual bool WaitAndCheckForAsyncOperation(IVssAsync* pAsync);
virtual void QuerySnapshotSet(GUID snapshotSetID);
bool CheckWriterStatus();
}
// Initialize the COM infrastructure and the internal pointers
-bool VSSClientGeneric::Initialize(DWORD dwContext, bool bDuringRestore)
+bool VSSClientGeneric::Initialize(DWORD dwContext, bool bDuringRestore, bool (*VssInitCallback)(JCR *, int))
{
+ CComPtr<IVssAsync> pAsync1;
+
if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
Dmsg2(0, "VSSClientGeneric::Initialize: p_CreateVssBackupComponents = 0x%08X, p_VssFreeSnapshotProperties = 0x%08X\n", p_CreateVssBackupComponents, p_VssFreeSnapshotProperties);
errno = ENOSYS;
return false;
}
- CComPtr<IVssAsync> pAsync1;
// 3. GatherWriterMetaData
hr = ((IVssBackupComponents*) m_pVssObject)->GatherWriterMetadata(&pAsync1.p);
if (FAILED(hr)) {
// Waits for the async operation to finish and checks the result
WaitAndCheckForAsyncOperation(pAsync1.p);
}
+ else
+ {
+ WCHAR *xml;
+ HRESULT hr;
+ int fd;
+ struct stat stat;
+
+ /* obviously this is just temporary - the xml should come from somewhere like the catalog */
+ fd = open("C:\\james.xml", O_RDONLY);
+ Dmsg1(0, "fd = %d\n", fd);
+ fstat(fd, &stat);
+ Dmsg1(0, "size = %d\n", stat.st_size);
+ xml = new WCHAR[stat.st_size / sizeof(WCHAR) + 1];
+ read(fd, xml, stat.st_size);
+ close(fd);
+ xml[stat.st_size / sizeof(WCHAR)] = 0;
+
+ // 1. InitializeForRestore
+ hr = ((IVssBackupComponents*) m_pVssObject)->InitializeForRestore(xml);
+ if (FAILED(hr)) {
+ Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->InitializeForRestore returned 0x%08X\n", hr);
+ errno = b_errno_win32;
+ return false;
+ }
+ VssInitCallback(m_jcr, VSS_INIT_RESTORE_AFTER_INIT);
+
+ // 2. GatherWriterMetaData
+ hr = ((IVssBackupComponents*) m_pVssObject)->GatherWriterMetadata(&pAsync1.p);
+ if (FAILED(hr)) {
+ Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->GatherWriterMetadata returned 0x%08X\n", hr);
+ errno = b_errno_win32;
+ return false;
+ }
+ WaitAndCheckForAsyncOperation(pAsync1.p);
+ VssInitCallback(m_jcr, VSS_INIT_RESTORE_AFTER_GATHER);
+
+ // 3. PreRestore
+ hr = ((IVssBackupComponents*) m_pVssObject)->PreRestore(&pAsync1.p);
+ if (FAILED(hr)) {
+ Dmsg1(0, "VSSClientGeneric::Initialize: IVssBackupComponents->PreRestore returned 0x%08X\n", hr);
+ errno = b_errno_win32;
+ return false;
+ }
+ WaitAndCheckForAsyncOperation(pAsync1.p);
+ /* get latest info about writer status */
+ if (!CheckWriterStatus()) {
+ Dmsg0(0, "VSSClientGeneric::InitializePostPlugin: Failed to CheckWriterstatus\n");
+ errno = b_errno_win32;
+ return false;
+ }
+ }
// We are during restore now?
m_bDuringRestore = bDuringRestore;
return true;
}
-
bool VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync)
{
// Wait until the async operation finishes
m_bBackupIsInitialized = false;
+{
+ HRESULT hr;
+ BSTR xml;
+ int fd;
+
+ hr = pVss->SaveAsXML(&xml);
+ fd = open("C:\\james.xml", O_CREAT | O_WRONLY | O_TRUNC, 0777);
+ write(fd, xml, wcslen(xml) * sizeof(WCHAR));
+ close(fd);
+}
if (SUCCEEDED(pVss->BackupComplete(&pAsync.p))) {
// Waits for the async operation to finish and checks the result
WaitAndCheckForAsyncOperation(pAsync.p);
return bRet;
}
+bool VSSClientGeneric::CloseRestore()
+{
+ HRESULT hr;
+ IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
+ CComPtr<IVssAsync> pAsync;
+
+ if (!pVss)
+ {
+ errno = ENOSYS;
+ return false;
+ }
+ if (SUCCEEDED(hr = pVss->PostRestore(&pAsync.p))) {
+ // Waits for the async operation to finish and checks the result
+ WaitAndCheckForAsyncOperation(pAsync.p);
+ /* get latest info about writer status */
+ if (!CheckWriterStatus()) {
+ errno = b_errno_win32;
+ return false;
+ }
+ } else {
+ errno = b_errno_win32;
+ return false;
+ }
+ return true;
+}
+
// Query all the shadow copies in the given set
void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
{