From: Eric Biggers Date: Sat, 2 Jan 2016 19:30:01 +0000 (-0600) Subject: vss: support on Windows XP X-Git-Tag: v1.9.0~29 X-Git-Url: https://wimlib.net/git/?p=wimlib;a=commitdiff_plain;h=0a267870dd204ff41140af1d6dbfa272354a9ffe vss: support on Windows XP --- diff --git a/doc/man1/wimlib-imagex-capture.1 b/doc/man1/wimlib-imagex-capture.1 index 6198d52b..05197006 100644 --- a/doc/man1/wimlib-imagex-capture.1 +++ b/doc/man1/wimlib-imagex-capture.1 @@ -579,13 +579,13 @@ See the documentation for this option in \fBwimlib-imagex-optimize\fR (1). .TP \fB--snapshot\fR EXPERIMENTAL: create a temporary filesystem snapshot of the source directory and -capture the files from it. Currently, this option is only supported on Windows -(Vista and later), where it uses the Volume Shadow Copy Service (VSS). Using -this option, you can create a consistent backup of the system volume of a -running Windows system without running into problems with locked files. For the -VSS snapshot to be successfully created, \fBwimlib-imagex\fR must be run as an -Administrator, and it cannot be run in WoW64 mode (i.e. if Windows is 64-bit, -then \fBwimlib-imagex\fR must be 64-bit as well). +capture the files from it. Currently, this option is only supported on Windows, +where it uses the Volume Shadow Copy Service (VSS). Using this option, you can +create a consistent backup of the system volume of a running Windows system +without running into problems with locked files. For the VSS snapshot to be +successfully created, \fBwimlib-imagex\fR must be run as an Administrator, and +it cannot be run in WoW64 mode (i.e. if Windows is 64-bit, then +\fBwimlib-imagex\fR must be 64-bit as well). .SH NOTES \fBwimlib-imagex append\fR does not support appending an image to a split WIM. .PP diff --git a/include/wimlib.h b/include/wimlib.h index f2e9f229..2e5ba3c6 100644 --- a/include/wimlib.h +++ b/include/wimlib.h @@ -1750,13 +1750,12 @@ typedef int (*wimlib_iterate_lookup_table_callback_t)(const struct wimlib_resour /** * EXPERIMENTAL, since wimlib v1.9.0: create a temporary filesystem snapshot of * the source directory and add the files from it. Currently, this option is - * only supported on Windows (Vista and later), where it uses the Volume Shadow - * Copy Service (VSS). Using this option, you can create a consistent backup of - * the system volume of a running Windows system without running into problems - * with locked files. For the VSS snapshot to be successfully created, your - * application must be run as an Administrator, and it cannot be run in WoW64 - * mode (i.e. if Windows is 64-bit, then your application must be 64-bit as - * well). + * only supported on Windows, where it uses the Volume Shadow Copy Service + * (VSS). Using this option, you can create a consistent backup of the system + * volume of a running Windows system without running into problems with locked + * files. For the VSS snapshot to be successfully created, your application + * must be run as an Administrator, and it cannot be run in WoW64 mode (i.e. if + * Windows is 64-bit, then your application must be 64-bit as well). */ #define WIMLIB_ADD_FLAG_SNAPSHOT 0x00008000 diff --git a/src/win32_vss.c b/src/win32_vss.c index 46af4bb1..4ee6c9de 100644 --- a/src/win32_vss.c +++ b/src/win32_vss.c @@ -131,14 +131,21 @@ struct IVssAsyncVTable { void *AddRef; ULONG (WINAPI *Release)(IVssAsync *this); void *Cancel; - HRESULT (WINAPI *Wait)(IVssAsync *this, DWORD dwMilliseconds); + union { + HRESULT (WINAPI *Wait)(IVssAsync *this, DWORD dwMilliseconds); + + /* Pre-Vista version */ + HRESULT (WINAPI *OldWait)(IVssAsync *this); + }; void *QueryStatus; }; typedef struct IVssBackupComponentsVTable IVssBackupComponentsVTable; +typedef struct IVssBackupComponentsVTable_old IVssBackupComponentsVTable_old; -typedef struct { +typedef union { IVssBackupComponentsVTable *vtable; + IVssBackupComponentsVTable_old *old_vtable; } IVssBackupComponents; struct IVssBackupComponentsVTable { @@ -196,6 +203,7 @@ struct IVssBackupComponentsVTable { IVssAsync **ppAsync); void *DeleteSnapshots; void *ImportSnapshots; + /*void *RemountReadWrite;*/ /* Old API only */ void *BreakSnapshotSet; HRESULT (WINAPI *GetSnapshotProperties)(IVssBackupComponents *this, VSS_ID SnapshotId, @@ -210,6 +218,88 @@ struct IVssBackupComponentsVTable { void *QueryRevertStatus; }; +/* Pre-Vista version */ +struct IVssBackupComponentsVTable_old { + void *QueryInterface; + void *AddRef; + ULONG (WINAPI *Release)(IVssBackupComponents *this); + void *GetWriterComponentsCount; + void *GetWriterComponents; + HRESULT (WINAPI *InitializeForBackup)(IVssBackupComponents *this, + BSTR bstrXML); + HRESULT (WINAPI *SetBackupState)(IVssBackupComponents *this, + BOOLEAN bSelectComponents, + BOOLEAN bBackupBootableSystemState, + VSS_BACKUP_TYPE backupType, + BOOLEAN bPartialFileSupport); + void *InitializeForRestore; + /*void *SetRestoreState;*/ /* New API only */ + HRESULT (WINAPI *GatherWriterMetadata)(IVssBackupComponents *this, + IVssAsync **ppAsync); + void *GetWriterMetadataCount; + void *GetWriterMetadata; + void *FreeWriterMetadata; + void *AddComponent; + HRESULT (WINAPI *PrepareForBackup)(IVssBackupComponents *this, + IVssAsync **ppAsync); + void *AbortBackup; + void *GatherWriterStatus; + void *GetWriterStatusCount; + void *FreeWriterStatus; + void *GetWriterStatus; + void *SetBackupSucceeded; + void *SetBackupOptions; + void *SetSelectedForRestore; + void *SetRestoreOptions; + void *SetAdditionalRestores; + void *SetPreviousBackupStamp; + void *SaveAsXML; + void *BackupComplete; + void *AddAlternativeLocationMapping; + void *AddRestoreSubcomponent; + void *SetFileRestoreStatus; + /*void *AddNewTarget;*/ /* New API only */ + /*void *SetRangesFilePath;*/ /* New API only */ + void *PreRestore; + void *PostRestore; + HRESULT (WINAPI *SetContext)(IVssBackupComponents *this, + LONG lContext); + HRESULT (WINAPI *StartSnapshotSet)(IVssBackupComponents *this, + VSS_ID *pSnapshotSetId); + HRESULT (WINAPI *AddToSnapshotSet)(IVssBackupComponents *this, + VSS_PWSZ pwszVolumeName, + VSS_ID ProviderId, + VSS_ID *pidSnapshot); + HRESULT (WINAPI *DoSnapshotSet)(IVssBackupComponents *this, + IVssAsync **ppAsync); + void *DeleteSnapshots; + void *ImportSnapshots; + void *RemountReadWrite; + void *BreakSnapshotSet; + HRESULT (WINAPI *GetSnapshotProperties)(IVssBackupComponents *this, + VSS_ID SnapshotId, + VSS_SNAPSHOT_PROP *pprop); + void *Query; + void *IsVolumeSupported; + void *DisableWriterClasses; + void *EnableWriterClasses; + void *DisableWriterInstances; + void *ExposeSnapshot; + /*void *RevertToSnapshot;*/ /* New API only */ + /*void *QueryRevertStatus;*/ /* New API only */ +}; + +/* Call a method, assuming its signature is identical in the old and new APIs */ +#define CALL_METHOD(obj, method, ...) \ +({ \ + HRESULT res; \ + if (is_old_api) \ + res = (obj)->old_vtable->method((obj), ##__VA_ARGS__); \ + else \ + res = (obj)->vtable->method((obj), ##__VA_ARGS__); \ + res; \ +}) + /*----------------------------------------------------------------------------* * VSS API initialization * *----------------------------------------------------------------------------*/ @@ -218,9 +308,10 @@ static bool vss_initialized; static pthread_mutex_t vss_initialization_mutex = PTHREAD_MUTEX_INITIALIZER; /* vssapi.dll */ +static bool is_old_api; /* old VSS API (pre-Vista)? */ static HANDLE hVssapi; -static HRESULT (WINAPI *func_CreateVssBackupComponentsInternal)(IVssBackupComponents **ppBackup); -static void (WINAPI *func_VssFreeSnapshotPropertiesInternal)(VSS_SNAPSHOT_PROP *pProp); +static HRESULT (WINAPI *func_CreateVssBackupComponents)(IVssBackupComponents **ppBackup); +static void (WINAPI *func_VssFreeSnapshotProperties)(VSS_SNAPSHOT_PROP *pProp); /* ole32.dll */ static HANDLE hOle32; @@ -236,18 +327,29 @@ vss_global_init_impl(void) goto err; } - func_CreateVssBackupComponentsInternal = + func_CreateVssBackupComponents = (void *)GetProcAddress(hVssapi, "CreateVssBackupComponentsInternal"); - if (!func_CreateVssBackupComponentsInternal) { - ERROR("CreateVssBackupComponentsInternal() not found in vssapi.dll"); - goto err_vssapi; + if (!func_CreateVssBackupComponents) { + func_CreateVssBackupComponents = + (void *)GetProcAddress(hVssapi, "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"); + if (!func_CreateVssBackupComponents) { + ERROR("CreateVssBackupComponents() not found in vssapi.dll"); + goto err_vssapi; + } + is_old_api = true; + } else { + is_old_api = false; } - func_VssFreeSnapshotPropertiesInternal = + func_VssFreeSnapshotProperties = (void *)GetProcAddress(hVssapi, "VssFreeSnapshotPropertiesInternal"); - if (!func_VssFreeSnapshotPropertiesInternal) { - ERROR("VssFreeSnapshotPropertiesInternal() not found in vssapi.dll"); - goto err_vssapi; + if (!func_VssFreeSnapshotProperties) { + func_VssFreeSnapshotProperties = + (void *)GetProcAddress(hVssapi, "VssFreeSnapshotProperties"); + if (!func_VssFreeSnapshotProperties) { + ERROR("VssFreeSnapshotProperties() not found in vssapi.dll"); + goto err_vssapi; + } } hOle32 = LoadLibrary(L"ole32.dll"); @@ -293,7 +395,7 @@ vss_global_init(void) if (vss_initialized) return true; ERROR("The Volume Shadow Copy Service (VSS) API could not be " - "initialized."); + "initialized. Probably it isn't supported on this computer."); return false; } @@ -332,16 +434,20 @@ vss_delete_snapshot(struct vss_snapshot *snapshot) internal = container_of(snapshot, struct vss_snapshot_internal, base); if (internal->props.m_pwszSnapshotDeviceObject) - (*func_VssFreeSnapshotPropertiesInternal)(&internal->props); + (*func_VssFreeSnapshotProperties)(&internal->props); if (internal->vss) - internal->vss->vtable->Release(internal->vss); + CALL_METHOD(internal->vss, Release); FREE(internal); } static HRESULT wait_and_release(IVssAsync *async) { - HRESULT res = async->vtable->Wait(async, INFINITE); + HRESULT res; + if (is_old_api) + res = async->vtable->OldWait(async); + else + res = async->vtable->Wait(async, INFINITE); async->vtable->Release(async); return res; } @@ -353,37 +459,31 @@ request_vss_snapshot(IVssBackupComponents *vss, wchar_t *volume, HRESULT res; IVssAsync *async; - res = vss->vtable->InitializeForBackup(vss, NULL); + res = CALL_METHOD(vss, InitializeForBackup, NULL); if (FAILED(res)) { ERROR("IVssBackupComponents.InitializeForBackup() error: %x", res); return false; } - res = vss->vtable->SetContext(vss, VSS_CTX_BACKUP); - if (FAILED(res)) { - ERROR("IVssBackupComponents.SetContext() error: %x", res); - return false; - } - - res = vss->vtable->SetBackupState(vss, FALSE, TRUE, VSS_BT_COPY, FALSE); + res = CALL_METHOD(vss, SetBackupState, FALSE, TRUE, VSS_BT_COPY, FALSE); if (FAILED(res)) { ERROR("IVssBackupComponents.SetBackupState() error: %x", res); return false; } - res = vss->vtable->StartSnapshotSet(vss, snapshot_id); + res = CALL_METHOD(vss, StartSnapshotSet, snapshot_id); if (FAILED(res)) { ERROR("IVssBackupComponents.StartSnapshotSet() error: %x", res); return false; } - res = vss->vtable->AddToSnapshotSet(vss, volume, (GUID){}, snapshot_id); + res = CALL_METHOD(vss, AddToSnapshotSet, volume, (GUID){}, snapshot_id); if (FAILED(res)) { ERROR("IVssBackupComponents.AddToSnapshotSet() error: %x", res); return false; } - res = vss->vtable->PrepareForBackup(vss, &async); + res = CALL_METHOD(vss, PrepareForBackup, &async); if (FAILED(res)) { ERROR("IVssBackupComponents.PrepareForBackup() error: %x", res); return false; @@ -394,7 +494,7 @@ request_vss_snapshot(IVssBackupComponents *vss, wchar_t *volume, return false; } - res = vss->vtable->DoSnapshotSet(vss, &async); + res = CALL_METHOD(vss, DoSnapshotSet, &async); if (FAILED(res)) { ERROR("IVssBackupComponents.DoSnapshotSet() error: %x", res); return false; @@ -408,12 +508,6 @@ request_vss_snapshot(IVssBackupComponents *vss, wchar_t *volume, return true; } -static bool -is_pre_vista(void) -{ - return (GetVersion() & 0xFF) < 6; -} - static bool is_wow64(void) { @@ -465,7 +559,7 @@ vss_create_snapshot(const wchar_t *source, UNICODE_STRING *vss_path_ret, if (!vss_global_init()) goto vss_err; - res = (*func_CreateVssBackupComponentsInternal)(&vss); + res = (*func_CreateVssBackupComponents)(&vss); if (FAILED(res)) { ERROR("CreateVssBackupComponents error: %x", res); goto vss_err; @@ -476,7 +570,7 @@ vss_create_snapshot(const wchar_t *source, UNICODE_STRING *vss_path_ret, if (!request_vss_snapshot(vss, volume, &snapshot_id)) goto vss_err; - res = vss->vtable->GetSnapshotProperties(vss, snapshot_id, &snapshot->props); + res = CALL_METHOD(vss, GetSnapshotProperties, snapshot_id, &snapshot->props); if (FAILED(res)) { ERROR("IVssBackupComponents.GetSnapshotProperties() error: %x", res); goto vss_err; @@ -509,10 +603,7 @@ vss_create_snapshot(const wchar_t *source, UNICODE_STRING *vss_path_ret, vss_err: ret = WIMLIB_ERR_SNAPSHOT_FAILURE; - if (is_pre_vista() && !vss_initialized) { - ERROR("Snapshot mode is only supported on Windows Vista " - "and later!"); - } else if (is_wow64()) { + if (is_wow64()) { ERROR("64-bit Windows doesn't allow 32-bit applications to " "create VSS snapshots.\n" " Run the 64-bit version of this application "