X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fwin32_vss.c;h=2270feeac6814fc63e06c4865cf6f2b998238f00;hb=e8da56fa0465b6ee714581fe828e22fd63bf3f8b;hp=6e5d3ebc5f2e21fa9f2882208c203b64be58fa91;hpb=8b676e7d340fb8197824745eb387e1d3154e6f60;p=wimlib diff --git a/src/win32_vss.c b/src/win32_vss.c index 6e5d3ebc..2270feea 100644 --- a/src/win32_vss.c +++ b/src/win32_vss.c @@ -1,10 +1,10 @@ /* - * win32_vss.c - Experimental Windows-specific code for creating VSS (Volume - * Shadow Copy Service) snapshots. + * win32_vss.c - Windows-specific code for creating VSS (Volume Shadow Copy + * Service) snapshots. */ /* - * Copyright (C) 2015 Eric Biggers + * Copyright (C) 2015-2016 Eric Biggers * * This file is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free @@ -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"); @@ -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,6 +508,15 @@ request_vss_snapshot(IVssBackupComponents *vss, wchar_t *volume, return true; } +static bool +is_wow64(void) +{ + BOOL wow64 = FALSE; + if (sizeof(size_t) == 4) + IsWow64Process(GetCurrentProcess(), &wow64); + return wow64; +} + /* * Create a VSS snapshot of the specified @volume. Return the NT namespace path * to the snapshot root directory in @vss_path_ret and a handle to the snapshot @@ -450,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; @@ -461,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; @@ -494,8 +603,16 @@ vss_create_snapshot(const wchar_t *source, UNICODE_STRING *vss_path_ret, vss_err: ret = WIMLIB_ERR_SNAPSHOT_FAILURE; - ERROR("A problem occurred while creating a VSS snapshot of \"%ls\".\n" - " Aborting the operation.", volume); + 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 " + "instead."); + } else { + ERROR("A problem occurred while creating a VSS snapshot of " + "\"%ls\".\n" + " Aborting the operation.", volume); + } err: if (snapshot) vss_delete_snapshot(&snapshot->base);