#include #include #include #include #include typedef struct _VSP_CONTEXT { HANDLE Handle; PVOLSNAP_FLUSH_AND_HOLD_INPUT FlushInput; } VSP_CONTEXT, *PVSP_CONTEXT; DWORD FlushAndHoldRoutine( PVOID Context ) { PVSP_CONTEXT context = Context; BOOL b; DWORD bytes; b = DeviceIoControl(context->Handle, IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES, context->FlushInput, sizeof(VOLSNAP_FLUSH_AND_HOLD_INPUT), NULL, 0, &bytes, NULL); if (!b) { printf("Flush and hold failed with %d\n", GetLastError()); return GetLastError(); } return 0; } void __cdecl main( int argc, char** argv ) { WCHAR driveName[10]; HANDLE handle[100]; VOLSNAP_PREPARE_INFO prepareInfo; BOOL b, persistent; DWORD bytes; int i, j; VOLSNAP_FLUSH_AND_HOLD_INPUT flushInput; PVOLSNAP_NAME name; WCHAR buffer[100]; HANDLE threads[100]; DWORD threadid; VSP_CONTEXT context[100]; if (argc < 2) { printf("usage: %s [/p] drive: drive: ...\n", argv[0]); return; } if (argv[1][0] == '/' && (argv[1][1] == 'p' || argv[1][1] == 'P')) { persistent = TRUE; if (argc < 3) { printf("usage: %s /p drive: drive: ...\n", argv[0]); return; } } else { persistent = FALSE; } for (i = persistent ? 2 : 1; i < argc; i++) { swprintf(driveName, L"\\\\?\\%c:", toupper(argv[i][0])); handle[i] = CreateFile(driveName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE); if (handle[i] == INVALID_HANDLE_VALUE) { printf("Could not open volume %c:, error = %d\n", argv[i][0], GetLastError()); break; } if (persistent) { prepareInfo.Attributes = 1; } else { prepareInfo.Attributes = 0; } prepareInfo.InitialDiffAreaAllocation = 100*1024*1024; b = DeviceIoControl(handle[i], IOCTL_VOLSNAP_PREPARE_FOR_SNAPSHOT, &prepareInfo, sizeof(prepareInfo), NULL, 0, &bytes, NULL); if (!b) { printf("Prepare failed with %d\n", GetLastError()); break; } CloseHandle(handle[i]); handle[i] = CreateFile(driveName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE); if (handle == INVALID_HANDLE_VALUE) { printf("Could not open volume %c:, error = %d\n", argv[i][0], GetLastError()); break; } } if (i < argc) { for (j = persistent ? 2 : 1; j < i; j++) { b = DeviceIoControl(handle[j], IOCTL_VOLSNAP_ABORT_PREPARED_SNAPSHOT, NULL, 0, NULL, 0, &bytes, NULL); if (!b) { printf("Abort of Prepared snapshot failed with %d\n", GetLastError()); } } return; } CoCreateGuid(&flushInput.InstanceId); flushInput.NumberOfVolumesToFlush = argc - (persistent ? 2 : 1); flushInput.SecondsToHoldFileSystemsTimeout = 60; flushInput.SecondsToHoldIrpsTimeout = 10; for (i = persistent ? 2 : 1; i < argc; i++) { context[i].Handle = handle[i]; context[i].FlushInput = &flushInput; threads[i] = CreateThread(NULL, 0, FlushAndHoldRoutine, &context[i], 0, &threadid); } WaitForMultipleObjects(argc - (persistent ? 2 : 1), &threads[persistent ? 2 : 1], TRUE, INFINITE); for (i = persistent ? 2 : 1; i < argc; i++) { b = DeviceIoControl(handle[i], IOCTL_VOLSNAP_COMMIT_SNAPSHOT, NULL, 0, NULL, 0, &bytes, NULL); if (!b) { printf("Commit failed with %d\n", GetLastError()); break; } } name = (PVOLSNAP_NAME) buffer; if (i < argc) { for (j = persistent ? 2 : 1; j < argc; j++) { b = DeviceIoControl(handle[j], IOCTL_VOLSNAP_RELEASE_WRITES, NULL, 0, NULL, 0, &bytes, NULL); } for (j = persistent ? 2 : 1; j < i; j++) { b = DeviceIoControl(handle[j], IOCTL_VOLSNAP_END_COMMIT_SNAPSHOT, NULL, 0, name, 200, &bytes, NULL); } for (; j < argc; j++) { b = DeviceIoControl(handle[j], IOCTL_VOLSNAP_ABORT_PREPARED_SNAPSHOT, NULL, 0, NULL, 0, &bytes, NULL); } return; } for (i = persistent ? 2 : 1; i < argc; i++) { b = DeviceIoControl(handle[i], IOCTL_VOLSNAP_RELEASE_WRITES, NULL, 0, NULL, 0, &bytes, NULL); if (!b) { printf("Release writes failed with %d\n", GetLastError()); } } for (i = persistent ? 2 : 1; i < argc; i++) { b = DeviceIoControl(handle[i], IOCTL_VOLSNAP_END_COMMIT_SNAPSHOT, NULL, 0, name, 200, &bytes, NULL); if (!b) { printf("End commit failed with %d\n", GetLastError()); } else { name->Name[name->NameLength/sizeof(WCHAR)] = 0; printf("%ws created.\n", name->Name); } } }