00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
#include <ntrtlp.h>
00026
#include <mountdev.h>
00027
00028
#ifdef POOL_TAGGING
00029
#undef ExAllocatePool
00030
#undef ExAllocatePoolWithQuota
00031
#define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,' d2D')
00032
#define ExAllocatePoolWithQuota(a,b) ExAllocatePoolWithQuotaTag(a,b,' d2D')
00033
#endif
00034
00035
NTSTATUS
00036
QuerySymbolicLink(
00037 IN PUNICODE_STRING SymbolicLinkName,
00038 OUT PUNICODE_STRING LinkTarget
00039 );
00040
00041
NTSTATUS
00042
QueryDeviceNameForPath(
00043 IN PUNICODE_STRING Path,
00044 OUT PUNICODE_STRING DeviceName
00045 );
00046
00047
NTSTATUS
00048
OpenDeviceReparseIndex(
00049 IN PUNICODE_STRING DeviceName,
00050 OUT PHANDLE Handle
00051 );
00052
00053 BOOLEAN
00054
IsVolumeName(
00055 IN PUNICODE_STRING Name
00056 );
00057
00058
NTSTATUS
00059
GetNextReparseVolumePath(
00060 IN HANDLE Handle,
00061 OUT PUNICODE_STRING Path
00062 );
00063
00064
NTSTATUS
00065
FindPathForDevice(
00066 IN PUNICODE_STRING StartingPath,
00067 IN PUNICODE_STRING DeviceName,
00068 IN OUT PLIST_ENTRY DevicesInPath,
00069 OUT PUNICODE_STRING FinalPath
00070 );
00071
00072
NTSTATUS
00073
RtlVolumeDeviceToDosName(
00074 IN PVOID VolumeDeviceObject,
00075 OUT PUNICODE_STRING DosName
00076 );
00077
00078
#if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
00079
#pragma alloc_text(PAGE,QuerySymbolicLink)
00080
#pragma alloc_text(PAGE,QueryDeviceNameForPath)
00081
#pragma alloc_text(PAGE,OpenDeviceReparseIndex)
00082
#pragma alloc_text(PAGE,IsVolumeName)
00083
#pragma alloc_text(PAGE,GetNextReparseVolumePath)
00084
#pragma alloc_text(PAGE,FindPathForDevice)
00085
#pragma alloc_text(PAGE,RtlVolumeDeviceToDosName)
00086
#endif
00087
00088 typedef struct _DEVICE_NAME_ENTRY {
00089 LIST_ENTRY
ListEntry;
00090 UNICODE_STRING
DeviceName;
00091 }
DEVICE_NAME_ENTRY, *
PDEVICE_NAME_ENTRY;
00092
00093
NTSTATUS
00094 QuerySymbolicLink(
00095 IN PUNICODE_STRING SymbolicLinkName,
00096 OUT PUNICODE_STRING LinkTarget
00097 )
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117 {
00118 OBJECT_ATTRIBUTES oa;
00119
NTSTATUS status;
00120 HANDLE h;
00121
00122 InitializeObjectAttributes(&oa, SymbolicLinkName, OBJ_CASE_INSENSITIVE,
00123 0, 0);
00124
00125 status = ZwOpenSymbolicLinkObject(&h, GENERIC_READ, &oa);
00126
if (!
NT_SUCCESS(status)) {
00127
return status;
00128 }
00129
00130 LinkTarget->MaximumLength = 200*
sizeof(WCHAR);
00131 LinkTarget->Length = 0;
00132 LinkTarget->Buffer =
ExAllocatePool(
PagedPool, LinkTarget->MaximumLength);
00133
if (!LinkTarget->Buffer) {
00134 ZwClose(h);
00135
return STATUS_INSUFFICIENT_RESOURCES;
00136 }
00137
00138 status = ZwQuerySymbolicLinkObject(h, LinkTarget,
NULL);
00139 ZwClose(h);
00140
00141
if (!
NT_SUCCESS(status)) {
00142
ExFreePool(LinkTarget->Buffer);
00143 }
00144
00145
return status;
00146 }
00147
00148
NTSTATUS
00149 QueryDeviceNameForPath(
00150 IN PUNICODE_STRING Path,
00151 OUT PUNICODE_STRING DeviceName
00152 )
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174 {
00175
NTSTATUS status;
00176 OBJECT_ATTRIBUTES oa;
00177 HANDLE h;
00178 IO_STATUS_BLOCK ioStatus;
00179 PREPARSE_DATA_BUFFER reparse;
00180 UNICODE_STRING volumeName;
00181
00182 status =
QuerySymbolicLink(Path, DeviceName);
00183
if (
NT_SUCCESS(status)) {
00184
return status;
00185 }
00186
00187 InitializeObjectAttributes(&oa, Path, OBJ_CASE_INSENSITIVE, 0, 0);
00188 status =
ZwOpenFile(&h, SYNCHRONIZE | FILE_GENERIC_READ, &oa, &ioStatus,
00189 FILE_SHARE_READ | FILE_SHARE_WRITE,
00190 FILE_OPEN_REPARSE_POINT | FILE_SYNCHRONOUS_IO_ALERT);
00191
if (!
NT_SUCCESS(status)) {
00192
return status;
00193 }
00194
00195 reparse =
ExAllocatePool(
PagedPool, MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
00196
if (!reparse) {
00197 ZwClose(h);
00198
return STATUS_INSUFFICIENT_RESOURCES;
00199 }
00200
00201 status = ZwFsControlFile(h,
NULL,
NULL,
NULL, &ioStatus,
00202 FSCTL_GET_REPARSE_POINT,
NULL, 0, reparse,
00203 MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
00204 ZwClose(h);
00205
if (!
NT_SUCCESS(status)) {
00206
ExFreePool(reparse);
00207
return status;
00208 }
00209
00210 volumeName.Length = reparse->MountPointReparseBuffer.SubstituteNameLength -
00211
sizeof(WCHAR);
00212 volumeName.MaximumLength = volumeName.Length +
sizeof(WCHAR);
00213 volumeName.Buffer = (PWCHAR)
00214 ((PCHAR) reparse->MountPointReparseBuffer.PathBuffer +
00215 reparse->MountPointReparseBuffer.SubstituteNameOffset);
00216 volumeName.Buffer[volumeName.Length/
sizeof(WCHAR)] = 0;
00217
00218 status =
QuerySymbolicLink(&volumeName, DeviceName);
00219
ExFreePool(reparse);
00220
00221
return status;
00222 }
00223
00224
NTSTATUS
00225 OpenDeviceReparseIndex(
00226 IN PUNICODE_STRING DeviceName,
00227 OUT PHANDLE Handle
00228 )
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248 {
00249
NTSTATUS status;
00250
PFILE_OBJECT fileObject;
00251
PDEVICE_OBJECT deviceObject;
00252 UNICODE_STRING reparseSuffix, reparseName;
00253 OBJECT_ATTRIBUTES oa;
00254 IO_STATUS_BLOCK ioStatus;
00255
00256 status =
IoGetDeviceObjectPointer(DeviceName, FILE_READ_ATTRIBUTES,
00257 &fileObject, &deviceObject);
00258
if (!
NT_SUCCESS(status)) {
00259
return status;
00260 }
00261 deviceObject = fileObject->
DeviceObject;
00262
00263
if (!deviceObject->
Vpb || !(deviceObject->
Vpb->
Flags&
VPB_MOUNTED)) {
00264
ObDereferenceObject(fileObject);
00265
return STATUS_UNSUCCESSFUL;
00266 }
00267
00268
ObDereferenceObject(fileObject);
00269
00270
RtlInitUnicodeString(&reparseSuffix,
00271
L"\\$Extend\\$Reparse:$R:$INDEX_ALLOCATION");
00272 reparseName.Length = DeviceName->Length + reparseSuffix.Length;
00273 reparseName.MaximumLength = reparseName.Length +
sizeof(WCHAR);
00274 reparseName.Buffer =
ExAllocatePool(
PagedPool, reparseName.MaximumLength);
00275
if (!reparseName.Buffer) {
00276
return STATUS_INSUFFICIENT_RESOURCES;
00277 }
00278
00279 RtlCopyMemory(reparseName.Buffer, DeviceName->Buffer, DeviceName->Length);
00280 RtlCopyMemory((PCHAR) reparseName.Buffer + DeviceName->Length,
00281 reparseSuffix.Buffer, reparseSuffix.Length);
00282 reparseName.Buffer[reparseName.Length/
sizeof(WCHAR)] = 0;
00283
00284 InitializeObjectAttributes(&oa, &reparseName, OBJ_CASE_INSENSITIVE, 0, 0);
00285 status =
ZwOpenFile(
Handle, SYNCHRONIZE | FILE_LIST_DIRECTORY, &oa,
00286 &ioStatus, FILE_SHARE_READ | FILE_SHARE_WRITE,
00287 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_ALERT |
00288 FILE_OPEN_FOR_BACKUP_INTENT);
00289
00290
ExFreePool(reparseName.Buffer);
00291
00292
return status;
00293 }
00294
00295 BOOLEAN
00296 IsVolumeName(
00297 IN PUNICODE_STRING Name
00298 )
00299
00300 {
00301
if (
Name->Length == 96 &&
00302
Name->Buffer[0] ==
'\\' &&
00303
Name->Buffer[1] ==
'?' &&
00304
Name->Buffer[2] ==
'?' &&
00305
Name->Buffer[3] ==
'\\' &&
00306
Name->Buffer[4] ==
'V' &&
00307
Name->Buffer[5] ==
'o' &&
00308
Name->Buffer[6] ==
'l' &&
00309
Name->Buffer[7] ==
'u' &&
00310
Name->Buffer[8] ==
'm' &&
00311
Name->Buffer[9] ==
'e' &&
00312
Name->Buffer[10] ==
'{' &&
00313
Name->Buffer[19] ==
'-' &&
00314
Name->Buffer[24] ==
'-' &&
00315
Name->Buffer[29] ==
'-' &&
00316
Name->Buffer[34] ==
'-' &&
00317
Name->Buffer[47] ==
'}') {
00318
00319
return TRUE;
00320 }
00321
00322
return FALSE;
00323 }
00324
00325
NTSTATUS
00326 GetNextReparseVolumePath(
00327 IN HANDLE Handle,
00328 OUT PUNICODE_STRING Path
00329 )
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350 {
00351
NTSTATUS status;
00352 IO_STATUS_BLOCK ioStatus;
00353 FILE_REPARSE_POINT_INFORMATION reparseInfo;
00354 UNICODE_STRING fileId;
00355 OBJECT_ATTRIBUTES oa;
00356 HANDLE h;
00357 PREPARSE_DATA_BUFFER reparse;
00358 UNICODE_STRING volumeName;
00359 ULONG nameInfoSize;
00360 PFILE_NAME_INFORMATION nameInfo;
00361
00362
for (;;) {
00363
00364 status = ZwQueryDirectoryFile(
Handle,
NULL,
NULL,
NULL, &ioStatus,
00365 &reparseInfo,
sizeof(reparseInfo),
00366 FileReparsePointInformation,
TRUE,
NULL,
00367
FALSE);
00368
if (!
NT_SUCCESS(status)) {
00369
return status;
00370 }
00371
00372
if (reparseInfo.Tag != IO_REPARSE_TAG_MOUNT_POINT) {
00373
continue;
00374 }
00375
00376 fileId.Length =
sizeof(reparseInfo.FileReference);
00377 fileId.MaximumLength = fileId.Length;
00378 fileId.Buffer = (PWSTR) &reparseInfo.FileReference;
00379
00380 InitializeObjectAttributes(&oa, &fileId, 0,
Handle,
NULL);
00381
00382 status =
ZwOpenFile(&h, SYNCHRONIZE | FILE_GENERIC_READ, &oa,
00383 &ioStatus, FILE_SHARE_READ | FILE_SHARE_WRITE,
00384 FILE_OPEN_BY_FILE_ID | FILE_OPEN_REPARSE_POINT |
00385 FILE_SYNCHRONOUS_IO_ALERT);
00386
if (!
NT_SUCCESS(status)) {
00387
continue;
00388 }
00389
00390 reparse =
ExAllocatePool(
PagedPool, MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
00391
if (!reparse) {
00392 ZwClose(h);
00393
return STATUS_INSUFFICIENT_RESOURCES;
00394 }
00395
00396 status = ZwFsControlFile(h,
NULL,
NULL,
NULL, &ioStatus,
00397 FSCTL_GET_REPARSE_POINT,
NULL, 0, reparse,
00398 MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
00399
if (!
NT_SUCCESS(status)) {
00400
ExFreePool(reparse);
00401 ZwClose(h);
00402
continue;
00403 }
00404
00405 volumeName.Length = reparse->MountPointReparseBuffer.SubstituteNameLength -
00406
sizeof(WCHAR);
00407 volumeName.MaximumLength = volumeName.Length +
sizeof(WCHAR);
00408 volumeName.Buffer = (PWCHAR)
00409 ((PCHAR) reparse->MountPointReparseBuffer.PathBuffer +
00410 reparse->MountPointReparseBuffer.SubstituteNameOffset);
00411 volumeName.Buffer[volumeName.Length/
sizeof(WCHAR)] = 0;
00412
00413
if (!
IsVolumeName(&volumeName)) {
00414
ExFreePool(reparse);
00415 ZwClose(h);
00416
continue;
00417 }
00418
00419
ExFreePool(reparse);
00420
00421 nameInfoSize = 1024;
00422 nameInfo =
ExAllocatePool(
PagedPool, nameInfoSize);
00423
if (!nameInfo) {
00424 ZwClose(h);
00425
continue;
00426 }
00427
00428 status = ZwQueryInformationFile(h, &ioStatus, nameInfo, nameInfoSize,
00429 FileNameInformation);
00430 ZwClose(h);
00431
if (!
NT_SUCCESS(status)) {
00432
continue;
00433 }
00434
00435 Path->Length = (
USHORT) nameInfo->FileNameLength;
00436 Path->MaximumLength = Path->Length +
sizeof(WCHAR);
00437 Path->Buffer =
ExAllocatePool(
PagedPool, Path->MaximumLength);
00438
if (!Path->Buffer) {
00439
ExFreePool(nameInfo);
00440
continue;
00441 }
00442
00443 RtlCopyMemory(Path->Buffer, nameInfo->FileName, Path->Length);
00444 Path->Buffer[Path->Length/
sizeof(WCHAR)] = 0;
00445
00446
ExFreePool(nameInfo);
00447
break;
00448 }
00449
00450
return status;
00451 }
00452
00453
NTSTATUS
00454 FindPathForDevice(
00455 IN PUNICODE_STRING StartingPath,
00456 IN PUNICODE_STRING DeviceName,
00457 IN OUT PLIST_ENTRY DevicesInPath,
00458 OUT PUNICODE_STRING FinalPath
00459 )
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486 {
00487
NTSTATUS status;
00488 UNICODE_STRING startingDeviceName;
00489 PLIST_ENTRY l;
00490
PDEVICE_NAME_ENTRY entry;
00491 HANDLE h;
00492 UNICODE_STRING
path, newStart;
00493
00494 status =
QueryDeviceNameForPath(StartingPath, &startingDeviceName);
00495
if (!
NT_SUCCESS(status)) {
00496
return status;
00497 }
00498
00499
if (
RtlEqualUnicodeString(DeviceName, &startingDeviceName,
TRUE)) {
00500
ExFreePool(startingDeviceName.Buffer);
00501 FinalPath->Length = StartingPath->Length;
00502 FinalPath->MaximumLength = FinalPath->Length +
sizeof(WCHAR);
00503 FinalPath->Buffer =
ExAllocatePool(
PagedPool,
00504 FinalPath->MaximumLength);
00505
if (!FinalPath->Buffer) {
00506
return STATUS_INSUFFICIENT_RESOURCES;
00507 }
00508
00509 RtlCopyMemory(FinalPath->Buffer, StartingPath->Buffer,
00510 FinalPath->Length);
00511 FinalPath->Buffer[FinalPath->Length/
sizeof(WCHAR)] = 0;
00512
00513
return STATUS_SUCCESS;
00514 }
00515
00516
for (l = DevicesInPath->Flink; l != DevicesInPath; l = l->Flink) {
00517 entry = CONTAINING_RECORD(l,
DEVICE_NAME_ENTRY, ListEntry);
00518
if (
RtlEqualUnicodeString(&entry->
DeviceName, &startingDeviceName,
00519
TRUE)) {
00520
00521
ExFreePool(startingDeviceName.Buffer);
00522
return STATUS_UNSUCCESSFUL;
00523 }
00524 }
00525
00526 status =
OpenDeviceReparseIndex(&startingDeviceName, &h);
00527
if (!
NT_SUCCESS(status)) {
00528
ExFreePool(startingDeviceName.Buffer);
00529
return status;
00530 }
00531
00532 entry =
ExAllocatePool(
PagedPool,
sizeof(
DEVICE_NAME_ENTRY));
00533
if (!entry) {
00534 ZwClose(h);
00535
ExFreePool(startingDeviceName.Buffer);
00536
return STATUS_INSUFFICIENT_RESOURCES;
00537 }
00538 entry->
DeviceName = startingDeviceName;
00539 InsertTailList(DevicesInPath, &entry->
ListEntry);
00540
00541
for (;;) {
00542
00543 status =
GetNextReparseVolumePath(h, &
path);
00544
if (!
NT_SUCCESS(status)) {
00545
break;
00546 }
00547 newStart.Length = StartingPath->Length +
path.Length;
00548 newStart.MaximumLength = newStart.Length +
sizeof(WCHAR);
00549 newStart.Buffer =
ExAllocatePool(
PagedPool, newStart.MaximumLength);
00550
if (!newStart.Buffer) {
00551
ExFreePool(
path.Buffer);
00552 status = STATUS_INSUFFICIENT_RESOURCES;
00553
break;
00554 }
00555
00556 RtlCopyMemory(newStart.Buffer, StartingPath->Buffer,
00557 StartingPath->Length);
00558 RtlCopyMemory((PCHAR) newStart.Buffer + StartingPath->Length,
00559
path.Buffer,
path.Length);
00560 newStart.Buffer[newStart.Length/
sizeof(WCHAR)] = 0;
00561
ExFreePool(
path.Buffer);
00562
00563 status =
FindPathForDevice(&newStart, DeviceName, DevicesInPath,
00564 FinalPath);
00565
ExFreePool(newStart.Buffer);
00566
if (
NT_SUCCESS(status)) {
00567
break;
00568 }
00569 }
00570
00571 RemoveEntryList(&entry->
ListEntry);
00572
ExFreePool(entry);
00573 ZwClose(h);
00574
ExFreePool(startingDeviceName.Buffer);
00575
00576
return status;
00577 }
00578
00579
NTSTATUS
00580 RtlVolumeDeviceToDosName(
00581 IN PVOID VolumeDeviceObject,
00582 OUT PUNICODE_STRING DosName
00583 )
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605 {
00606
PDEVICE_OBJECT volumeDeviceObject = VolumeDeviceObject;
00607 PMOUNTDEV_NAME name;
00608
CHAR output[512];
00609
KEVENT event;
00610
PIRP irp;
00611 IO_STATUS_BLOCK ioStatus;
00612
NTSTATUS status;
00613 UNICODE_STRING deviceName;
00614 WCHAR buffer[30];
00615 UNICODE_STRING driveLetterName;
00616 WCHAR
c;
00617 UNICODE_STRING linkTarget;
00618 LIST_ENTRY devicesInPath;
00619
00620 name = (PMOUNTDEV_NAME) output;
00621
KeInitializeEvent(&event, NotificationEvent,
FALSE);
00622 irp =
IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
00623 volumeDeviceObject,
NULL, 0, name, 512,
00624
FALSE, &event, &ioStatus);
00625
if (!irp) {
00626
return STATUS_INSUFFICIENT_RESOURCES;
00627 }
00628
00629 status =
IoCallDriver(volumeDeviceObject, irp);
00630
if (status == STATUS_PENDING) {
00631
KeWaitForSingleObject(&event,
Executive,
KernelMode,
FALSE,
NULL);
00632 status = ioStatus.Status;
00633 }
00634
00635
if (!
NT_SUCCESS(status)) {
00636
return status;
00637 }
00638
00639 deviceName.MaximumLength = deviceName.Length = name->NameLength;
00640 deviceName.Buffer = name->Name;
00641
00642 swprintf(buffer,
L"\\??\\C:");
00643
RtlInitUnicodeString(&driveLetterName, buffer);
00644
00645
for (
c =
'A';
c <=
'Z';
c++) {
00646 driveLetterName.Buffer[4] =
c;
00647
00648 status =
QuerySymbolicLink(&driveLetterName, &linkTarget);
00649
if (!
NT_SUCCESS(status)) {
00650
continue;
00651 }
00652
00653
if (
RtlEqualUnicodeString(&linkTarget, &deviceName,
TRUE)) {
00654
ExFreePool(linkTarget.Buffer);
00655
break;
00656 }
00657
00658
ExFreePool(linkTarget.Buffer);
00659 }
00660
00661
if (
c <=
'Z') {
00662 DosName->Buffer =
ExAllocatePool(
PagedPool, 3*
sizeof(WCHAR));
00663
if (!DosName->Buffer) {
00664
return STATUS_INSUFFICIENT_RESOURCES;
00665 }
00666 DosName->MaximumLength = 6;
00667 DosName->Length = 4;
00668 DosName->Buffer[0] =
c;
00669 DosName->Buffer[1] =
':';
00670 DosName->Buffer[2] = 0;
00671
return STATUS_SUCCESS;
00672 }
00673
00674
for (
c =
'A';
c <=
'Z';
c++) {
00675 driveLetterName.Buffer[4] =
c;
00676 InitializeListHead(&devicesInPath);
00677 status =
FindPathForDevice(&driveLetterName, &deviceName,
00678 &devicesInPath, DosName);
00679
00680
if (
NT_SUCCESS(status)) {
00681 DosName->Length -= 4*
sizeof(WCHAR);
00682 RtlMoveMemory(DosName->Buffer, &DosName->Buffer[4],
00683 DosName->Length);
00684 DosName->Buffer[DosName->Length/
sizeof(WCHAR)] = 0;
00685
return status;
00686 }
00687 }
00688
00689
return status;
00690 }