kernel32: Add support for detecting volume information with libudev. New

Revisions: 

Revision 1

user image Zebediah Figura Author
17 Aug. 17

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.

Alexandre said this code belongs in mountmgr.sys, along with the current code in GetVolumeInformation() and NtQueryVolumeInformationFile(). This requires a fair amount of work since Wine isn't currently built to use "kernel-mode" drivers in the way Windows is. I'd like to submit this patch for now until I can do this work.

Single files Merged diff Tar archive
You have unsaved changes. Press CTRL + ENTER in a text field to submit your comments.

0001-kernel32-Add-support-for-detecting-volume-informatio.patch (3 comments)

From 9cdf096c85d22fdb957358a8070538357413c4f2 Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Sun, 23 Jul 2017 23:16:40 -0500
Subject: [PATCH] kernel32: Add support for detecting volume information with
libudev.
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@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");
user image Michael Müller
21 Aug. 17

The _ENC versions of the labels replace 'unsafe' characters by their corresponding hex encoding. Your code does not decode them.

+ device_type = udev_device_get_property_value(udev_device, "ID_FS_TYPE");
+
+ if (label)
user image Michael Müller
21 Aug. 17

You should check if label_len is zero.

+ {
+ 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;
user image Michael Müller
21 Aug. 17

This certainly does not match with the serial returned by VOLUME_GetSuperblockSerial. I could imagine that some DRM software might complain about a wrong CDROM serial. It could also break other DRM host binding checks if you change between a Wine version with and without udev support. The sscanf doesn't seem to fit everywhere. Here are some examples from my system:

ext4: ID_FS_UUID_ENC=1579ed55-5426-24f0-93aa-d7c32db02842 ntfs: ID_FS_UUID_ENC=898725B93725A76A iso9660: ID_FS_UUID_ENC=2001-01-29-12-00-16-00

+ 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