From aaf94cd2de105f4051bbb1064c6891af0acf60f5 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 3 Mar 2008 22:58:32 -0800 Subject: [PATCH] explorer/mountmgr: Move device hotplug code over to mount manager --- dlls/mountmgr.sys/Makefile.in | 7 +- dlls/mountmgr.sys/device.c | 266 +++++++++++++++++++++++++++++++++++++++++ dlls/mountmgr.sys/diskarb.c | 145 ++++++++++++++++++++++ dlls/mountmgr.sys/hal.c | 249 ++++++++++++++++++++++++++++++++++++++ dlls/mountmgr.sys/mountmgr.c | 4 + dlls/mountmgr.sys/mountmgr.h | 26 ++++ programs/explorer/Makefile.in | 5 - programs/explorer/desktop.c | 2 - programs/explorer/device.c | 266 ----------------------------------------- programs/explorer/diskarb.c | 145 ---------------------- programs/explorer/hal.c | 249 -------------------------------------- 11 files changed, 696 insertions(+), 668 deletions(-) create mode 100644 dlls/mountmgr.sys/device.c create mode 100644 dlls/mountmgr.sys/diskarb.c create mode 100644 dlls/mountmgr.sys/hal.c create mode 100644 dlls/mountmgr.sys/mountmgr.h delete mode 100644 programs/explorer/device.c delete mode 100644 programs/explorer/diskarb.c delete mode 100644 programs/explorer/hal.c diff --git a/dlls/mountmgr.sys/Makefile.in b/dlls/mountmgr.sys/Makefile.in index f73e4d4..825467c 100644 --- a/dlls/mountmgr.sys/Makefile.in +++ b/dlls/mountmgr.sys/Makefile.in @@ -3,10 +3,15 @@ TOPOBJDIR = ../.. SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = mountmgr.sys -IMPORTS = advapi32 ntoskrnl.exe kernel32 ntdll +IMPORTS = advapi32 ntoskrnl.exe kernel32 ntdll user32 EXTRADLLFLAGS = -Wb,--subsystem,native +EXTRADEFS = @HALINCL@ +EXTRALIBS = @DISKARBITRATIONLIB@ -luuid C_SRCS = \ + device.c \ + diskarb.c \ + hal.c \ mountmgr.c @MAKE_DLL_RULES@ diff --git a/dlls/mountmgr.sys/device.c b/dlls/mountmgr.sys/device.c new file mode 100644 index 0000000..0435f35 --- /dev/null +++ b/dlls/mountmgr.sys/device.c @@ -0,0 +1,266 @@ +/* + * Dynamic devices support + * + * Copyright 2006 Alexandre Julliard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winuser.h" +#include "dbt.h" + +#include "wine/library.h" +#include "wine/list.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mountmgr); + +struct dos_drive +{ + struct list entry; + char *udi; + int drive; +}; + +static struct list drives_list = LIST_INIT(drives_list); + +static char *get_dosdevices_path(void) +{ + const char *config_dir = wine_get_config_dir(); + size_t len = strlen(config_dir) + sizeof("/dosdevices/a::"); + char *path = HeapAlloc( GetProcessHeap(), 0, len ); + if (path) + { + strcpy( path, config_dir ); + strcat( path, "/dosdevices/a::" ); + } + return path; +} + +/* send notification about a change to a given drive */ +static void send_notify( int drive, int code ) +{ + DWORD_PTR result; + DEV_BROADCAST_VOLUME info; + + info.dbcv_size = sizeof(info); + info.dbcv_devicetype = DBT_DEVTYP_VOLUME; + info.dbcv_reserved = 0; + info.dbcv_unitmask = 1 << drive; + info.dbcv_flags = DBTF_MEDIA; + result = BroadcastSystemMessageW( BSF_FORCEIFHUNG|BSF_QUERY, NULL, + WM_DEVICECHANGE, code, (LPARAM)&info ); +} + +static inline int is_valid_device( struct stat *st ) +{ +#if defined(linux) || defined(__sun__) + return S_ISBLK( st->st_mode ); +#else + /* disks are char devices on *BSD */ + return S_ISCHR( st->st_mode ); +#endif +} + +/* find or create a DOS drive for the corresponding device */ +static int add_drive( const char *device, const char *type ) +{ + char *path, *p; + char in_use[26]; + struct stat dev_st, drive_st; + int drive, first, last, avail = 0; + + if (stat( device, &dev_st ) == -1 || !is_valid_device( &dev_st )) return -1; + + if (!(path = get_dosdevices_path())) return -1; + p = path + strlen(path) - 3; + + memset( in_use, 0, sizeof(in_use) ); + + first = 2; + last = 26; + if (type && !strcmp( type, "floppy" )) + { + first = 0; + last = 2; + } + + while (avail != -1) + { + avail = -1; + for (drive = first; drive < last; drive++) + { + if (in_use[drive]) continue; /* already checked */ + *p = 'a' + drive; + if (stat( path, &drive_st ) == -1) + { + if (lstat( path, &drive_st ) == -1 && errno == ENOENT) /* this is a candidate */ + { + if (avail == -1) + { + p[2] = 0; + /* if mount point symlink doesn't exist either, it's available */ + if (lstat( path, &drive_st ) == -1 && errno == ENOENT) avail = drive; + p[2] = ':'; + } + } + else in_use[drive] = 1; + } + else + { + in_use[drive] = 1; + if (!is_valid_device( &drive_st )) continue; + if (dev_st.st_rdev == drive_st.st_rdev) goto done; + } + } + if (avail != -1) + { + /* try to use the one we found */ + drive = avail; + *p = 'a' + drive; + if (symlink( device, path ) != -1) goto done; + /* failed, retry the search */ + } + } + drive = -1; + +done: + HeapFree( GetProcessHeap(), 0, path ); + return drive; +} + +static BOOL set_mount_point( struct dos_drive *drive, const char *mount_point ) +{ + char *path, *p; + struct stat path_st, mnt_st; + BOOL modified = FALSE; + + if (drive->drive == -1) return FALSE; + if (!(path = get_dosdevices_path())) return FALSE; + p = path + strlen(path) - 3; + *p = 'a' + drive->drive; + p[2] = 0; + + if (mount_point[0]) + { + /* try to avoid unlinking if already set correctly */ + if (stat( path, &path_st ) == -1 || stat( mount_point, &mnt_st ) == -1 || + path_st.st_dev != mnt_st.st_dev || path_st.st_ino != mnt_st.st_ino) + { + unlink( path ); + symlink( mount_point, path ); + modified = TRUE; + } + } + else + { + if (unlink( path ) != -1) modified = TRUE; + } + + HeapFree( GetProcessHeap(), 0, path ); + return modified; +} + +BOOL add_dos_device( const char *udi, const char *device, + const char *mount_point, const char *type ) +{ + struct dos_drive *drive; + + /* first check if it already exists */ + LIST_FOR_EACH_ENTRY( drive, &drives_list, struct dos_drive, entry ) + { + if (!strcmp( udi, drive->udi )) goto found; + } + + if (!(drive = HeapAlloc( GetProcessHeap(), 0, sizeof(*drive) ))) return FALSE; + if (!(drive->udi = HeapAlloc( GetProcessHeap(), 0, strlen(udi)+1 ))) + { + HeapFree( GetProcessHeap(), 0, drive ); + return FALSE; + } + strcpy( drive->udi, udi ); + list_add_tail( &drives_list, &drive->entry ); + +found: + drive->drive = add_drive( device, type ); + if (drive->drive != -1) + { + HKEY hkey; + + set_mount_point( drive, mount_point ); + + TRACE( "added device %c: udi %s for %s on %s type %s\n", + 'a' + drive->drive, wine_dbgstr_a(udi), wine_dbgstr_a(device), + wine_dbgstr_a(mount_point), wine_dbgstr_a(type) ); + + /* hack: force the drive type in the registry */ + if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Drives", &hkey )) + { + char name[3] = "a:"; + name[0] += drive->drive; + if (!type || strcmp( type, "cdrom" )) type = "floppy"; /* FIXME: default to floppy */ + RegSetValueExA( hkey, name, 0, REG_SZ, (const BYTE *)type, strlen(type) + 1 ); + RegCloseKey( hkey ); + } + + send_notify( drive->drive, DBT_DEVICEARRIVAL ); + } + return TRUE; +} + +BOOL remove_dos_device( const char *udi ) +{ + HKEY hkey; + struct dos_drive *drive; + + LIST_FOR_EACH_ENTRY( drive, &drives_list, struct dos_drive, entry ) + { + if (strcmp( udi, drive->udi )) continue; + + if (drive->drive != -1) + { + BOOL modified = set_mount_point( drive, "" ); + + /* clear the registry key too */ + if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Drives", &hkey )) + { + char name[3] = "a:"; + name[0] += drive->drive; + RegDeleteValueA( hkey, name ); + RegCloseKey( hkey ); + } + + if (modified) send_notify( drive->drive, DBT_DEVICEREMOVECOMPLETE ); + } + + list_remove( &drive->entry ); + HeapFree( GetProcessHeap(), 0, drive->udi ); + HeapFree( GetProcessHeap(), 0, drive ); + return TRUE; + } + return FALSE; +} diff --git a/dlls/mountmgr.sys/diskarb.c b/dlls/mountmgr.sys/diskarb.c new file mode 100644 index 0000000..d5f3d61 --- /dev/null +++ b/dlls/mountmgr.sys/diskarb.c @@ -0,0 +1,145 @@ +/* + * Devices support using the MacOS Disk Arbitration library. + * + * Copyright 2006 Alexandre Julliard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winuser.h" + +#include "wine/debug.h" +#include "mountmgr.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mountmgr); + +#ifdef HAVE_DISKARBITRATION_DISKARBITRATION_H + +#include + +static void appeared_callback( DADiskRef disk, void *context ) +{ + CFDictionaryRef dict = DADiskCopyDescription( disk ); + const void *ref; + char device[64]; + char mount_point[PATH_MAX]; + const char *type = NULL; + + if (!dict) return; + + /* ignore non-removable devices */ + if (!(ref = CFDictionaryGetValue( dict, CFSTR("DAMediaRemovable") )) || + !CFBooleanGetValue( ref )) goto done; + + /* get device name */ + if (!(ref = CFDictionaryGetValue( dict, CFSTR("DAMediaBSDName") ))) goto done; + strcpy( device, "/dev/r" ); + CFStringGetCString( ref, device + 6, sizeof(device) - 6, kCFStringEncodingASCII ); + + if ((ref = CFDictionaryGetValue( dict, CFSTR("DAVolumePath") ))) + CFURLGetFileSystemRepresentation( ref, true, (UInt8 *)mount_point, sizeof(mount_point) ); + else + mount_point[0] = 0; + + if ((ref = CFDictionaryGetValue( dict, CFSTR("DAVolumeKind") ))) + { + if (!CFStringCompare( ref, CFSTR("cd9660"), 0 ) || + !CFStringCompare( ref, CFSTR("udf"), 0 )) + type = "cdrom"; + } + + TRACE( "got mount notification for '%s' on '%s'\n", device, mount_point ); + + add_dos_device( device, device, mount_point, type ); +done: + CFRelease( dict ); +} + +static void changed_callback( DADiskRef disk, CFArrayRef keys, void *context ) +{ + appeared_callback( disk, context ); +} + +static void disappeared_callback( DADiskRef disk, void *context ) +{ + CFDictionaryRef dict = DADiskCopyDescription( disk ); + const void *ref; + char device[100]; + + if (!dict) return; + + /* ignore non-removable devices */ + if (!(ref = CFDictionaryGetValue( dict, CFSTR("DAMediaRemovable") )) || + !CFBooleanGetValue( ref )) goto done; + + /* get device name */ + if (!(ref = CFDictionaryGetValue( dict, CFSTR("DAMediaBSDName") ))) goto done; + strcpy( device, "/dev/r" ); + CFStringGetCString( ref, device + 6, sizeof(device) - 6, kCFStringEncodingASCII ); + + TRACE( "got unmount notification for '%s'\n", device ); + + remove_dos_device( device ); +done: + CFRelease( dict ); +} + +static DWORD WINAPI runloop_thread( void *arg ) +{ + DASessionRef session = DASessionCreate( NULL ); + + if (!session) return 1; + + DASessionScheduleWithRunLoop( session, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode ); + DARegisterDiskAppearedCallback( session, kDADiskDescriptionMatchVolumeMountable, + appeared_callback, NULL ); + DARegisterDiskDisappearedCallback( session, kDADiskDescriptionMatchVolumeMountable, + disappeared_callback, NULL ); + DARegisterDiskDescriptionChangedCallback( session, kDADiskDescriptionMatchVolumeMountable, + kDADiskDescriptionWatchVolumePath, changed_callback, NULL ); + CFRunLoopRun(); + DASessionUnscheduleFromRunLoop( session, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode ); + CFRelease( session ); + return 0; +} + +void initialize_diskarbitration(void) +{ + HANDLE handle; + + if (!(handle = CreateThread( NULL, 0, runloop_thread, NULL, 0, NULL ))) return; + CloseHandle( handle ); +} + +#else /* HAVE_DISKARBITRATION_DISKARBITRATION_H */ + +void initialize_diskarbitration(void) +{ + TRACE( "Skipping, Disk Arbitration support not compiled in\n" ); +} + +#endif /* HAVE_DISKARBITRATION_DISKARBITRATION_H */ diff --git a/dlls/mountmgr.sys/hal.c b/dlls/mountmgr.sys/hal.c new file mode 100644 index 0000000..615edf0 --- /dev/null +++ b/dlls/mountmgr.sys/hal.c @@ -0,0 +1,249 @@ +/* + * HAL devices support + * + * Copyright 2006 Alexandre Julliard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winuser.h" +#include "excpt.h" + +#include "wine/library.h" +#include "wine/exception.h" +#include "wine/debug.h" +#include "mountmgr.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mountmgr); + +#ifdef SONAME_LIBHAL + +#include +#include + +#define DBUS_FUNCS \ + DO_FUNC(dbus_bus_get); \ + DO_FUNC(dbus_connection_close); \ + DO_FUNC(dbus_connection_read_write_dispatch); \ + DO_FUNC(dbus_error_init); \ + DO_FUNC(dbus_error_free); \ + DO_FUNC(dbus_error_is_set) + +#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_set_device_added); \ + DO_FUNC(libhal_ctx_set_device_property_modified); \ + DO_FUNC(libhal_ctx_set_device_removed); \ + DO_FUNC(libhal_ctx_shutdown); \ + DO_FUNC(libhal_device_get_property_bool); \ + DO_FUNC(libhal_device_get_property_string); \ + DO_FUNC(libhal_device_add_property_watch); \ + DO_FUNC(libhal_device_remove_property_watch); \ + 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 BOOL load_functions(void) +{ + void *hal_handle; + char error[128]; + + /* Load libhal with RTLD_GLOBAL so that the dbus symbols are available. + * We can't load libdbus directly since libhal may have been built against a + * different version but with the same soname. Binary compatibility is for wimps. */ + + 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 TRUE; + +failed: + WARN( "failed to load HAL support: %s\n", error ); + return FALSE; +} + +static LONG WINAPI assert_fault(EXCEPTION_POINTERS *eptr) +{ + if (eptr->ExceptionRecord->ExceptionCode == EXCEPTION_WINE_ASSERTION) + return EXCEPTION_EXECUTE_HANDLER; + return EXCEPTION_CONTINUE_SEARCH; +} + +/* HAL callback for new device */ +static void new_device( LibHalContext *ctx, const char *udi ) +{ + DBusError error; + char *parent = NULL; + char *mount_point = NULL; + char *device = NULL; + char *type = NULL; + + p_dbus_error_init( &error ); + + if (!(device = p_libhal_device_get_property_string( ctx, udi, "block.device", &error ))) + goto done; + + if (!(mount_point = p_libhal_device_get_property_string( ctx, udi, "volume.mount_point", &error ))) + goto done; + + if (!(parent = p_libhal_device_get_property_string( ctx, udi, "info.parent", &error ))) + goto done; + + if (!p_libhal_device_get_property_bool( ctx, parent, "storage.removable", &error )) + goto done; + + if (!(type = p_libhal_device_get_property_string( ctx, parent, "storage.drive_type", &error ))) + p_dbus_error_free( &error ); /* ignore error */ + + add_dos_device( udi, device, mount_point, type ); + + /* add property watch for mount point */ + p_libhal_device_add_property_watch( ctx, udi, &error ); + +done: + if (type) p_libhal_free_string( type ); + if (parent) p_libhal_free_string( parent ); + if (device) p_libhal_free_string( device ); + if (mount_point) p_libhal_free_string( mount_point ); + p_dbus_error_free( &error ); +} + +/* HAL callback for removed device */ +static void removed_device( LibHalContext *ctx, const char *udi ) +{ + DBusError error; + + TRACE( "removed %s\n", wine_dbgstr_a(udi) ); + + if (remove_dos_device( udi )) + { + p_dbus_error_init( &error ); + p_libhal_device_remove_property_watch( ctx, udi, &error ); + p_dbus_error_free( &error ); + } +} + +/* HAL callback for property changes */ +static void property_modified (LibHalContext *ctx, const char *udi, + const char *key, dbus_bool_t is_removed, dbus_bool_t is_added) +{ + TRACE( "udi %s key %s %s\n", wine_dbgstr_a(udi), wine_dbgstr_a(key), + is_added ? "added" : is_removed ? "removed" : "modified" ); + + if (!strcmp( key, "volume.mount_point" )) new_device( ctx, udi ); +} + + +static DWORD WINAPI hal_thread( void *arg ) +{ + DBusError error; + DBusConnection *dbc; + LibHalContext *ctx; + int i, num; + char **list; + + if (!(ctx = p_libhal_ctx_new())) return 1; + + 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 ); + return 1; + } + + p_libhal_ctx_set_dbus_connection( ctx, dbc ); + p_libhal_ctx_set_device_added( ctx, new_device ); + p_libhal_ctx_set_device_removed( ctx, removed_device ); + p_libhal_ctx_set_device_property_modified( ctx, property_modified ); + + if (!p_libhal_ctx_init( ctx, &error )) + { + WARN( "HAL context init failed: %s\n", error.message ); + p_dbus_error_free( &error ); + return 1; + } + + /* retrieve all existing devices */ + if (!(list = p_libhal_get_all_devices( ctx, &num, &error ))) p_dbus_error_free( &error ); + else + { + for (i = 0; i < num; i++) new_device( ctx, list[i] ); + p_libhal_free_string_array( list ); + } + + __TRY + { + while (p_dbus_connection_read_write_dispatch( dbc, -1 )) /* nothing */ ; + } + __EXCEPT( assert_fault ) + { + WARN( "dbus assertion failure, disabling HAL support\n" ); + return 1; + } + __ENDTRY; + + p_libhal_ctx_shutdown( ctx, &error ); + p_dbus_error_free( &error ); /* just in case */ + p_dbus_connection_close( dbc ); + p_libhal_ctx_free( ctx ); + return 0; +} + +void initialize_hal(void) +{ + HANDLE handle; + + if (!load_functions()) return; + if (!(handle = CreateThread( NULL, 0, hal_thread, NULL, 0, NULL ))) return; + CloseHandle( handle ); +} + +#else /* SONAME_LIBHAL */ + +void initialize_hal(void) +{ + TRACE( "Skipping, HAL support not compiled in\n" ); +} + +#endif /* SONAME_LIBHAL */ diff --git a/dlls/mountmgr.sys/mountmgr.c b/dlls/mountmgr.sys/mountmgr.c index ee819a5..73e2554 100644 --- a/dlls/mountmgr.sys/mountmgr.c +++ b/dlls/mountmgr.sys/mountmgr.c @@ -38,6 +38,7 @@ #include "wine/library.h" #include "wine/unicode.h" #include "wine/debug.h" +#include "mountmgr.h" WINE_DEFAULT_DEBUG_CHANNEL(mountmgr); @@ -493,6 +494,9 @@ NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path ) return status; } + initialize_hal(); + initialize_diskarbitration(); + RtlInitUnicodeString( &nameW, harddiskW ); status = IoCreateDriver( &nameW, harddisk_driver_entry ); diff --git a/dlls/mountmgr.sys/mountmgr.h b/dlls/mountmgr.sys/mountmgr.h new file mode 100644 index 0000000..394904e --- /dev/null +++ b/dlls/mountmgr.sys/mountmgr.h @@ -0,0 +1,26 @@ +/* + * Mountmanager private header + * + * Copyright 2008 Maarten Lankhorst + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +void initialize_hal(void); +void initialize_diskarbitration(void); +BOOL add_dos_device( const char *udi, const char *device, + const char *mount_point, const char *type ); +BOOL remove_dos_device( const char *udi ); + diff --git a/programs/explorer/Makefile.in b/programs/explorer/Makefile.in index 9498a0f..4854eda 100644 --- a/programs/explorer/Makefile.in +++ b/programs/explorer/Makefile.in @@ -6,15 +6,10 @@ MODULE = explorer.exe APPMODE = -mwindows IMPORTS = rpcrt4 user32 gdi32 advapi32 kernel32 ntdll DELAYIMPORTS = comctl32 -EXTRADEFS = @HALINCL@ -EXTRALIBS = @DISKARBITRATIONLIB@ C_SRCS = \ desktop.c \ - device.c \ - diskarb.c \ explorer.c \ - hal.c \ systray.c @MAKE_PROG_RULES@ diff --git a/programs/explorer/desktop.c b/programs/explorer/desktop.c index ddca914..40b2f8e 100644 --- a/programs/explorer/desktop.c +++ b/programs/explorer/desktop.c @@ -234,8 +234,6 @@ void manage_desktop( char *arg ) SystemParametersInfoA( SPI_SETDESKPATTERN, -1, NULL, FALSE ); SetDeskWallPaper( (LPSTR)-1 ); initialize_display_settings( hwnd ); - initialize_diskarbitration(); - initialize_hal(); initialize_systray(); } else diff --git a/programs/explorer/device.c b/programs/explorer/device.c deleted file mode 100644 index 922f4d0..0000000 --- a/programs/explorer/device.c +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Dynamic devices support - * - * Copyright 2006 Alexandre Julliard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "config.h" -#include "wine/port.h" - -#include -#include -#include -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "winreg.h" -#include "winuser.h" -#include "dbt.h" - -#include "wine/library.h" -#include "wine/list.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(explorer); - -struct dos_drive -{ - struct list entry; - char *udi; - int drive; -}; - -static struct list drives_list = LIST_INIT(drives_list); - -static char *get_dosdevices_path(void) -{ - const char *config_dir = wine_get_config_dir(); - size_t len = strlen(config_dir) + sizeof("/dosdevices/a::"); - char *path = HeapAlloc( GetProcessHeap(), 0, len ); - if (path) - { - strcpy( path, config_dir ); - strcat( path, "/dosdevices/a::" ); - } - return path; -} - -/* send notification about a change to a given drive */ -static void send_notify( int drive, int code ) -{ - DWORD_PTR result; - DEV_BROADCAST_VOLUME info; - - info.dbcv_size = sizeof(info); - info.dbcv_devicetype = DBT_DEVTYP_VOLUME; - info.dbcv_reserved = 0; - info.dbcv_unitmask = 1 << drive; - info.dbcv_flags = DBTF_MEDIA; - SendMessageTimeoutW( HWND_BROADCAST, WM_DEVICECHANGE, code, (LPARAM)&info, - SMTO_ABORTIFHUNG, 0, &result ); -} - -static inline int is_valid_device( struct stat *st ) -{ -#if defined(linux) || defined(__sun__) - return S_ISBLK( st->st_mode ); -#else - /* disks are char devices on *BSD */ - return S_ISCHR( st->st_mode ); -#endif -} - -/* find or create a DOS drive for the corresponding device */ -static int add_drive( const char *device, const char *type ) -{ - char *path, *p; - char in_use[26]; - struct stat dev_st, drive_st; - int drive, first, last, avail = 0; - - if (stat( device, &dev_st ) == -1 || !is_valid_device( &dev_st )) return -1; - - if (!(path = get_dosdevices_path())) return -1; - p = path + strlen(path) - 3; - - memset( in_use, 0, sizeof(in_use) ); - - first = 2; - last = 26; - if (type && !strcmp( type, "floppy" )) - { - first = 0; - last = 2; - } - - while (avail != -1) - { - avail = -1; - for (drive = first; drive < last; drive++) - { - if (in_use[drive]) continue; /* already checked */ - *p = 'a' + drive; - if (stat( path, &drive_st ) == -1) - { - if (lstat( path, &drive_st ) == -1 && errno == ENOENT) /* this is a candidate */ - { - if (avail == -1) - { - p[2] = 0; - /* if mount point symlink doesn't exist either, it's available */ - if (lstat( path, &drive_st ) == -1 && errno == ENOENT) avail = drive; - p[2] = ':'; - } - } - else in_use[drive] = 1; - } - else - { - in_use[drive] = 1; - if (!is_valid_device( &drive_st )) continue; - if (dev_st.st_rdev == drive_st.st_rdev) goto done; - } - } - if (avail != -1) - { - /* try to use the one we found */ - drive = avail; - *p = 'a' + drive; - if (symlink( device, path ) != -1) goto done; - /* failed, retry the search */ - } - } - drive = -1; - -done: - HeapFree( GetProcessHeap(), 0, path ); - return drive; -} - -static BOOL set_mount_point( struct dos_drive *drive, const char *mount_point ) -{ - char *path, *p; - struct stat path_st, mnt_st; - BOOL modified = FALSE; - - if (drive->drive == -1) return FALSE; - if (!(path = get_dosdevices_path())) return FALSE; - p = path + strlen(path) - 3; - *p = 'a' + drive->drive; - p[2] = 0; - - if (mount_point[0]) - { - /* try to avoid unlinking if already set correctly */ - if (stat( path, &path_st ) == -1 || stat( mount_point, &mnt_st ) == -1 || - path_st.st_dev != mnt_st.st_dev || path_st.st_ino != mnt_st.st_ino) - { - unlink( path ); - symlink( mount_point, path ); - modified = TRUE; - } - } - else - { - if (unlink( path ) != -1) modified = TRUE; - } - - HeapFree( GetProcessHeap(), 0, path ); - return modified; -} - -BOOL add_dos_device( const char *udi, const char *device, - const char *mount_point, const char *type ) -{ - struct dos_drive *drive; - - /* first check if it already exists */ - LIST_FOR_EACH_ENTRY( drive, &drives_list, struct dos_drive, entry ) - { - if (!strcmp( udi, drive->udi )) goto found; - } - - if (!(drive = HeapAlloc( GetProcessHeap(), 0, sizeof(*drive) ))) return FALSE; - if (!(drive->udi = HeapAlloc( GetProcessHeap(), 0, strlen(udi)+1 ))) - { - HeapFree( GetProcessHeap(), 0, drive ); - return FALSE; - } - strcpy( drive->udi, udi ); - list_add_tail( &drives_list, &drive->entry ); - -found: - drive->drive = add_drive( device, type ); - if (drive->drive != -1) - { - HKEY hkey; - - set_mount_point( drive, mount_point ); - - WINE_TRACE( "added device %c: udi %s for %s on %s type %s\n", - 'a' + drive->drive, wine_dbgstr_a(udi), wine_dbgstr_a(device), - wine_dbgstr_a(mount_point), wine_dbgstr_a(type) ); - - /* hack: force the drive type in the registry */ - if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Drives", &hkey )) - { - char name[3] = "a:"; - name[0] += drive->drive; - if (!type || strcmp( type, "cdrom" )) type = "floppy"; /* FIXME: default to floppy */ - RegSetValueExA( hkey, name, 0, REG_SZ, (const BYTE *)type, strlen(type) + 1 ); - RegCloseKey( hkey ); - } - - send_notify( drive->drive, DBT_DEVICEARRIVAL ); - } - return TRUE; -} - -BOOL remove_dos_device( const char *udi ) -{ - HKEY hkey; - struct dos_drive *drive; - - LIST_FOR_EACH_ENTRY( drive, &drives_list, struct dos_drive, entry ) - { - if (strcmp( udi, drive->udi )) continue; - - if (drive->drive != -1) - { - BOOL modified = set_mount_point( drive, "" ); - - /* clear the registry key too */ - if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Drives", &hkey )) - { - char name[3] = "a:"; - name[0] += drive->drive; - RegDeleteValueA( hkey, name ); - RegCloseKey( hkey ); - } - - if (modified) send_notify( drive->drive, DBT_DEVICEREMOVECOMPLETE ); - } - - list_remove( &drive->entry ); - HeapFree( GetProcessHeap(), 0, drive->udi ); - HeapFree( GetProcessHeap(), 0, drive ); - return TRUE; - } - return FALSE; -} diff --git a/programs/explorer/diskarb.c b/programs/explorer/diskarb.c deleted file mode 100644 index 08a8097..0000000 --- a/programs/explorer/diskarb.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Devices support using the MacOS Disk Arbitration library. - * - * Copyright 2006 Alexandre Julliard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "config.h" -#include "wine/port.h" - -#include -#include -#include -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "winreg.h" -#include "winuser.h" - -#include "wine/debug.h" -#include "explorer_private.h" - -WINE_DEFAULT_DEBUG_CHANNEL(explorer); - -#ifdef HAVE_DISKARBITRATION_DISKARBITRATION_H - -#include - -static void appeared_callback( DADiskRef disk, void *context ) -{ - CFDictionaryRef dict = DADiskCopyDescription( disk ); - const void *ref; - char device[64]; - char mount_point[PATH_MAX]; - const char *type = NULL; - - if (!dict) return; - - /* ignore non-removable devices */ - if (!(ref = CFDictionaryGetValue( dict, CFSTR("DAMediaRemovable") )) || - !CFBooleanGetValue( ref )) goto done; - - /* get device name */ - if (!(ref = CFDictionaryGetValue( dict, CFSTR("DAMediaBSDName") ))) goto done; - strcpy( device, "/dev/r" ); - CFStringGetCString( ref, device + 6, sizeof(device) - 6, kCFStringEncodingASCII ); - - if ((ref = CFDictionaryGetValue( dict, CFSTR("DAVolumePath") ))) - CFURLGetFileSystemRepresentation( ref, true, (UInt8 *)mount_point, sizeof(mount_point) ); - else - mount_point[0] = 0; - - if ((ref = CFDictionaryGetValue( dict, CFSTR("DAVolumeKind") ))) - { - if (!CFStringCompare( ref, CFSTR("cd9660"), 0 ) || - !CFStringCompare( ref, CFSTR("udf"), 0 )) - type = "cdrom"; - } - - WINE_TRACE( "got mount notification for '%s' on '%s'\n", device, mount_point ); - - add_dos_device( device, device, mount_point, type ); -done: - CFRelease( dict ); -} - -static void changed_callback( DADiskRef disk, CFArrayRef keys, void *context ) -{ - appeared_callback( disk, context ); -} - -static void disappeared_callback( DADiskRef disk, void *context ) -{ - CFDictionaryRef dict = DADiskCopyDescription( disk ); - const void *ref; - char device[100]; - - if (!dict) return; - - /* ignore non-removable devices */ - if (!(ref = CFDictionaryGetValue( dict, CFSTR("DAMediaRemovable") )) || - !CFBooleanGetValue( ref )) goto done; - - /* get device name */ - if (!(ref = CFDictionaryGetValue( dict, CFSTR("DAMediaBSDName") ))) goto done; - strcpy( device, "/dev/r" ); - CFStringGetCString( ref, device + 6, sizeof(device) - 6, kCFStringEncodingASCII ); - - WINE_TRACE( "got unmount notification for '%s'\n", device ); - - remove_dos_device( device ); -done: - CFRelease( dict ); -} - -static DWORD WINAPI runloop_thread( void *arg ) -{ - DASessionRef session = DASessionCreate( NULL ); - - if (!session) return 1; - - DASessionScheduleWithRunLoop( session, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode ); - DARegisterDiskAppearedCallback( session, kDADiskDescriptionMatchVolumeMountable, - appeared_callback, NULL ); - DARegisterDiskDisappearedCallback( session, kDADiskDescriptionMatchVolumeMountable, - disappeared_callback, NULL ); - DARegisterDiskDescriptionChangedCallback( session, kDADiskDescriptionMatchVolumeMountable, - kDADiskDescriptionWatchVolumePath, changed_callback, NULL ); - CFRunLoopRun(); - DASessionUnscheduleFromRunLoop( session, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode ); - CFRelease( session ); - return 0; -} - -void initialize_diskarbitration(void) -{ - HANDLE handle; - - if (!(handle = CreateThread( NULL, 0, runloop_thread, NULL, 0, NULL ))) return; - CloseHandle( handle ); -} - -#else /* HAVE_DISKARBITRATION_DISKARBITRATION_H */ - -void initialize_diskarbitration(void) -{ - WINE_TRACE( "Skipping, Disk Arbitration support not compiled in\n" ); -} - -#endif /* HAVE_DISKARBITRATION_DISKARBITRATION_H */ diff --git a/programs/explorer/hal.c b/programs/explorer/hal.c deleted file mode 100644 index df31c6b..0000000 --- a/programs/explorer/hal.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * HAL devices support - * - * Copyright 2006 Alexandre Julliard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "config.h" -#include "wine/port.h" - -#include -#include -#include -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "winreg.h" -#include "winuser.h" -#include "excpt.h" - -#include "wine/library.h" -#include "wine/exception.h" -#include "wine/debug.h" -#include "explorer_private.h" - -WINE_DEFAULT_DEBUG_CHANNEL(explorer); - -#ifdef SONAME_LIBHAL - -#include -#include - -#define DBUS_FUNCS \ - DO_FUNC(dbus_bus_get); \ - DO_FUNC(dbus_connection_close); \ - DO_FUNC(dbus_connection_read_write_dispatch); \ - DO_FUNC(dbus_error_init); \ - DO_FUNC(dbus_error_free); \ - DO_FUNC(dbus_error_is_set) - -#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_set_device_added); \ - DO_FUNC(libhal_ctx_set_device_property_modified); \ - DO_FUNC(libhal_ctx_set_device_removed); \ - DO_FUNC(libhal_ctx_shutdown); \ - DO_FUNC(libhal_device_get_property_bool); \ - DO_FUNC(libhal_device_get_property_string); \ - DO_FUNC(libhal_device_add_property_watch); \ - DO_FUNC(libhal_device_remove_property_watch); \ - 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 BOOL load_functions(void) -{ - void *hal_handle; - char error[128]; - - /* Load libhal with RTLD_GLOBAL so that the dbus symbols are available. - * We can't load libdbus directly since libhal may have been built against a - * different version but with the same soname. Binary compatibility is for wimps. */ - - 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 TRUE; - -failed: - WINE_WARN( "failed to load HAL support: %s\n", error ); - return FALSE; -} - -static LONG WINAPI assert_fault(EXCEPTION_POINTERS *eptr) -{ - if (eptr->ExceptionRecord->ExceptionCode == EXCEPTION_WINE_ASSERTION) - return EXCEPTION_EXECUTE_HANDLER; - return EXCEPTION_CONTINUE_SEARCH; -} - -/* HAL callback for new device */ -static void new_device( LibHalContext *ctx, const char *udi ) -{ - DBusError error; - char *parent = NULL; - char *mount_point = NULL; - char *device = NULL; - char *type = NULL; - - p_dbus_error_init( &error ); - - if (!(device = p_libhal_device_get_property_string( ctx, udi, "block.device", &error ))) - goto done; - - if (!(mount_point = p_libhal_device_get_property_string( ctx, udi, "volume.mount_point", &error ))) - goto done; - - if (!(parent = p_libhal_device_get_property_string( ctx, udi, "info.parent", &error ))) - goto done; - - if (!p_libhal_device_get_property_bool( ctx, parent, "storage.removable", &error )) - goto done; - - if (!(type = p_libhal_device_get_property_string( ctx, parent, "storage.drive_type", &error ))) - p_dbus_error_free( &error ); /* ignore error */ - - add_dos_device( udi, device, mount_point, type ); - - /* add property watch for mount point */ - p_libhal_device_add_property_watch( ctx, udi, &error ); - -done: - if (type) p_libhal_free_string( type ); - if (parent) p_libhal_free_string( parent ); - if (device) p_libhal_free_string( device ); - if (mount_point) p_libhal_free_string( mount_point ); - p_dbus_error_free( &error ); -} - -/* HAL callback for removed device */ -static void removed_device( LibHalContext *ctx, const char *udi ) -{ - DBusError error; - - WINE_TRACE( "removed %s\n", wine_dbgstr_a(udi) ); - - if (remove_dos_device( udi )) - { - p_dbus_error_init( &error ); - p_libhal_device_remove_property_watch( ctx, udi, &error ); - p_dbus_error_free( &error ); - } -} - -/* HAL callback for property changes */ -static void property_modified (LibHalContext *ctx, const char *udi, - const char *key, dbus_bool_t is_removed, dbus_bool_t is_added) -{ - WINE_TRACE( "udi %s key %s %s\n", wine_dbgstr_a(udi), wine_dbgstr_a(key), - is_added ? "added" : is_removed ? "removed" : "modified" ); - - if (!strcmp( key, "volume.mount_point" )) new_device( ctx, udi ); -} - - -static DWORD WINAPI hal_thread( void *arg ) -{ - DBusError error; - DBusConnection *dbc; - LibHalContext *ctx; - int i, num; - char **list; - - if (!(ctx = p_libhal_ctx_new())) return 1; - - p_dbus_error_init( &error ); - if (!(dbc = p_dbus_bus_get( DBUS_BUS_SYSTEM, &error ))) - { - WINE_WARN( "failed to get system dbus connection: %s\n", error.message ); - p_dbus_error_free( &error ); - return 1; - } - - p_libhal_ctx_set_dbus_connection( ctx, dbc ); - p_libhal_ctx_set_device_added( ctx, new_device ); - p_libhal_ctx_set_device_removed( ctx, removed_device ); - p_libhal_ctx_set_device_property_modified( ctx, property_modified ); - - if (!p_libhal_ctx_init( ctx, &error )) - { - WINE_WARN( "HAL context init failed: %s\n", error.message ); - p_dbus_error_free( &error ); - return 1; - } - - /* retrieve all existing devices */ - if (!(list = p_libhal_get_all_devices( ctx, &num, &error ))) p_dbus_error_free( &error ); - else - { - for (i = 0; i < num; i++) new_device( ctx, list[i] ); - p_libhal_free_string_array( list ); - } - - __TRY - { - while (p_dbus_connection_read_write_dispatch( dbc, -1 )) /* nothing */ ; - } - __EXCEPT( assert_fault ) - { - WINE_WARN( "dbus assertion failure, disabling HAL support\n" ); - return 1; - } - __ENDTRY; - - p_libhal_ctx_shutdown( ctx, &error ); - p_dbus_error_free( &error ); /* just in case */ - p_dbus_connection_close( dbc ); - p_libhal_ctx_free( ctx ); - return 0; -} - -void initialize_hal(void) -{ - HANDLE handle; - - if (!load_functions()) return; - if (!(handle = CreateThread( NULL, 0, hal_thread, NULL, 0, NULL ))) return; - CloseHandle( handle ); -} - -#else /* SONAME_LIBHAL */ - -void initialize_hal(void) -{ - WINE_TRACE( "Skipping, HAL support not compiled in\n" ); -} - -#endif /* SONAME_LIBHAL */ -- 1.5.4.1