test: dev2dos.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# dev2dos.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1989  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     dev2dos.c
    00008
    00009 Abstract:
    00010
    00011     This module implements the device object to DOS name routine.
    00012
    00013 Author:
    00014
    00015     Norbert Kusters (norbertk)  21-Oct-1998
    00016
    00017 Environment:
    00018
    00019     Kernel Mode.
    00020
    00021 Revision History:
    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 Routine Description:
    00102
    00103     This routine returns the target of the symbolic link name.
    00104
    00105 Arguments:
    00106
    00107     SymbolicLinkName    - Supplies the symbolic link name.
    00108
    00109     LinkTarget          - Returns the link target.
    00110
    00111 Return Value:
    00112
    00113     NTSTATUS
    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 Routine Description:
    00157
    00158     This routine returns the device name for the given path.  It first checks
    00159     to see if the path is a symbolic link and then checks to see if it is a
    00160     volume reparse point.
    00161
    00162 Arguments:
    00163
    00164     Path        - Supplies the path.
    00165
    00166     DeviceName  - Returns the device name.
    00167
    00168 Return Value:
    00169
    00170     NTSTATUS
    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 Routine Description:
    00233
    00234     This routine opens the reparse index on the given device.
    00235
    00236 Arguments:
    00237
    00238     DeviceName  - Supplies the device name.
    00239
    00240     Handle      - Returns the handle.
    00241
    00242 Return Value:
    00243
    00244     NTSTATUS
    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 Routine Description:
    00334
    00335     This routine queries the reparse index for the next volume mount point.
    00336
    00337 Arguments:
    00338
    00339     Handle  - Supplies the handle.
    00340
    00341     Path    - Returns the path.
    00342
    00343
    00344 Return Value:
    00345
    00346     NTSTATUS
    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 Routine Description:
    00464
    00465     This routine finds a path (if any) to the given device that begins
    00466     with the given starting path.  The final path returned includes the
    00467     starting path.
    00468
    00469 Arguments:
    00470
    00471     StartingPath    - Supplies the path to begin the search on.
    00472
    00473     DeviceName      - Supplies the device name whose path we are searching for.
    00474
    00475     DevicesInPath   - Supplies a list of the devices in all proper prefixes
    00476                             of the path.
    00477
    00478     FinalPath       - Returns the final path to the given device.
    00479
    00480 Return Value:
    00481
    00482     NTSTATUS
    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 Routine Description:
    00588
    00589     This routine returns a valid DOS path for the given device object.
    00590     This caller of this routine must call ExFreePool on DosName->Buffer
    00591     when it is no longer needed.
    00592
    00593 Arguments:
    00594
    00595     VolumeDeviceObject  - Supplies the volume device object.
    00596
    00597     DosName             - Returns the DOS name for the volume
    00598
    00599 Return Value:
    00600
    00601     NTSTATUS
    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 }