[PATCH 4/4] kernel32: Implement GetVolumeInformationByHandleW().

Zebediah Figura z.figura12 at gmail.com
Mon Apr 6 20:36:15 CDT 2020


Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---

This paves the way for an implementation of GetVolumeInformation() on top of
ntdll.  Unfortunately, I ran into a snag while doing so, which is that one of
the tests attempts to open a file by a device path other than the DOS one
(specifically, \\?\Volume{...}\).  mountmgr allows that, which was enough for
kernel32 to fall back to assuming NTFS.  Unless we implement a similar fallback
(which feels much like papering over the problem), that test would start
failing.

I don't know how to resolve this. One way is to hook up the missing IRPs in
mountmgr, but this seems like more work than its worth.  It'd be nice for ntdll
to be able to recognize volume paths such that they resolve to the same Unix
file object as the equivalent DOS path, but there are many ways to achieve this
goal and I can't even guess at what would be the right one.

 dlls/kernel32/tests/volume.c | 68 ++++++++++++++++++++++++++++++++++++
 dlls/kernel32/volume.c       | 67 +++++++++++++++++++++++++++--------
 2 files changed, 120 insertions(+), 15 deletions(-)

diff --git a/dlls/kernel32/tests/volume.c b/dlls/kernel32/tests/volume.c
index 37d15fd3f8c..126df5b8a0f 100644
--- a/dlls/kernel32/tests/volume.c
+++ b/dlls/kernel32/tests/volume.c
@@ -60,6 +60,7 @@ static BOOL (WINAPI *pGetVolumePathNameA)(LPCSTR, LPSTR, DWORD);
 static BOOL (WINAPI *pGetVolumePathNamesForVolumeNameA)(LPCSTR, LPSTR, DWORD, LPDWORD);
 static BOOL (WINAPI *pGetVolumePathNamesForVolumeNameW)(LPCWSTR, LPWSTR, DWORD, LPDWORD);
 static BOOL (WINAPI *pCreateSymbolicLinkA)(const char *, const char *, DWORD);
+static BOOL (WINAPI *pGetVolumeInformationByHandleW)(HANDLE, WCHAR *, DWORD, DWORD *, DWORD *, DWORD *, WCHAR *, DWORD);
 
 /* ############################### */
 
@@ -1520,6 +1521,71 @@ static void test_mounted_folder(void)
     ok(ret, "got error %u\n", GetLastError());
 }
 
+static void test_GetVolumeInformationByHandle(void)
+{
+    char buffer[50] DECLSPEC_ALIGN(8);
+    FILE_FS_ATTRIBUTE_INFORMATION *attr_info = (void *)buffer;
+    FILE_FS_VOLUME_INFORMATION *volume_info = (void *)buffer;
+    DWORD serial, filename_len, flags;
+    WCHAR label[20], fsname[20];
+    IO_STATUS_BLOCK io;
+    HANDLE file;
+    NTSTATUS status;
+    BOOL ret;
+
+    if (!pGetVolumeInformationByHandleW)
+    {
+        win_skip("GetVolumeInformationByHandleW is not present.\n");
+        return;
+    }
+
+    file = CreateFileA( "C:/windows", 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+            OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL );
+    ok(file != INVALID_HANDLE_VALUE, "failed to open file, error %u\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ret = pGetVolumeInformationByHandleW( INVALID_HANDLE_VALUE, label, ARRAY_SIZE(label), &serial,
+            &filename_len, &flags, fsname, ARRAY_SIZE(fsname) );
+    ok(!ret, "expected failure\n");
+    ok(GetLastError() == ERROR_INVALID_HANDLE, "got error %u\n", GetLastError());
+
+    ret = pGetVolumeInformationByHandleW( file, NULL, 0, NULL, NULL, NULL, NULL, 0 );
+    ok(ret, "got error %u\n", GetLastError());
+
+    ret = pGetVolumeInformationByHandleW( file, label, ARRAY_SIZE(label), &serial,
+            &filename_len, &flags, fsname, ARRAY_SIZE(fsname) );
+    ok(ret, "got error %u\n", GetLastError());
+
+    memset(buffer, 0, sizeof(buffer));
+    status = NtQueryVolumeInformationFile( file, &io, buffer, sizeof(buffer), FileFsAttributeInformation );
+    ok(!status, "got status %#x\n", status);
+    ok(flags == attr_info->FileSystemAttributes, "expected flags %#x, got %#x\n",
+            attr_info->FileSystemAttributes, flags);
+    ok(filename_len == attr_info->MaximumComponentNameLength, "expected filename_len %u, got %u\n",
+            attr_info->MaximumComponentNameLength, filename_len);
+    ok(!wcscmp( fsname, attr_info->FileSystemName ), "expected fsname %s, got %s\n",
+            debugstr_w( attr_info->FileSystemName ), debugstr_w( fsname ));
+    ok(wcslen( fsname ) == attr_info->FileSystemNameLength / sizeof(WCHAR),
+            "expected fsname length %u, got %u\n", attr_info->FileSystemNameLength / sizeof(WCHAR), wcslen( fsname ));
+
+    SetLastError(0xdeadbeef);
+    ret = pGetVolumeInformationByHandleW( file, NULL, 0, NULL, &filename_len, &flags, fsname, 2 );
+    ok(!ret, "expected failure\n");
+    ok(GetLastError() == ERROR_BAD_LENGTH, "got error %u\n", GetLastError());
+
+    memset(buffer, 0, sizeof(buffer));
+    status = NtQueryVolumeInformationFile( file, &io, buffer, sizeof(buffer), FileFsVolumeInformation );
+    ok(!status, "got status %#x\n", status);
+    ok(serial == volume_info->VolumeSerialNumber, "expected serial %08x, got %08x\n",
+            volume_info->VolumeSerialNumber, serial);
+    ok(!wcscmp( label, volume_info->VolumeLabel ), "expected label %s, got %s\n",
+            debugstr_w( volume_info->VolumeLabel ), debugstr_w( label ));
+    ok(wcslen( label ) == volume_info->VolumeLabelLength / sizeof(WCHAR),
+            "expected label length %u, got %u\n", volume_info->VolumeLabelLength / sizeof(WCHAR), wcslen( label ));
+
+    CloseHandle( file );
+}
+
 START_TEST(volume)
 {
     hdll = GetModuleHandleA("kernel32.dll");
@@ -1535,6 +1601,7 @@ START_TEST(volume)
     pGetVolumePathNamesForVolumeNameA = (void *) GetProcAddress(hdll, "GetVolumePathNamesForVolumeNameA");
     pGetVolumePathNamesForVolumeNameW = (void *) GetProcAddress(hdll, "GetVolumePathNamesForVolumeNameW");
     pCreateSymbolicLinkA = (void *) GetProcAddress(hdll, "CreateSymbolicLinkA");
+    pGetVolumeInformationByHandleW = (void *) GetProcAddress(hdll, "GetVolumeInformationByHandleW");
 
     test_query_dos_deviceA();
     test_dos_devices();
@@ -1553,4 +1620,5 @@ START_TEST(volume)
     test_GetVolumePathNamesForVolumeNameW();
     test_cdrom_ioctl();
     test_mounted_folder();
+    test_GetVolumeInformationByHandle();
 }
diff --git a/dlls/kernel32/volume.c b/dlls/kernel32/volume.c
index 4f0f4a0a0fc..7555dd9e95d 100644
--- a/dlls/kernel32/volume.c
+++ b/dlls/kernel32/volume.c
@@ -2117,21 +2117,58 @@ BOOL WINAPI SetVolumeMountPointW(LPCWSTR path, LPCWSTR volume)
 /***********************************************************************
  *           GetVolumeInformationByHandleW (KERNEL32.@)
  */
-BOOL WINAPI GetVolumeInformationByHandleW(HANDLE handle, WCHAR *volnamebuf, DWORD volnamesize, DWORD *volserial, DWORD *maxlength, DWORD *flags, WCHAR *fsnamebuf, DWORD fsnamesize)
+BOOL WINAPI GetVolumeInformationByHandleW( HANDLE handle, WCHAR *label, DWORD label_len,
+                                           DWORD *serial, DWORD *filename_len, DWORD *flags,
+                                           WCHAR *fsname, DWORD fsname_len )
 {
-    FIXME("%p %p %d %p %p %p %p %d\n", handle, volnamebuf, volnamesize, volserial, maxlength, flags, fsnamebuf, fsnamesize);
-
-    if(volnamebuf && volnamesize)
-        *volnamebuf = 0;
-    if(volserial)
-        *volserial = 0;
-    if(maxlength)
-        *maxlength = 0;
-    if(flags)
-        *flags = 0;
-    if(fsnamebuf && fsnamesize)
-        *fsnamebuf = 0;
+    IO_STATUS_BLOCK io;
 
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+    TRACE( "%p\n", handle );
+
+    if (label || serial)
+    {
+        char buffer[sizeof(FILE_FS_VOLUME_INFORMATION) + MAX_PATH * sizeof(WCHAR)];
+        FILE_FS_VOLUME_INFORMATION *info = (FILE_FS_VOLUME_INFORMATION *)buffer;
+
+        if (!set_ntstatus( NtQueryVolumeInformationFile( handle, &io, info, sizeof(buffer),
+                                                         FileFsVolumeInformation ) ))
+            return FALSE;
+
+        if (label)
+        {
+            if (label_len < info->VolumeLabelLength / sizeof(WCHAR) + 1)
+            {
+                SetLastError( ERROR_BAD_LENGTH );
+                return FALSE;
+            }
+            memcpy( label, info->VolumeLabel, info->VolumeLabelLength );
+            label[info->VolumeLabelLength / sizeof(WCHAR)] = 0;
+        }
+        if (serial) *serial = info->VolumeSerialNumber;
+    }
+
+    if (filename_len || flags || fsname)
+    {
+        char buffer[sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + MAX_PATH * sizeof(WCHAR)];
+        FILE_FS_ATTRIBUTE_INFORMATION *info = (FILE_FS_ATTRIBUTE_INFORMATION *)buffer;
+
+        if (!set_ntstatus( NtQueryVolumeInformationFile( handle, &io, info, sizeof(buffer),
+                                                         FileFsAttributeInformation ) ))
+            return FALSE;
+
+        if (fsname)
+        {
+            if (fsname_len < info->FileSystemNameLength / sizeof(WCHAR) + 1)
+            {
+                SetLastError( ERROR_BAD_LENGTH );
+                return FALSE;
+            }
+            memcpy( fsname, info->FileSystemName, info->FileSystemNameLength );
+            fsname[info->FileSystemNameLength / sizeof(WCHAR)] = 0;
+        }
+        if (filename_len) *filename_len = info->MaximumComponentNameLength;
+        if (flags) *flags = info->FileSystemAttributes;
+    }
+
+    return TRUE;
 }
-- 
2.26.0




More information about the wine-devel mailing list