This is an automated email from the git hooks/post-receive script.
www-data pushed a commit to branch master
in repository reactos.
View the commit online:
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=cb17d5dba4a5e1cee30f4…
commit cb17d5dba4a5e1cee30f47776821f52890b9b4e0
Author: Pierre Schweitzer <pierre(a)reactos.org>
AuthorDate: Thu Oct 5 23:41:26 2017 +0200
[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.
---
dll/win32/kernel32/client/file/disk.c | 244 +++++++++++++++++++++---------
dll/win32/kernel32/client/file/mntpoint.c | 2 +-
dll/win32/kernel32/client/file/volume.c | 2 +-
dll/win32/kernel32/include/kernel32.h | 14 ++
4 files changed, 188 insertions(+), 74 deletions(-)
diff --git a/dll/win32/kernel32/client/file/disk.c
b/dll/win32/kernel32/client/file/disk.c
index 74ca5713f0..e7843067fc 100644
--- a/dll/win32/kernel32/client/file/disk.c
+++ b/dll/win32/kernel32/client/file/disk.c
@@ -23,7 +23,6 @@
#define NDEBUG
#include <debug.h>
-DEBUG_CHANNEL(kernel32file);
#define MAX_DOS_DRIVES 26
@@ -482,127 +481,228 @@ UINT
WINAPI
GetDriveTypeW(IN LPCWSTR lpRootPathName)
{
- FILE_FS_DEVICE_INFORMATION FileFsDevice;
- OBJECT_ATTRIBUTES ObjectAttributes;
- IO_STATUS_BLOCK IoStatusBlock;
- UNICODE_STRING PathName;
- HANDLE FileHandle;
+ BOOL RetryOpen;
+ PCWSTR RootPath;
NTSTATUS Status;
- PWSTR CurrentDir = NULL;
- PCWSTR lpRootPath;
+ WCHAR DriveLetter;
+ 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 */
- DWORD BufferSize = GetCurrentDirectoryW(0, NULL);
- CurrentDir = HeapAlloc(GetProcessHeap(), 0, BufferSize * sizeof(WCHAR));
- if (!CurrentDir)
- return DRIVE_UNKNOWN;
- if (!GetCurrentDirectoryW(BufferSize, CurrentDir))
+ RootPath = Buffer;
+ /* This will be current drive (<letter>:\ - drop the rest)*/
+ if (RtlGetCurrentDirectory_U(sizeof(Buffer), Buffer) > 3 * sizeof(WCHAR))
{
- HeapFree(GetProcessHeap(), 0, CurrentDir);
- return DRIVE_UNKNOWN;
+ Buffer[3] = UNICODE_NULL;
}
-
- if (wcslen(CurrentDir) > 3)
- CurrentDir[3] = 0;
-
- lpRootPath = CurrentDir;
}
else
{
- size_t Length = wcslen(lpRootPathName);
-
- TRACE("lpRootPathName: %S\n", lpRootPathName);
-
- lpRootPath = lpRootPathName;
- if (Length == 2)
+ /* Handle broken value */
+ if (lpRootPathName == (PVOID)-1)
{
- 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':')
{
- Length = (Length + 2) * sizeof(WCHAR);
-
- CurrentDir = HeapAlloc(GetProcessHeap(), 0, Length);
- if (!CurrentDir)
- return DRIVE_UNKNOWN;
+ /* Make it a volume */
+ Buffer[0] = DriveLetter;
+ Buffer[1] = L':';
+ Buffer[2] = L'\\';
+ Buffer[3] = UNICODE_NULL;
+ RootPath = Buffer;
+ }
+ }
+ }
- StringCbPrintfW(CurrentDir, Length, L"%s\\", lpRootPathName);
+ /* If the provided looks like a DOS device... Like <letter>:\<0> */
+ DriveLetter = RtlUpcaseUnicodeChar(RootPath[0]);
+ /* 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)
+ {
+ USHORT Index;
+ PROCESS_DEVICEMAP_INFORMATION DeviceMap;
+
+ /* Query the device map */
+ Status = NtQueryInformationProcess(NtCurrentProcess(), ProcessDeviceMap,
+ &DeviceMap,
+ sizeof(PROCESS_DEVICEMAP_INFORMATION),
+ NULL);
+ /* Zero output if we failed */
+ if (!NT_SUCCESS(Status))
+ {
+ RtlZeroMemory(&DeviceMap, sizeof(PROCESS_DEVICEMAP_INFORMATION));
+ }
- lpRootPath = CurrentDir;
+ /* Get our index in the device map */
+ Index = DriveLetter - L'A';
+ /* Check we're in the device map (bit set) */
+ 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;
}
}
- }
- TRACE("lpRootPath: %S\n", lpRootPath);
+ /* We couldn't find ourselves, do it the slow way */
+ }
- if (!RtlDosPathNameToNtPathName_U(lpRootPath, &PathName, NULL, NULL))
+ /* No path provided, use root */
+ if (lpRootPathName == NULL)
{
- if (CurrentDir != NULL)
- HeapFree(GetProcessHeap(), 0, CurrentDir);
+ RootPath = L"\\";
+ }
+ /* Convert to NT path */
+ if (!RtlDosPathNameToNtPathName_U(RootPath, &PathName, NULL, NULL))
+ {
return DRIVE_NO_ROOT_DIR;
}
- TRACE("PathName: %S\n", PathName.Buffer);
-
- if (CurrentDir != NULL)
- HeapFree(GetProcessHeap(), 0, CurrentDir);
-
- if (PathName.Buffer[(PathName.Length >> 1) - 1] != L'\\')
+ /* 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;
}
- InitializeObjectAttributes(&ObjectAttributes,
- &PathName,
- OBJ_CASE_INSENSITIVE,
- NULL,
- NULL);
-
- Status = NtOpenFile(&FileHandle,
- FILE_READ_ATTRIBUTES | SYNCHRONIZE,
- &ObjectAttributes,
- &IoStatusBlock,
+ /* 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_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_SYNCHRONOUS_IO_NONALERT);
+ }
+ /* We don't need path any longer */
RtlFreeHeap(RtlGetProcessHeap(), 0, PathName.Buffer);
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,
&FileFsDevice,
sizeof(FILE_FS_DEVICE_INFORMATION),
FileFsDeviceInformation);
- NtClose(FileHandle);
+ /* No longer required */
+ NtClose(RootHandle);
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)
{
+ /* CDROM, easy */
case FILE_DEVICE_CD_ROM:
case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
return DRIVE_CDROM;
- case FILE_DEVICE_VIRTUAL_DISK:
- return DRIVE_RAMDISK;
- case FILE_DEVICE_NETWORK_FILE_SYSTEM:
- return DRIVE_REMOTE;
+
+ /* Disk... */
case FILE_DEVICE_DISK:
case FILE_DEVICE_DISK_FILE_SYSTEM:
- if (FileFsDevice.Characteristics & FILE_REMOTE_DEVICE)
- return DRIVE_REMOTE;
- if (FileFsDevice.Characteristics & FILE_REMOVABLE_MEDIA)
+ /* Removable media? Floppy is one */
+ if ((FileFsDevice.Characteristics & FILE_REMOVABLE_MEDIA) ==
FILE_REMOVABLE_MEDIA ||
+ (FileFsDevice.Characteristics & FILE_FLOPPY_DISKETTE) ==
FILE_FLOPPY_DISKETTE)
+ {
return DRIVE_REMOVABLE;
- return DRIVE_FIXED;
- }
+ }
+ else
+ {
+ return DRIVE_FIXED;
+ }
+
+ /* Easy cases */
+ case FILE_DEVICE_NETWORK:
+ case FILE_DEVICE_NETWORK_FILE_SYSTEM:
+ return DRIVE_REMOTE;
- ERR("Returning DRIVE_UNKNOWN for device type %lu\n",
FileFsDevice.DeviceType);
+ case FILE_DEVICE_VIRTUAL_DISK:
+ return DRIVE_RAMDISK;
+ }
+ /* Nothing matching, just fail */
return DRIVE_UNKNOWN;
}
diff --git a/dll/win32/kernel32/client/file/mntpoint.c
b/dll/win32/kernel32/client/file/mntpoint.c
index 9cd3dd3a5c..9dfabf7b2b 100644
--- a/dll/win32/kernel32/client/file/mntpoint.c
+++ b/dll/win32/kernel32/client/file/mntpoint.c
@@ -253,7 +253,7 @@ GetVolumeNameForRoot(IN LPCWSTR lpszRootPath,
/*
* @implemented
*/
-static BOOL
+BOOL
BasepGetVolumeNameFromReparsePoint(IN LPCWSTR lpszMountPoint,
OUT LPWSTR lpszVolumeName,
IN DWORD cchBufferLength,
diff --git a/dll/win32/kernel32/client/file/volume.c
b/dll/win32/kernel32/client/file/volume.c
index 4d57a2a633..e59c291b67 100644
--- a/dll/win32/kernel32/client/file/volume.c
+++ b/dll/win32/kernel32/client/file/volume.c
@@ -150,7 +150,7 @@ CleanAndQuit:
/*
* @implemented
*/
-static BOOL
+BOOL
IsThisARootDirectory(IN HANDLE VolumeHandle,
IN PUNICODE_STRING NtPathName)
{
diff --git a/dll/win32/kernel32/include/kernel32.h
b/dll/win32/kernel32/include/kernel32.h
index 2bfcc82e91..d5839bfc8d 100644
--- a/dll/win32/kernel32/include/kernel32.h
+++ b/dll/win32/kernel32/include/kernel32.h
@@ -448,6 +448,20 @@ BasepGetVolumeNameForVolumeMountPoint(
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 */
VOID
WINAPI
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.