[PATCH] kernel32: Add support for detecting volume information with libudev.

Zebediah Figura z.figura12 at gmail.com
Sun Jul 23 23:26:45 CDT 2017


Using GetVolumeInformation may fail due to lack of permissions; e.g.
when the drive was mounted as root. This patch uses libudev, if it
is available, to retrieve the volume label, serial number, and type.

Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/kernel32/Makefile.in |  3 +-
 dlls/kernel32/volume.c    | 88 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 90 insertions(+), 1 deletion(-)

diff --git a/dlls/kernel32/Makefile.in b/dlls/kernel32/Makefile.in
index 1399859..a265625 100644
--- a/dlls/kernel32/Makefile.in
+++ b/dlls/kernel32/Makefile.in
@@ -2,7 +2,8 @@ EXTRADEFS = -D_KERNEL32_ -D_NORMALIZE_
 MODULE    = kernel32.dll
 IMPORTLIB = kernel32
 IMPORTS   = winecrt0 ntdll
-EXTRALIBS = $(COREFOUNDATION_LIBS) $(POLL_LIBS)
+EXTRALIBS = $(COREFOUNDATION_LIBS) $(POLL_LIBS) $(UDEV_LIBS)
+EXTRAINCL = $(UDEV_CFLAGS)
 EXTRADLLFLAGS = -nodefaultlibs -Wb,-F,KERNEL32.dll -Wl,--image-base,0x7b400000
 
 C_SRCS = \
diff --git a/dlls/kernel32/volume.c b/dlls/kernel32/volume.c
index b4163f0..23631fe 100644
--- a/dlls/kernel32/volume.c
+++ b/dlls/kernel32/volume.c
@@ -28,6 +28,9 @@
 #include <stdarg.h>
 #include <stdlib.h>
 #include <stdio.h>
+#ifdef HAVE_UDEV
+#include <libudev.h>
+#endif
 
 #include "ntstatus.h"
 #define WIN32_NO_STATUS
@@ -679,6 +682,87 @@ static DWORD VOLUME_GetAudioCDSerial( const CDROM_TOC *toc )
     return serial;
 }
 
+#ifdef HAVE_UDEV
+static enum fs_type get_udev_information( LPCWSTR root, LPWSTR label, DWORD label_len,
+                                          DWORD *serial )
+{
+    WCHAR devname[] = {' ',':',':',0};
+    char *unix_path;
+    struct stat st;
+    struct udev *udev_context = NULL;
+    struct udev_device *udev_device = NULL;
+    const char *device_label, *device_serial, *device_type;
+    DWORD serial_low, serial_high;
+    enum fs_type type = FS_ERROR;
+
+    devname[0] = root[0];
+    unix_path = get_dos_device_path(devname);
+
+    if (stat(unix_path, &st) != 0)
+    {
+        WARN("couldn't stat %s\n", debugstr_a(unix_path));
+        goto end;
+    }
+
+    if (!S_ISBLK(st.st_mode))
+        goto end;
+
+    if (!(udev_context = udev_new()))
+    {
+        ERR("couldn't create udev context\n");
+        goto end;
+    }
+
+    if (!(udev_device = udev_device_new_from_devnum(udev_context, 'b', st.st_rdev)))
+    {
+        ERR("couldn't create udev device\n");
+        goto end;
+    }
+
+    device_label = udev_device_get_property_value(udev_device, "ID_FS_LABEL_ENC");
+    device_serial = udev_device_get_property_value(udev_device, "ID_FS_UUID_ENC");
+    device_type = udev_device_get_property_value(udev_device, "ID_FS_TYPE");
+
+    if (label)
+    {
+        if (device_label)
+        {
+            if (!MultiByteToWideChar(CP_UNIXCP, 0, device_label, -1, label, label_len))
+                label[label_len-1] = 0;
+        }
+        else
+            label[0] = 0;
+    }
+    if (serial)
+    {
+        if (device_serial && sscanf(device_serial, "%04x-%04x", &serial_high, &serial_low) == 2)
+            *serial = (serial_high << 16) | serial_low;
+        else
+            *serial = 0;
+    }
+    if (!device_type)
+        type = FS_UNKNOWN;
+    else if (!strcmp(device_type, "iso9660"))
+        type = FS_ISO9660;
+    else if (!strcmp(device_type, "vfat"))
+    {
+        const char *fat_version = udev_device_get_property_value(udev_device, "ID_FS_VERSION");
+        if (fat_version && (!strcmp(fat_version, "FAT12") || !strcmp(fat_version, "FAT16")))
+            type = FS_FAT1216;
+        else
+            type = FS_FAT32;
+    }
+    else if (!strcmp(device_type, "udf"))
+        type = FS_UDF;
+    else
+        type = FS_UNKNOWN;
+end:
+    if (udev_device) udev_device_unref(udev_device);
+    if (udev_context) udev_unref(udev_context);
+    HeapFree(GetProcessHeap(), 0, unix_path);
+    return type;
+}
+#endif /* HAVE_UDEV */
 
 /***********************************************************************
  *           GetVolumeInformationW   (KERNEL32.@)
@@ -777,6 +861,10 @@ BOOL WINAPI GetVolumeInformationW( LPCWSTR root, LPWSTR label, DWORD label_len,
         CloseHandle( handle );
         goto fill_fs_info;
     }
+#ifdef HAVE_UDEV
+    else if ((type = get_udev_information(root, label, label_len, serial)) != FS_ERROR)
+        goto fill_fs_info;
+#endif
     else TRACE( "cannot open device %s: %x\n", debugstr_w(nt_name.Buffer), status );
 
     /* we couldn't open the device, fallback to default strategy */
-- 
2.7.4




More information about the wine-patches mailing list