From dde935d1111d6f87c452ef91cc9283a6d1bc296c Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Tue, 3 Oct 2006 12:40:27 +0200 Subject: [PATCH] explorer: Split the device management to a separate file to make it usable independently of HAL support. --- programs/explorer/Makefile.in | 1 + programs/explorer/device.c | 250 +++++++++++++++++++++++++++ programs/explorer/explorer_private.h | 4 + programs/explorer/hal.c | 211 +--------------------- 4 files changed, 257 insertions(+), 209 deletions(-) create mode 100644 programs/explorer/device.c diff --git a/programs/explorer/Makefile.in b/programs/explorer/Makefile.in index 5d295a77357..d2630f45429 100644 --- a/programs/explorer/Makefile.in +++ b/programs/explorer/Makefile.in @@ -10,6 +10,7 @@ EXTRADEFS = @HALINCL@ C_SRCS = \ desktop.c \ + device.c \ explorer.c \ hal.c \ systray.c diff --git a/programs/explorer/device.c b/programs/explorer/device.c new file mode 100644 index 00000000000..0b86b436451 --- /dev/null +++ b/programs/explorer/device.c @@ -0,0 +1,250 @@ +/* + * 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 ); +} + +/* 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 || !S_ISBLK( dev_st.st_mode )) 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 (!S_ISBLK( drive_st.st_mode )) 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 void set_mount_point( struct dos_drive *drive, const char *mount_point ) +{ + char *path, *p; + struct stat path_st, mnt_st; + + if (drive->drive == -1) return; + if (!(path = get_dosdevices_path())) return; + 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 ); + } + } + else unlink( path ); + + HeapFree( GetProcessHeap(), 0, path ); +} + +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) + { + 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 ); + } + + 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/explorer_private.h b/programs/explorer/explorer_private.h index a69ce617834..806dd4c3dba 100644 --- a/programs/explorer/explorer_private.h +++ b/programs/explorer/explorer_private.h @@ -21,6 +21,10 @@ #ifndef __WINE_EXPLORER_PRIVATE_H #define __WINE_EXPLORER_PRIVATE_H +extern BOOL add_dos_device( const char *udi, const char *device, + const char *mount_point, const char *type ); +extern BOOL remove_dos_device( const char *udi ); + extern void manage_desktop( char *arg ); extern void initialize_hal(void); extern void initialize_systray(void); diff --git a/programs/explorer/hal.c b/programs/explorer/hal.c index bcb1d983ee2..dc7f66f34c0 100644 --- a/programs/explorer/hal.c +++ b/programs/explorer/hal.c @@ -31,13 +31,12 @@ #include "winbase.h" #include "winreg.h" #include "winuser.h" -#include "dbt.h" #include "excpt.h" #include "wine/library.h" -#include "wine/list.h" #include "wine/exception.h" #include "wine/debug.h" +#include "explorer_private.h" WINE_DEFAULT_DEBUG_CHANNEL(explorer); @@ -46,16 +45,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(explorer); #include #include -struct dos_drive -{ - struct list entry; - char *udi; - int drive; -}; - -static struct list drives_list = LIST_INIT(drives_list); - - #define DBUS_FUNCS \ DO_FUNC(dbus_bus_get); \ DO_FUNC(dbus_connection_close); \ @@ -119,198 +108,6 @@ static WINE_EXCEPTION_FILTER(assert_fault) return EXCEPTION_CONTINUE_SEARCH; } -/* 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 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; -} - -/* 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 || !S_ISBLK( dev_st.st_mode )) 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 (!S_ISBLK( drive_st.st_mode )) 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 void set_mount_point( struct dos_drive *drive, const char *mount_point ) -{ - char *path, *p; - struct stat path_st, mnt_st; - - if (drive->drive == -1) return; - if (!(path = get_dosdevices_path())) return; - 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 ); - } - } - else unlink( path ); - - HeapFree( GetProcessHeap(), 0, path ); -} - -static void 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; - if (!(drive->udi = HeapAlloc( GetProcessHeap(), 0, strlen(udi)+1 ))) - { - HeapFree( GetProcessHeap(), 0, drive ); - return; - } - 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 ); - } -} - -static void remove_dos_device( struct dos_drive *drive ) -{ - HKEY hkey; - - if (drive->drive != -1) - { - 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 ); - } - - send_notify( drive->drive, DBT_DEVICEREMOVECOMPLETE ); - } - - list_remove( &drive->entry ); - HeapFree( GetProcessHeap(), 0, drive->udi ); - HeapFree( GetProcessHeap(), 0, drive ); -} - /* HAL callback for new device */ static void new_device( LibHalContext *ctx, const char *udi ) { @@ -352,18 +149,14 @@ done: static void removed_device( LibHalContext *ctx, const char *udi ) { DBusError error; - struct dos_drive *drive; WINE_TRACE( "removed %s\n", wine_dbgstr_a(udi) ); - LIST_FOR_EACH_ENTRY( drive, &drives_list, struct dos_drive, entry ) + if (remove_dos_device( udi )) { - if (strcmp( udi, drive->udi )) continue; p_dbus_error_init( &error ); p_libhal_device_remove_property_watch( ctx, udi, &error ); - remove_dos_device( drive ); p_dbus_error_free( &error ); - return; } }