[Wine-patches] [2/5] ntdll: Use mountmgr IOCTL handler for removable disks.

Alexander Morozov =?iso-8859-1?q?amorozov_=CE=C1_etersoft=2Eru?=
Ср Ноя 12 12:45:13 MSK 2008


Ветка eterhack, баг 2790
----------- следующая часть -----------
From 64c92b88bdd037d8b7a7c23cb8b533901cb3ce0f Mon Sep 17 00:00:00 2001
From: Alexander Morozov <amorozov на etersoft.ru>
Date: Wed, 12 Nov 2008 12:34:18 +0300
Subject: [PATCH] ntdll: Use mountmgr IOCTL handler for removable disks.

---
 dlls/ntdll/Makefile.in |    1 +
 dlls/ntdll/directory.c |  210 +++++++++++++++++++++++++++++++++++++++++++++++-
 dlls/ntdll/loader.c    |    3 +
 3 files changed, 213 insertions(+), 1 deletions(-)

diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in
index d0055f3..71b6e0b 100644
--- a/dlls/ntdll/Makefile.in
+++ b/dlls/ntdll/Makefile.in
@@ -7,6 +7,7 @@ MODULE    = ntdll.dll
 IMPORTLIB = ntdll
 EXTRALIBS = @IOKITLIB@
 EXTRADLLFLAGS = -Wl,--image-base,0x7bc00000
+EXTRADEFS = @HALINCL@
 
 C_SRCS = \
 	actctx.c \
diff --git a/dlls/ntdll/directory.c b/dlls/ntdll/directory.c
index dee0ce6..caccebe 100644
--- a/dlls/ntdll/directory.c
+++ b/dlls/ntdll/directory.c
@@ -75,6 +75,75 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(file);
 
+#ifdef SONAME_LIBHAL
+
+#include <dbus/dbus.h>
+#include <hal/libhal.h>
+
+#define DBUS_FUNCS \
+    DO_FUNC(dbus_bus_get); \
+    DO_FUNC(dbus_error_init); \
+    DO_FUNC(dbus_error_free); \
+    DO_FUNC(dbus_error_is_set); \
+    DO_FUNC(dbus_connection_unref)
+
+#define HAL_FUNCS \
+    DO_FUNC(libhal_ctx_free); \
+    DO_FUNC(libhal_ctx_init); \
+    DO_FUNC(libhal_ctx_new); \
+    DO_FUNC(libhal_ctx_set_dbus_connection); \
+    DO_FUNC(libhal_ctx_shutdown); \
+    DO_FUNC(libhal_device_get_property_bool); \
+    DO_FUNC(libhal_device_get_property_string); \
+    DO_FUNC(libhal_free_string); \
+    DO_FUNC(libhal_free_string_array); \
+    DO_FUNC(libhal_get_all_devices)
+
+#define DO_FUNC(f) static typeof(f) * p_##f
+DBUS_FUNCS;
+HAL_FUNCS;
+#undef DO_FUNC
+
+static void *hal_handle = NULL;
+
+int load_hal_functions(void)
+{
+    char error[128];
+
+    if (hal_handle)
+        return 0;
+    if (!(hal_handle = wine_dlopen( SONAME_LIBHAL, RTLD_NOW|RTLD_GLOBAL,
+            error, sizeof(error) )))
+        goto failed;
+#define DO_FUNC(f) if (!(p_##f = wine_dlsym( RTLD_DEFAULT, #f, \
+    error, sizeof(error) ))) goto failed
+    DBUS_FUNCS;
+#undef DO_FUNC
+#define DO_FUNC(f) if (!(p_##f = wine_dlsym( hal_handle, #f, \
+    error, sizeof(error) ))) goto failed
+    HAL_FUNCS;
+#undef DO_FUNC
+    return 0;
+failed:
+    WARN( "failed to load HAL support: %s\n", error );
+    return 1;
+}
+
+void unload_hal_functions(void)
+{
+    if (hal_handle)
+    {
+        wine_dlclose( hal_handle, NULL, 0 );
+        hal_handle = NULL;
+#define DO_FUNC(f) p_##f = NULL
+        DBUS_FUNCS;
+        HAL_FUNCS;
+#undef DO_FUNC
+    }
+}
+
+#endif  /* SONAME_LIBHAL */
+
 /* just in case... */
 #undef VFAT_IOCTL_READDIR_BOTH
 #undef USE_GETDENTS
@@ -1865,6 +1934,137 @@ static inline int get_dos_prefix_len( const UNICODE_STRING *name )
 
 
 /******************************************************************************
+ *           is_removable_disk
+ *
+ * Check if the device is a disk and it is removable.
+ * This function returns 0 for cdrom and floppy.
+ */
+static int is_removable_disk( const ANSI_STRING *unix_name )
+{
+#ifdef SONAME_LIBHAL
+    char *buf, *unix_device;
+    ssize_t len;
+    DBusError error;
+    DBusConnection *dbc;
+    LibHalContext *ctx;
+    int i, num, ret = 0, found = 0;
+    char **list;
+
+    buf = RtlAllocateHeap( GetProcessHeap(), 0, 2 * PATH_MAX + 2 );
+    if (!buf) return 0;
+    unix_device = buf + PATH_MAX + 1;
+
+    lstrcpynA( unix_device, unix_name->Buffer, unix_name->Length + 1 );
+    unix_device[unix_name->Length] = 0;
+    for (;;)
+    {
+        len = readlink( unix_device, buf, PATH_MAX );
+        if (len == -1)
+            break;
+        buf[len] = 0;
+        if (*buf == '/')
+        {
+            lstrcpynA( unix_device, buf, PATH_MAX + 1 );
+            continue;
+        }
+        *(strrchr( unix_device, '/' ) + 1) = 0;
+        strcat( unix_device, buf );
+    }
+
+    if (load_hal_functions())
+        goto end;
+
+    p_dbus_error_init( &error );
+    if (!(dbc = p_dbus_bus_get( DBUS_BUS_SYSTEM, &error )))
+    {
+        WARN( "failed to get system dbus connection: %s\n", error.message );
+        p_dbus_error_free( &error );
+        goto end;
+    }
+
+    if (!(ctx = p_libhal_ctx_new())) {
+        WARN( "HAL context creation failed\n" );
+        goto end;
+    }
+
+    if (!p_libhal_ctx_set_dbus_connection( ctx, dbc ))
+    {
+        WARN( "failed to set dbus connection\n" );
+        goto end;
+    }
+
+    if (!p_libhal_ctx_init( ctx, &error ))
+    {
+        WARN( "HAL context init failed: %s\n", error.message );
+        p_dbus_error_free( &error );
+        goto end;
+    }
+
+    if (!(list = p_libhal_get_all_devices( ctx, &num, &error )))
+        p_dbus_error_free( &error );
+    else
+    {
+        for (i = 0; i < num && !found; i++)
+        {
+            char *device;
+
+            if (!(device = p_libhal_device_get_property_string( ctx, list[i],
+                    "block.device", &error )))
+            {
+                p_dbus_error_free( &error );
+                continue;
+            }
+            if (!strcmp( unix_device, device ))
+            {
+                char *parent;
+
+                if (!(parent = p_libhal_device_get_property_string( ctx, list[i],
+                        "info.parent", &error )))
+                    p_dbus_error_free( &error );
+                else
+                {
+                    if (!p_libhal_device_get_property_bool( ctx, parent,
+                            "storage.removable", &error ))
+                        p_dbus_error_free( &error );
+                    else
+                    {
+                        char *type;
+
+                        if (!(type = p_libhal_device_get_property_string( ctx,
+                                parent, "storage.drive_type", &error )))
+                            p_dbus_error_free( &error );
+                        else
+                        {
+                            if (!strcmp( type, "disk" ))
+                                ret = 1;
+                            p_libhal_free_string( type );
+                        }
+                    }
+                    p_libhal_free_string( parent );
+                }
+                found = 1;
+            }
+            p_libhal_free_string( device );
+        }
+        p_libhal_free_string_array( list );
+    }
+
+    p_libhal_ctx_shutdown( ctx, &error );
+    if (p_dbus_error_is_set( &error ))
+        p_dbus_error_free( &error );
+    p_libhal_ctx_free( ctx );
+    p_dbus_connection_unref( dbc );
+end:
+    RtlFreeHeap( GetProcessHeap(), 0, buf );
+    return ret;
+#else
+    WARN( "HAL support not compiled in\n" );
+    return 0;
+#endif
+}
+
+
+/******************************************************************************
  *           wine_nt_to_unix_file_name  (NTDLL.@) Not a Windows API
  *
  * Convert a file name from NT namespace to Unix namespace.
@@ -1910,7 +2110,15 @@ NTSTATUS wine_nt_to_unix_file_name( const UNICODE_STRING *nameW, ANSI_STRING *un
         return STATUS_OBJECT_NAME_INVALID;
 
     if (pos == name_len)  /* no subdir, plain DOS device */
-        return get_dos_device( name, name_len, unix_name_ret );
+    {
+        status = get_dos_device( name, name_len, unix_name_ret );
+        /* return STATUS_BAD_DEVICE_TYPE for removable disk device
+           in order to mountmgr.sys can handle IOCTLs */
+        if (status != STATUS_BAD_DEVICE_TYPE && is_removable_disk( unix_name_ret ))
+            return STATUS_BAD_DEVICE_TYPE;
+        else
+            return status;
+    }
 
     for (prefix_len = 0; prefix_len < pos; prefix_len++)
         prefix[prefix_len] = tolowerW(name[prefix_len]);
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index 3a88199..f65dd8b 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -2551,6 +2551,9 @@ NTSTATUS WINAPI NtUnloadDriver( const UNICODE_STRING *DriverServiceName )
 BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
 {
     if (reason == DLL_PROCESS_ATTACH) LdrDisableThreadCalloutsForDll( inst );
+#ifdef SONAME_LIBHAL
+    if (reason == DLL_PROCESS_DETACH) unload_hal_functions();
+#endif
     return TRUE;
 }
 
-- 
1.5.6.5.GIT



Подробная информация о списке рассылки Wine-patches