mirror of
https://github.com/reactos/reactos.git
synced 2025-05-20 17:45:06 +00:00
[KERNEL32]: Reimplement GetDriveTypeW(). This allows providing a quick path for DOS drives and fixes a few detection cases. It allows brings in support for mount points.
This commit is contained in:
parent
676bd0cf37
commit
cb17d5dba4
4 changed files with 189 additions and 75 deletions
|
@ -23,7 +23,6 @@
|
||||||
|
|
||||||
#define NDEBUG
|
#define NDEBUG
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
DEBUG_CHANNEL(kernel32file);
|
|
||||||
|
|
||||||
#define MAX_DOS_DRIVES 26
|
#define MAX_DOS_DRIVES 26
|
||||||
|
|
||||||
|
@ -482,127 +481,228 @@ UINT
|
||||||
WINAPI
|
WINAPI
|
||||||
GetDriveTypeW(IN LPCWSTR lpRootPathName)
|
GetDriveTypeW(IN LPCWSTR lpRootPathName)
|
||||||
{
|
{
|
||||||
FILE_FS_DEVICE_INFORMATION FileFsDevice;
|
BOOL RetryOpen;
|
||||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
PCWSTR RootPath;
|
||||||
IO_STATUS_BLOCK IoStatusBlock;
|
|
||||||
UNICODE_STRING PathName;
|
|
||||||
HANDLE FileHandle;
|
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
PWSTR CurrentDir = NULL;
|
WCHAR DriveLetter;
|
||||||
PCWSTR lpRootPath;
|
HANDLE RootHandle;
|
||||||
|
IO_STATUS_BLOCK IoStatusBlock;
|
||||||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
|
UNICODE_STRING PathName, VolumeString;
|
||||||
|
FILE_FS_DEVICE_INFORMATION FileFsDevice;
|
||||||
|
WCHAR Buffer[MAX_PATH], VolumeName[MAX_PATH];
|
||||||
|
|
||||||
if (!lpRootPathName)
|
/* If no path, get one */
|
||||||
|
if (lpRootPathName == NULL)
|
||||||
{
|
{
|
||||||
/* If NULL is passed, use current directory path */
|
RootPath = Buffer;
|
||||||
DWORD BufferSize = GetCurrentDirectoryW(0, NULL);
|
/* This will be current drive (<letter>:\ - drop the rest)*/
|
||||||
CurrentDir = HeapAlloc(GetProcessHeap(), 0, BufferSize * sizeof(WCHAR));
|
if (RtlGetCurrentDirectory_U(sizeof(Buffer), Buffer) > 3 * sizeof(WCHAR))
|
||||||
if (!CurrentDir)
|
|
||||||
return DRIVE_UNKNOWN;
|
|
||||||
if (!GetCurrentDirectoryW(BufferSize, CurrentDir))
|
|
||||||
{
|
{
|
||||||
HeapFree(GetProcessHeap(), 0, CurrentDir);
|
Buffer[3] = UNICODE_NULL;
|
||||||
return DRIVE_UNKNOWN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wcslen(CurrentDir) > 3)
|
|
||||||
CurrentDir[3] = 0;
|
|
||||||
|
|
||||||
lpRootPath = CurrentDir;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
size_t Length = wcslen(lpRootPathName);
|
/* Handle broken value */
|
||||||
|
if (lpRootPathName == (PVOID)-1)
|
||||||
TRACE("lpRootPathName: %S\n", lpRootPathName);
|
|
||||||
|
|
||||||
lpRootPath = lpRootPathName;
|
|
||||||
if (Length == 2)
|
|
||||||
{
|
{
|
||||||
WCHAR DriveLetter = RtlUpcaseUnicodeChar(lpRootPathName[0]);
|
return DRIVE_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
RootPath = lpRootPathName;
|
||||||
|
/* If provided path is 2-len, it might be a drive letter... */
|
||||||
|
if (wcslen(lpRootPathName) == 2)
|
||||||
|
{
|
||||||
|
/* Check it! */
|
||||||
|
DriveLetter = RtlUpcaseUnicodeChar(lpRootPathName[0]);
|
||||||
|
/* That's a drive letter! */
|
||||||
if (DriveLetter >= L'A' && DriveLetter <= L'Z' && lpRootPathName[1] == L':')
|
if (DriveLetter >= L'A' && DriveLetter <= L'Z' && lpRootPathName[1] == L':')
|
||||||
{
|
{
|
||||||
Length = (Length + 2) * sizeof(WCHAR);
|
/* Make it a volume */
|
||||||
|
Buffer[0] = DriveLetter;
|
||||||
CurrentDir = HeapAlloc(GetProcessHeap(), 0, Length);
|
Buffer[1] = L':';
|
||||||
if (!CurrentDir)
|
Buffer[2] = L'\\';
|
||||||
return DRIVE_UNKNOWN;
|
Buffer[3] = UNICODE_NULL;
|
||||||
|
RootPath = Buffer;
|
||||||
StringCbPrintfW(CurrentDir, Length, L"%s\\", lpRootPathName);
|
|
||||||
|
|
||||||
lpRootPath = CurrentDir;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE("lpRootPath: %S\n", lpRootPath);
|
/* If the provided looks like a DOS device... Like <letter>:\<0> */
|
||||||
|
DriveLetter = RtlUpcaseUnicodeChar(RootPath[0]);
|
||||||
if (!RtlDosPathNameToNtPathName_U(lpRootPath, &PathName, NULL, NULL))
|
/* We'll take the quick path!
|
||||||
|
* We'll find the device type looking at the device map (and types ;-))
|
||||||
|
* associated with the current process
|
||||||
|
*/
|
||||||
|
if (DriveLetter >= L'A' && DriveLetter <= L'Z' && RootPath[1] == L':' &&
|
||||||
|
RootPath[2] == L'\\' && RootPath[3] == UNICODE_NULL)
|
||||||
{
|
{
|
||||||
if (CurrentDir != NULL)
|
USHORT Index;
|
||||||
HeapFree(GetProcessHeap(), 0, CurrentDir);
|
PROCESS_DEVICEMAP_INFORMATION DeviceMap;
|
||||||
|
|
||||||
return DRIVE_NO_ROOT_DIR;
|
/* Query the device map */
|
||||||
}
|
Status = NtQueryInformationProcess(NtCurrentProcess(), ProcessDeviceMap,
|
||||||
|
&DeviceMap,
|
||||||
TRACE("PathName: %S\n", PathName.Buffer);
|
sizeof(PROCESS_DEVICEMAP_INFORMATION),
|
||||||
|
|
||||||
if (CurrentDir != NULL)
|
|
||||||
HeapFree(GetProcessHeap(), 0, CurrentDir);
|
|
||||||
|
|
||||||
if (PathName.Buffer[(PathName.Length >> 1) - 1] != L'\\')
|
|
||||||
{
|
|
||||||
return DRIVE_NO_ROOT_DIR;
|
|
||||||
}
|
|
||||||
|
|
||||||
InitializeObjectAttributes(&ObjectAttributes,
|
|
||||||
&PathName,
|
|
||||||
OBJ_CASE_INSENSITIVE,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
NULL);
|
||||||
|
/* Zero output if we failed */
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
RtlZeroMemory(&DeviceMap, sizeof(PROCESS_DEVICEMAP_INFORMATION));
|
||||||
|
}
|
||||||
|
|
||||||
Status = NtOpenFile(&FileHandle,
|
/* Get our index in the device map */
|
||||||
FILE_READ_ATTRIBUTES | SYNCHRONIZE,
|
Index = DriveLetter - L'A';
|
||||||
&ObjectAttributes,
|
/* Check we're in the device map (bit set) */
|
||||||
&IoStatusBlock,
|
if (((1 << Index) & DeviceMap.Query.DriveMap) != 0)
|
||||||
|
{
|
||||||
|
/* Validate device type and return it */
|
||||||
|
if (DeviceMap.Query.DriveType[Index] >= DRIVE_REMOVABLE &&
|
||||||
|
DeviceMap.Query.DriveType[Index] <= DRIVE_RAMDISK)
|
||||||
|
{
|
||||||
|
return DeviceMap.Query.DriveType[Index];
|
||||||
|
}
|
||||||
|
/* Otherwise, return we don't know the type */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return DRIVE_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We couldn't find ourselves, do it the slow way */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No path provided, use root */
|
||||||
|
if (lpRootPathName == NULL)
|
||||||
|
{
|
||||||
|
RootPath = L"\\";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert to NT path */
|
||||||
|
if (!RtlDosPathNameToNtPathName_U(RootPath, &PathName, NULL, NULL))
|
||||||
|
{
|
||||||
|
return DRIVE_NO_ROOT_DIR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If not a directory, fail, we need a volume */
|
||||||
|
if (PathName.Buffer[(PathName.Length / sizeof(WCHAR)) - 1] != L'\\')
|
||||||
|
{
|
||||||
|
RtlFreeHeap(RtlGetProcessHeap(), 0, PathName.Buffer);
|
||||||
|
return DRIVE_NO_ROOT_DIR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Let's probe for it, by forcing open failure! */
|
||||||
|
RetryOpen = TRUE;
|
||||||
|
InitializeObjectAttributes(&ObjectAttributes, &PathName,
|
||||||
|
OBJ_CASE_INSENSITIVE, NULL, NULL);
|
||||||
|
Status = NtOpenFile(&RootHandle, SYNCHRONIZE | FILE_READ_ATTRIBUTES,
|
||||||
|
&ObjectAttributes, &IoStatusBlock,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
|
||||||
|
/* It properly failed! */
|
||||||
|
if (Status == STATUS_FILE_IS_A_DIRECTORY)
|
||||||
|
{
|
||||||
|
/* It might be a mount point, then, query for target */
|
||||||
|
if (BasepGetVolumeNameFromReparsePoint(lpRootPathName, VolumeName, MAX_PATH, NULL))
|
||||||
|
{
|
||||||
|
/* We'll reopen the target */
|
||||||
|
RtlInitUnicodeString(&VolumeString, VolumeName);
|
||||||
|
VolumeName[1] = L'?';
|
||||||
|
VolumeString.Length -= sizeof(WCHAR);
|
||||||
|
InitializeObjectAttributes(&ObjectAttributes, &VolumeString,
|
||||||
|
OBJ_CASE_INSENSITIVE, NULL, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* heh. It worked? Or failed for whatever other reason?
|
||||||
|
* Check we have a directory if we get farther in path
|
||||||
|
*/
|
||||||
|
PathName.Length += sizeof(WCHAR);
|
||||||
|
if (IsThisARootDirectory(0, &PathName))
|
||||||
|
{
|
||||||
|
/* Yes? Heh, then it's fine, keep our current handle */
|
||||||
|
RetryOpen = FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Then, retry to open without forcing non directory type */
|
||||||
|
PathName.Length -= sizeof(WCHAR);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
NtClose(RootHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now, we retry without forcing file type - should work now */
|
||||||
|
if (RetryOpen)
|
||||||
|
{
|
||||||
|
Status = NtOpenFile(&RootHandle, SYNCHRONIZE | FILE_READ_ATTRIBUTES,
|
||||||
|
&ObjectAttributes, &IoStatusBlock,
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
FILE_SYNCHRONOUS_IO_NONALERT);
|
FILE_SYNCHRONOUS_IO_NONALERT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We don't need path any longer */
|
||||||
RtlFreeHeap(RtlGetProcessHeap(), 0, PathName.Buffer);
|
RtlFreeHeap(RtlGetProcessHeap(), 0, PathName.Buffer);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
return DRIVE_NO_ROOT_DIR; /* According to WINE regression tests */
|
{
|
||||||
|
return DRIVE_NO_ROOT_DIR;
|
||||||
|
}
|
||||||
|
|
||||||
Status = NtQueryVolumeInformationFile(FileHandle,
|
/* Query the device for its type */
|
||||||
|
Status = NtQueryVolumeInformationFile(RootHandle,
|
||||||
&IoStatusBlock,
|
&IoStatusBlock,
|
||||||
&FileFsDevice,
|
&FileFsDevice,
|
||||||
sizeof(FILE_FS_DEVICE_INFORMATION),
|
sizeof(FILE_FS_DEVICE_INFORMATION),
|
||||||
FileFsDeviceInformation);
|
FileFsDeviceInformation);
|
||||||
NtClose(FileHandle);
|
/* No longer required */
|
||||||
|
NtClose(RootHandle);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
return 0;
|
return DRIVE_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Do we have a remote device? Return so! */
|
||||||
|
if ((FileFsDevice.Characteristics & FILE_REMOTE_DEVICE) == FILE_REMOTE_DEVICE)
|
||||||
|
{
|
||||||
|
return DRIVE_REMOTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the device type */
|
||||||
switch (FileFsDevice.DeviceType)
|
switch (FileFsDevice.DeviceType)
|
||||||
{
|
{
|
||||||
|
/* CDROM, easy */
|
||||||
case FILE_DEVICE_CD_ROM:
|
case FILE_DEVICE_CD_ROM:
|
||||||
case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
|
case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
|
||||||
return DRIVE_CDROM;
|
return DRIVE_CDROM;
|
||||||
case FILE_DEVICE_VIRTUAL_DISK:
|
|
||||||
return DRIVE_RAMDISK;
|
/* Disk... */
|
||||||
case FILE_DEVICE_NETWORK_FILE_SYSTEM:
|
|
||||||
return DRIVE_REMOTE;
|
|
||||||
case FILE_DEVICE_DISK:
|
case FILE_DEVICE_DISK:
|
||||||
case FILE_DEVICE_DISK_FILE_SYSTEM:
|
case FILE_DEVICE_DISK_FILE_SYSTEM:
|
||||||
if (FileFsDevice.Characteristics & FILE_REMOTE_DEVICE)
|
/* Removable media? Floppy is one */
|
||||||
return DRIVE_REMOTE;
|
if ((FileFsDevice.Characteristics & FILE_REMOVABLE_MEDIA) == FILE_REMOVABLE_MEDIA ||
|
||||||
if (FileFsDevice.Characteristics & FILE_REMOVABLE_MEDIA)
|
(FileFsDevice.Characteristics & FILE_FLOPPY_DISKETTE) == FILE_FLOPPY_DISKETTE)
|
||||||
|
{
|
||||||
return DRIVE_REMOVABLE;
|
return DRIVE_REMOVABLE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return DRIVE_FIXED;
|
return DRIVE_FIXED;
|
||||||
}
|
}
|
||||||
|
|
||||||
ERR("Returning DRIVE_UNKNOWN for device type %lu\n", FileFsDevice.DeviceType);
|
/* Easy cases */
|
||||||
|
case FILE_DEVICE_NETWORK:
|
||||||
|
case FILE_DEVICE_NETWORK_FILE_SYSTEM:
|
||||||
|
return DRIVE_REMOTE;
|
||||||
|
|
||||||
|
case FILE_DEVICE_VIRTUAL_DISK:
|
||||||
|
return DRIVE_RAMDISK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Nothing matching, just fail */
|
||||||
return DRIVE_UNKNOWN;
|
return DRIVE_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -253,7 +253,7 @@ GetVolumeNameForRoot(IN LPCWSTR lpszRootPath,
|
||||||
/*
|
/*
|
||||||
* @implemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
static BOOL
|
BOOL
|
||||||
BasepGetVolumeNameFromReparsePoint(IN LPCWSTR lpszMountPoint,
|
BasepGetVolumeNameFromReparsePoint(IN LPCWSTR lpszMountPoint,
|
||||||
OUT LPWSTR lpszVolumeName,
|
OUT LPWSTR lpszVolumeName,
|
||||||
IN DWORD cchBufferLength,
|
IN DWORD cchBufferLength,
|
||||||
|
|
|
@ -150,7 +150,7 @@ CleanAndQuit:
|
||||||
/*
|
/*
|
||||||
* @implemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
static BOOL
|
BOOL
|
||||||
IsThisARootDirectory(IN HANDLE VolumeHandle,
|
IsThisARootDirectory(IN HANDLE VolumeHandle,
|
||||||
IN PUNICODE_STRING NtPathName)
|
IN PUNICODE_STRING NtPathName)
|
||||||
{
|
{
|
||||||
|
|
|
@ -448,6 +448,20 @@ BasepGetVolumeNameForVolumeMountPoint(
|
||||||
OUT LPBOOL IsAMountPoint
|
OUT LPBOOL IsAMountPoint
|
||||||
);
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
BasepGetVolumeNameFromReparsePoint(
|
||||||
|
IN LPCWSTR lpszMountPoint,
|
||||||
|
OUT LPWSTR lpszVolumeName,
|
||||||
|
IN DWORD cchBufferLength,
|
||||||
|
OUT LPBOOL IsAMountPoint
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
IsThisARootDirectory(
|
||||||
|
IN HANDLE VolumeHandle,
|
||||||
|
IN PUNICODE_STRING NtPathName
|
||||||
|
);
|
||||||
|
|
||||||
/* FIXME: This is EXPORTED! It should go in an external kernel32.h header */
|
/* FIXME: This is EXPORTED! It should go in an external kernel32.h header */
|
||||||
VOID
|
VOID
|
||||||
WINAPI
|
WINAPI
|
||||||
|
|
Loading…
Reference in a new issue