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=cb17d5dba4a5e1cee30f47...
commit cb17d5dba4a5e1cee30f47776821f52890b9b4e0 Author: Pierre Schweitzer pierre@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