/*
- * 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
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 {
IVssAsync **ppAsync);
void *DeleteSnapshots;
void *ImportSnapshots;
+ /*void *RemountReadWrite;*/ /* Old API only */
void *BreakSnapshotSet;
HRESULT (WINAPI *GetSnapshotProperties)(IVssBackupComponents *this,
VSS_ID SnapshotId,
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 *
*----------------------------------------------------------------------------*/
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;
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");
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;
}
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;
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;
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
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;
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;
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);