689 lines
18 KiB
C
689 lines
18 KiB
C
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dev2dos.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the device object to DOS name routine.
|
|
|
|
Author:
|
|
|
|
Norbert Kusters (norbertk) 21-Oct-1998
|
|
|
|
Environment:
|
|
|
|
Kernel Mode.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <ntrtlp.h>
|
|
#include <mountdev.h>
|
|
|
|
#ifdef POOL_TAGGING
|
|
#undef ExAllocatePool
|
|
#undef ExAllocatePoolWithQuota
|
|
#define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,' d2D')
|
|
#define ExAllocatePoolWithQuota(a,b) ExAllocatePoolWithQuotaTag(a,b,' d2D')
|
|
#endif
|
|
|
|
NTSTATUS
|
|
QuerySymbolicLink(
|
|
IN PUNICODE_STRING SymbolicLinkName,
|
|
OUT PUNICODE_STRING LinkTarget
|
|
);
|
|
|
|
NTSTATUS
|
|
QueryDeviceNameForPath(
|
|
IN PUNICODE_STRING Path,
|
|
OUT PUNICODE_STRING DeviceName
|
|
);
|
|
|
|
NTSTATUS
|
|
OpenDeviceReparseIndex(
|
|
IN PUNICODE_STRING DeviceName,
|
|
OUT PHANDLE Handle
|
|
);
|
|
|
|
BOOLEAN
|
|
IsVolumeName(
|
|
IN PUNICODE_STRING Name
|
|
);
|
|
|
|
NTSTATUS
|
|
GetNextReparseVolumePath(
|
|
IN HANDLE Handle,
|
|
OUT PUNICODE_STRING Path
|
|
);
|
|
|
|
NTSTATUS
|
|
FindPathForDevice(
|
|
IN PUNICODE_STRING StartingPath,
|
|
IN PUNICODE_STRING DeviceName,
|
|
IN OUT PLIST_ENTRY DevicesInPath,
|
|
OUT PUNICODE_STRING FinalPath
|
|
);
|
|
|
|
NTSTATUS
|
|
RtlVolumeDeviceToDosName(
|
|
IN PVOID VolumeDeviceObject,
|
|
OUT PUNICODE_STRING DosName
|
|
);
|
|
|
|
#if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
|
|
#pragma alloc_text(PAGE,QuerySymbolicLink)
|
|
#pragma alloc_text(PAGE,QueryDeviceNameForPath)
|
|
#pragma alloc_text(PAGE,OpenDeviceReparseIndex)
|
|
#pragma alloc_text(PAGE,IsVolumeName)
|
|
#pragma alloc_text(PAGE,GetNextReparseVolumePath)
|
|
#pragma alloc_text(PAGE,FindPathForDevice)
|
|
#pragma alloc_text(PAGE,RtlVolumeDeviceToDosName)
|
|
#endif
|
|
|
|
typedef struct _DEVICE_NAME_ENTRY {
|
|
LIST_ENTRY ListEntry;
|
|
UNICODE_STRING DeviceName;
|
|
} DEVICE_NAME_ENTRY, *PDEVICE_NAME_ENTRY;
|
|
|
|
NTSTATUS
|
|
QuerySymbolicLink(
|
|
IN PUNICODE_STRING SymbolicLinkName,
|
|
OUT PUNICODE_STRING LinkTarget
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the target of the symbolic link name.
|
|
|
|
Arguments:
|
|
|
|
SymbolicLinkName - Supplies the symbolic link name.
|
|
|
|
LinkTarget - Returns the link target.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
OBJECT_ATTRIBUTES oa;
|
|
NTSTATUS status;
|
|
HANDLE h;
|
|
|
|
InitializeObjectAttributes(&oa, SymbolicLinkName, OBJ_CASE_INSENSITIVE,
|
|
0, 0);
|
|
|
|
status = ZwOpenSymbolicLinkObject(&h, GENERIC_READ, &oa);
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
LinkTarget->MaximumLength = 200*sizeof(WCHAR);
|
|
LinkTarget->Length = 0;
|
|
LinkTarget->Buffer = ExAllocatePool(PagedPool, LinkTarget->MaximumLength);
|
|
if (!LinkTarget->Buffer) {
|
|
ZwClose(h);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
status = ZwQuerySymbolicLinkObject(h, LinkTarget, NULL);
|
|
ZwClose(h);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
ExFreePool(LinkTarget->Buffer);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
QueryDeviceNameForPath(
|
|
IN PUNICODE_STRING Path,
|
|
OUT PUNICODE_STRING DeviceName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the device name for the given path. It first checks
|
|
to see if the path is a symbolic link and then checks to see if it is a
|
|
volume reparse point.
|
|
|
|
Arguments:
|
|
|
|
Path - Supplies the path.
|
|
|
|
DeviceName - Returns the device name.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
OBJECT_ATTRIBUTES oa;
|
|
HANDLE h;
|
|
IO_STATUS_BLOCK ioStatus;
|
|
PREPARSE_DATA_BUFFER reparse;
|
|
UNICODE_STRING volumeName;
|
|
|
|
status = QuerySymbolicLink(Path, DeviceName);
|
|
if (NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
InitializeObjectAttributes(&oa, Path, OBJ_CASE_INSENSITIVE, 0, 0);
|
|
status = ZwOpenFile(&h, SYNCHRONIZE | FILE_GENERIC_READ, &oa, &ioStatus,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_OPEN_REPARSE_POINT | FILE_SYNCHRONOUS_IO_ALERT);
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
reparse = ExAllocatePool(PagedPool, MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
|
|
if (!reparse) {
|
|
ZwClose(h);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
status = ZwFsControlFile(h, NULL, NULL, NULL, &ioStatus,
|
|
FSCTL_GET_REPARSE_POINT, NULL, 0, reparse,
|
|
MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
|
|
ZwClose(h);
|
|
if (!NT_SUCCESS(status)) {
|
|
ExFreePool(reparse);
|
|
return status;
|
|
}
|
|
|
|
volumeName.Length = reparse->MountPointReparseBuffer.SubstituteNameLength -
|
|
sizeof(WCHAR);
|
|
volumeName.MaximumLength = volumeName.Length + sizeof(WCHAR);
|
|
volumeName.Buffer = (PWCHAR)
|
|
((PCHAR) reparse->MountPointReparseBuffer.PathBuffer +
|
|
reparse->MountPointReparseBuffer.SubstituteNameOffset);
|
|
volumeName.Buffer[volumeName.Length/sizeof(WCHAR)] = 0;
|
|
|
|
status = QuerySymbolicLink(&volumeName, DeviceName);
|
|
ExFreePool(reparse);
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
OpenDeviceReparseIndex(
|
|
IN PUNICODE_STRING DeviceName,
|
|
OUT PHANDLE Handle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine opens the reparse index on the given device.
|
|
|
|
Arguments:
|
|
|
|
DeviceName - Supplies the device name.
|
|
|
|
Handle - Returns the handle.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PFILE_OBJECT fileObject;
|
|
PDEVICE_OBJECT deviceObject;
|
|
UNICODE_STRING reparseSuffix, reparseName;
|
|
OBJECT_ATTRIBUTES oa;
|
|
IO_STATUS_BLOCK ioStatus;
|
|
|
|
status = IoGetDeviceObjectPointer(DeviceName, FILE_READ_ATTRIBUTES,
|
|
&fileObject, &deviceObject);
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
deviceObject = fileObject->DeviceObject;
|
|
|
|
if (!deviceObject->Vpb || !(deviceObject->Vpb->Flags&VPB_MOUNTED)) {
|
|
ObDereferenceObject(fileObject);
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
ObDereferenceObject(fileObject);
|
|
|
|
RtlInitUnicodeString(&reparseSuffix, L"\\$Extend\\$Reparse:$R:$INDEX_ALLOCATION");
|
|
reparseName.Length = DeviceName->Length + reparseSuffix.Length;
|
|
reparseName.MaximumLength = reparseName.Length + sizeof(WCHAR);
|
|
reparseName.Buffer = ExAllocatePool(PagedPool, reparseName.MaximumLength);
|
|
if (!reparseName.Buffer) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlCopyMemory(reparseName.Buffer, DeviceName->Buffer, DeviceName->Length);
|
|
RtlCopyMemory((PCHAR) reparseName.Buffer + DeviceName->Length,
|
|
reparseSuffix.Buffer, reparseSuffix.Length);
|
|
reparseName.Buffer[reparseName.Length/sizeof(WCHAR)] = 0;
|
|
|
|
InitializeObjectAttributes(&oa, &reparseName, OBJ_CASE_INSENSITIVE, 0, 0);
|
|
status = ZwOpenFile(Handle, SYNCHRONIZE | FILE_LIST_DIRECTORY, &oa,
|
|
&ioStatus, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_ALERT |
|
|
FILE_OPEN_FOR_BACKUP_INTENT);
|
|
|
|
ExFreePool(reparseName.Buffer);
|
|
|
|
return status;
|
|
}
|
|
|
|
BOOLEAN
|
|
IsVolumeName(
|
|
IN PUNICODE_STRING Name
|
|
)
|
|
|
|
{
|
|
if (Name->Length == 96 &&
|
|
Name->Buffer[0] == '\\' &&
|
|
Name->Buffer[1] == '?' &&
|
|
Name->Buffer[2] == '?' &&
|
|
Name->Buffer[3] == '\\' &&
|
|
Name->Buffer[4] == 'V' &&
|
|
Name->Buffer[5] == 'o' &&
|
|
Name->Buffer[6] == 'l' &&
|
|
Name->Buffer[7] == 'u' &&
|
|
Name->Buffer[8] == 'm' &&
|
|
Name->Buffer[9] == 'e' &&
|
|
Name->Buffer[10] == '{' &&
|
|
Name->Buffer[19] == '-' &&
|
|
Name->Buffer[24] == '-' &&
|
|
Name->Buffer[29] == '-' &&
|
|
Name->Buffer[34] == '-' &&
|
|
Name->Buffer[47] == '}') {
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
NTSTATUS
|
|
GetNextReparseVolumePath(
|
|
IN HANDLE Handle,
|
|
OUT PUNICODE_STRING Path
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine queries the reparse index for the next volume mount point.
|
|
|
|
Arguments:
|
|
|
|
Handle - Supplies the handle.
|
|
|
|
Path - Returns the path.
|
|
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK ioStatus;
|
|
FILE_REPARSE_POINT_INFORMATION reparseInfo;
|
|
UNICODE_STRING fileId;
|
|
OBJECT_ATTRIBUTES oa;
|
|
HANDLE h;
|
|
PREPARSE_DATA_BUFFER reparse;
|
|
UNICODE_STRING volumeName;
|
|
ULONG nameInfoSize;
|
|
PFILE_NAME_INFORMATION nameInfo;
|
|
|
|
for (;;) {
|
|
|
|
status = ZwQueryDirectoryFile(Handle, NULL, NULL, NULL, &ioStatus,
|
|
&reparseInfo, sizeof(reparseInfo),
|
|
FileReparsePointInformation, TRUE, NULL,
|
|
FALSE);
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
if (reparseInfo.Tag != IO_REPARSE_TAG_MOUNT_POINT) {
|
|
continue;
|
|
}
|
|
|
|
fileId.Length = sizeof(reparseInfo.FileReference);
|
|
fileId.MaximumLength = fileId.Length;
|
|
fileId.Buffer = (PWSTR) &reparseInfo.FileReference;
|
|
|
|
InitializeObjectAttributes(&oa, &fileId, 0, Handle, NULL);
|
|
|
|
status = ZwOpenFile(&h, SYNCHRONIZE | FILE_GENERIC_READ, &oa,
|
|
&ioStatus, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_OPEN_BY_FILE_ID | FILE_OPEN_REPARSE_POINT |
|
|
FILE_SYNCHRONOUS_IO_ALERT);
|
|
if (!NT_SUCCESS(status)) {
|
|
continue;
|
|
}
|
|
|
|
reparse = ExAllocatePool(PagedPool, MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
|
|
if (!reparse) {
|
|
ZwClose(h);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
status = ZwFsControlFile(h, NULL, NULL, NULL, &ioStatus,
|
|
FSCTL_GET_REPARSE_POINT, NULL, 0, reparse,
|
|
MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
|
|
if (!NT_SUCCESS(status)) {
|
|
ExFreePool(reparse);
|
|
ZwClose(h);
|
|
continue;
|
|
}
|
|
|
|
volumeName.Length = reparse->MountPointReparseBuffer.SubstituteNameLength -
|
|
sizeof(WCHAR);
|
|
volumeName.MaximumLength = volumeName.Length + sizeof(WCHAR);
|
|
volumeName.Buffer = (PWCHAR)
|
|
((PCHAR) reparse->MountPointReparseBuffer.PathBuffer +
|
|
reparse->MountPointReparseBuffer.SubstituteNameOffset);
|
|
volumeName.Buffer[volumeName.Length/sizeof(WCHAR)] = 0;
|
|
|
|
if (!IsVolumeName(&volumeName)) {
|
|
ExFreePool(reparse);
|
|
ZwClose(h);
|
|
continue;
|
|
}
|
|
|
|
ExFreePool(reparse);
|
|
|
|
nameInfoSize = 1024;
|
|
nameInfo = ExAllocatePool(PagedPool, nameInfoSize);
|
|
if (!nameInfo) {
|
|
ZwClose(h);
|
|
continue;
|
|
}
|
|
|
|
status = ZwQueryInformationFile(h, &ioStatus, nameInfo, nameInfoSize,
|
|
FileNameInformation);
|
|
ZwClose(h);
|
|
if (!NT_SUCCESS(status)) {
|
|
continue;
|
|
}
|
|
|
|
Path->Length = (USHORT) nameInfo->FileNameLength;
|
|
Path->MaximumLength = Path->Length + sizeof(WCHAR);
|
|
Path->Buffer = ExAllocatePool(PagedPool, Path->MaximumLength);
|
|
if (!Path->Buffer) {
|
|
ExFreePool(nameInfo);
|
|
continue;
|
|
}
|
|
|
|
RtlCopyMemory(Path->Buffer, nameInfo->FileName, Path->Length);
|
|
Path->Buffer[Path->Length/sizeof(WCHAR)] = 0;
|
|
|
|
ExFreePool(nameInfo);
|
|
break;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
FindPathForDevice(
|
|
IN PUNICODE_STRING StartingPath,
|
|
IN PUNICODE_STRING DeviceName,
|
|
IN OUT PLIST_ENTRY DevicesInPath,
|
|
OUT PUNICODE_STRING FinalPath
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine finds a path (if any) to the given device that begins
|
|
with the given starting path. The final path returned includes the
|
|
starting path.
|
|
|
|
Arguments:
|
|
|
|
StartingPath - Supplies the path to begin the search on.
|
|
|
|
DeviceName - Supplies the device name whose path we are searching for.
|
|
|
|
DevicesInPath - Supplies a list of the devices in all proper prefixes
|
|
of the path.
|
|
|
|
FinalPath - Returns the final path to the given device.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
UNICODE_STRING startingDeviceName;
|
|
PLIST_ENTRY l;
|
|
PDEVICE_NAME_ENTRY entry;
|
|
HANDLE h;
|
|
UNICODE_STRING path, newStart;
|
|
|
|
status = QueryDeviceNameForPath(StartingPath, &startingDeviceName);
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
if (RtlEqualUnicodeString(DeviceName, &startingDeviceName, TRUE)) {
|
|
ExFreePool(startingDeviceName.Buffer);
|
|
FinalPath->Length = StartingPath->Length;
|
|
FinalPath->MaximumLength = FinalPath->Length + sizeof(WCHAR);
|
|
FinalPath->Buffer = ExAllocatePool(PagedPool, FinalPath->MaximumLength);
|
|
if (!FinalPath->Buffer) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlCopyMemory(FinalPath->Buffer, StartingPath->Buffer,
|
|
FinalPath->Length);
|
|
FinalPath->Buffer[FinalPath->Length/sizeof(WCHAR)] = 0;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
for (l = DevicesInPath->Flink; l != DevicesInPath; l = l->Flink) {
|
|
entry = CONTAINING_RECORD(l, DEVICE_NAME_ENTRY, ListEntry);
|
|
if (RtlEqualUnicodeString(&entry->DeviceName, &startingDeviceName,
|
|
TRUE)) {
|
|
|
|
ExFreePool(startingDeviceName.Buffer);
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
}
|
|
|
|
status = OpenDeviceReparseIndex(&startingDeviceName, &h);
|
|
if (!NT_SUCCESS(status)) {
|
|
ExFreePool(startingDeviceName.Buffer);
|
|
return status;
|
|
}
|
|
|
|
entry = ExAllocatePool(PagedPool, sizeof(DEVICE_NAME_ENTRY));
|
|
if (!entry) {
|
|
ZwClose(h);
|
|
ExFreePool(startingDeviceName.Buffer);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
entry->DeviceName = startingDeviceName;
|
|
InsertTailList(DevicesInPath, &entry->ListEntry);
|
|
|
|
for (;;) {
|
|
|
|
status = GetNextReparseVolumePath(h, &path);
|
|
if (!NT_SUCCESS(status)) {
|
|
break;
|
|
}
|
|
newStart.Length = StartingPath->Length + path.Length;
|
|
newStart.MaximumLength = newStart.Length + sizeof(WCHAR);
|
|
newStart.Buffer = ExAllocatePool(PagedPool, newStart.MaximumLength);
|
|
if (!newStart.Buffer) {
|
|
ExFreePool(path.Buffer);
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
RtlCopyMemory(newStart.Buffer, StartingPath->Buffer,
|
|
StartingPath->Length);
|
|
RtlCopyMemory((PCHAR) newStart.Buffer + StartingPath->Length,
|
|
path.Buffer, path.Length);
|
|
newStart.Buffer[newStart.Length/sizeof(WCHAR)] = 0;
|
|
ExFreePool(path.Buffer);
|
|
|
|
status = FindPathForDevice(&newStart, DeviceName, DevicesInPath,
|
|
FinalPath);
|
|
ExFreePool(newStart.Buffer);
|
|
if (NT_SUCCESS(status)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
RemoveEntryList(&entry->ListEntry);
|
|
ExFreePool(entry);
|
|
ZwClose(h);
|
|
ExFreePool(startingDeviceName.Buffer);
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RtlVolumeDeviceToDosName(
|
|
IN PVOID VolumeDeviceObject,
|
|
OUT PUNICODE_STRING DosName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns a valid DOS path for the given device object.
|
|
This caller of this routine must call ExFreePool on DosName->Buffer
|
|
when it is no longer needed.
|
|
|
|
Arguments:
|
|
|
|
VolumeDeviceObject - Supplies the volume device object.
|
|
|
|
DosName - Returns the DOS name for the volume
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
PDEVICE_OBJECT volumeDeviceObject = VolumeDeviceObject;
|
|
PMOUNTDEV_NAME name;
|
|
CHAR output[512];
|
|
KEVENT event;
|
|
PIRP irp;
|
|
IO_STATUS_BLOCK ioStatus;
|
|
NTSTATUS status;
|
|
UNICODE_STRING deviceName;
|
|
WCHAR buffer[30];
|
|
UNICODE_STRING driveLetterName;
|
|
WCHAR c;
|
|
UNICODE_STRING linkTarget;
|
|
LIST_ENTRY devicesInPath;
|
|
|
|
name = (PMOUNTDEV_NAME) output;
|
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|
irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
|
|
volumeDeviceObject, NULL, 0, name, 512,
|
|
FALSE, &event, &ioStatus);
|
|
if (!irp) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
status = IoCallDriver(volumeDeviceObject, irp);
|
|
if (status == STATUS_PENDING) {
|
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|
status = ioStatus.Status;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
deviceName.MaximumLength = deviceName.Length = name->NameLength;
|
|
deviceName.Buffer = name->Name;
|
|
|
|
swprintf(buffer, L"\\??\\C:");
|
|
RtlInitUnicodeString(&driveLetterName, buffer);
|
|
|
|
for (c = 'A'; c <= 'Z'; c++) {
|
|
driveLetterName.Buffer[4] = c;
|
|
|
|
status = QuerySymbolicLink(&driveLetterName, &linkTarget);
|
|
if (!NT_SUCCESS(status)) {
|
|
continue;
|
|
}
|
|
|
|
if (RtlEqualUnicodeString(&linkTarget, &deviceName, TRUE)) {
|
|
ExFreePool(linkTarget.Buffer);
|
|
break;
|
|
}
|
|
|
|
ExFreePool(linkTarget.Buffer);
|
|
}
|
|
|
|
if (c <= 'Z') {
|
|
DosName->Buffer = ExAllocatePool(PagedPool, 3*sizeof(WCHAR));
|
|
if (!DosName->Buffer) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
DosName->MaximumLength = 6;
|
|
DosName->Length = 4;
|
|
DosName->Buffer[0] = c;
|
|
DosName->Buffer[1] = ':';
|
|
DosName->Buffer[2] = 0;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
for (c = 'A'; c <= 'Z'; c++) {
|
|
driveLetterName.Buffer[4] = c;
|
|
InitializeListHead(&devicesInPath);
|
|
status = FindPathForDevice(&driveLetterName, &deviceName,
|
|
&devicesInPath, DosName);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
DosName->Length -= 4*sizeof(WCHAR);
|
|
RtlMoveMemory(DosName->Buffer, &DosName->Buffer[4],
|
|
DosName->Length);
|
|
DosName->Buffer[DosName->Length/sizeof(WCHAR)] = 0;
|
|
return status;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|