You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
189 lines
6.1 KiB
189 lines
6.1 KiB
#include <windows.h>
|
|
#include <winioctl.h>
|
|
#include <ntddsnap.h>
|
|
#include <stdio.h>
|
|
#include <objbase.h>
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|