mountmgr: Add support for UDisks2.

This commit is contained in:
Alexandre Julliard 2012-06-13 17:51:00 +02:00
parent 2f86012373
commit 2ffc57821f

View File

@ -66,6 +66,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(mountmgr);
DO_FUNC(dbus_message_iter_append_basic); \
DO_FUNC(dbus_message_iter_get_arg_type); \
DO_FUNC(dbus_message_iter_get_basic); \
DO_FUNC(dbus_message_iter_get_fixed_array); \
DO_FUNC(dbus_message_iter_init); \
DO_FUNC(dbus_message_iter_init_append); \
DO_FUNC(dbus_message_iter_next); \
@ -364,6 +365,161 @@ static BOOL udisks_enumerate_devices(void)
return TRUE;
}
/* to make things easier, UDisks2 stores strings as array of bytes instead of strings... */
static const char *udisks2_string_from_array( DBusMessageIter *iter )
{
DBusMessageIter string;
const char *array;
int size;
p_dbus_message_iter_recurse( iter, &string );
p_dbus_message_iter_get_fixed_array( &string, &array, &size );
return array;
}
/* find the drive entry in the dictionary and get its parameters */
static void udisks2_get_drive_info( const char *drive_name, DBusMessageIter *dict,
enum device_type *drive_type, int *removable )
{
DBusMessageIter iter, drive, variant;
const char *name;
p_dbus_message_iter_recurse( dict, &iter );
while ((name = udisks_next_dict_entry( &iter, &drive )))
{
if (strcmp( name, drive_name )) continue;
while ((name = udisks_next_dict_entry( &drive, &iter )))
{
if (strcmp( name, "org.freedesktop.UDisks2.Drive" )) continue;
while ((name = udisks_next_dict_entry( &iter, &variant )))
{
if (!strcmp( name, "Removable" ))
p_dbus_message_iter_get_basic( &variant, removable );
else if (!strcmp( name, "MediaCompatibility" ))
*drive_type = udisks_parse_media_compatibility( &variant );
}
}
}
}
static void udisks2_add_device( const char *udi, DBusMessageIter *dict, DBusMessageIter *block )
{
DBusMessageIter iter, variant, paths, string;
const char *device = NULL;
const char *mount_point = NULL;
const char *type = NULL;
const char *drive = NULL;
GUID guid, *guid_ptr = NULL;
const char *iface, *name;
int removable = FALSE;
enum device_type drive_type = DEVICE_UNKNOWN;
while ((iface = udisks_next_dict_entry( block, &iter )))
{
if (!strcmp( iface, "org.freedesktop.UDisks2.Filesystem" ))
{
while ((name = udisks_next_dict_entry( &iter, &variant )))
{
if (!strcmp( name, "MountPoints" ))
{
p_dbus_message_iter_recurse( &variant, &paths );
if (p_dbus_message_iter_get_arg_type( &paths ) == DBUS_TYPE_ARRAY)
{
p_dbus_message_iter_recurse( &variant, &string );
mount_point = udisks2_string_from_array( &string );
}
}
}
}
if (!strcmp( iface, "org.freedesktop.UDisks2.Block" ))
{
while ((name = udisks_next_dict_entry( &iter, &variant )))
{
if (!strcmp( name, "Device" ))
device = udisks2_string_from_array( &variant );
else if (!strcmp( name, "IdType" ))
p_dbus_message_iter_get_basic( &variant, &type );
else if (!strcmp( name, "Drive" ))
{
p_dbus_message_iter_get_basic( &variant, &drive );
udisks2_get_drive_info( drive, dict, &drive_type, &removable );
}
else if (!strcmp( name, "IdUUID" ))
{
char *uuid_str;
p_dbus_message_iter_get_basic( &variant, &uuid_str );
guid_ptr = parse_uuid( &guid, uuid_str );
}
}
}
}
TRACE( "udi %s device %s mount point %s uuid %s type %s removable %u\n",
debugstr_a(udi), debugstr_a(device), debugstr_a(mount_point),
debugstr_guid(guid_ptr), debugstr_a(type), removable );
if (type)
{
if (!strcmp( type, "iso9660" ))
{
removable = TRUE;
drive_type = DEVICE_CDROM;
}
else if (!strcmp( type, "udf" ))
{
removable = TRUE;
drive_type = DEVICE_DVD;
}
}
if (device)
{
if (removable) add_dos_device( -1, udi, device, mount_point, drive_type, guid_ptr );
else if (guid_ptr) add_volume( udi, device, mount_point, DEVICE_HARDDISK_VOL, guid_ptr );
}
}
/* UDisks2 is almost, but not quite, entirely unlike UDisks.
* It would have been easy to make it backwards compatible, but where would be the fun in that?
*/
static BOOL udisks2_add_devices( const char *changed )
{
DBusMessage *request, *reply;
DBusMessageIter dict, iter, block;
DBusError error;
const char *udi;
request = p_dbus_message_new_method_call( "org.freedesktop.UDisks2", "/org/freedesktop/UDisks2",
"org.freedesktop.DBus.ObjectManager", "GetManagedObjects" );
if (!request) return FALSE;
p_dbus_error_init( &error );
reply = p_dbus_connection_send_with_reply_and_block( connection, request, udisks_timeout, &error );
p_dbus_message_unref( request );
if (!reply)
{
WARN( "failed: %s\n", error.message );
p_dbus_error_free( &error );
return FALSE;
}
p_dbus_error_free( &error );
p_dbus_message_iter_init( reply, &dict );
if (p_dbus_message_iter_get_arg_type( &dict ) == DBUS_TYPE_ARRAY)
{
p_dbus_message_iter_recurse( &dict, &iter );
while ((udi = udisks_next_dict_entry( &iter, &block )))
{
if (!starts_with( udi, "/org/freedesktop/UDisks2/block_devices/" )) continue;
if (changed && strcmp( changed, udi )) continue;
udisks2_add_device( udi, &dict, &block );
}
}
else WARN( "unexpected args in GetManagedObjects reply\n" );
p_dbus_message_unref( reply );
return TRUE;
}
static DBusHandlerResult udisks_filter( DBusConnection *ctx, DBusMessage *msg, void *user_data )
{
char *path;
@ -371,6 +527,7 @@ static DBusHandlerResult udisks_filter( DBusConnection *ctx, DBusMessage *msg, v
p_dbus_error_init( &error );
/* udisks signals */
if (p_dbus_message_is_signal( msg, "org.freedesktop.UDisks", "DeviceAdded" ) &&
p_dbus_message_get_args( msg, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID ))
{
@ -386,6 +543,24 @@ static DBusHandlerResult udisks_filter( DBusConnection *ctx, DBusMessage *msg, v
{
udisks_changed_device( path );
}
/* udisks2 signals */
else if (p_dbus_message_is_signal( msg, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded" ) &&
p_dbus_message_get_args( msg, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID ))
{
TRACE( "added %s\n", wine_dbgstr_a(path) );
udisks2_add_devices( path );
}
else if (p_dbus_message_is_signal( msg, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved" ) &&
p_dbus_message_get_args( msg, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID ))
{
udisks_removed_device( path );
}
else if (p_dbus_message_is_signal( msg, "org.freedesktop.DBus.Properties", "PropertiesChanged" ))
{
const char *udi = p_dbus_message_get_path( msg );
TRACE( "changed %s\n", wine_dbgstr_a(udi) );
udisks2_add_devices( udi );
}
else TRACE( "ignoring message type=%d path=%s interface=%s method=%s\n",
p_dbus_message_get_type( msg ), p_dbus_message_get_path( msg ),
p_dbus_message_get_interface( msg ), p_dbus_message_get_member( msg ) );
@ -514,6 +689,12 @@ static DWORD WINAPI dbus_thread( void *arg )
static const char udisks_match[] = "type='signal',"
"interface='org.freedesktop.UDisks',"
"sender='org.freedesktop.UDisks'";
static const char udisks2_match_interfaces[] = "type='signal',"
"interface='org.freedesktop.DBus.ObjectManager',"
"path='/org/freedesktop/UDisks2'";
static const char udisks2_match_properties[] = "type='signal',"
"interface='org.freedesktop.DBus.Properties'";
DBusError error;
@ -525,23 +706,33 @@ static DWORD WINAPI dbus_thread( void *arg )
return 1;
}
if (p_dbus_connection_add_filter( connection, udisks_filter, NULL, NULL ))
p_dbus_bus_add_match( connection, udisks_match, &error );
/* first try UDisks2 */
if (!udisks_enumerate_devices())
{
p_dbus_bus_remove_match( connection, udisks_match, &error );
p_dbus_connection_remove_filter( connection, udisks_filter, NULL );
p_dbus_connection_add_filter( connection, udisks_filter, NULL, NULL );
p_dbus_bus_add_match( connection, udisks2_match_interfaces, &error );
p_dbus_bus_add_match( connection, udisks2_match_properties, &error );
if (udisks2_add_devices( NULL )) goto found;
p_dbus_bus_remove_match( connection, udisks2_match_interfaces, &error );
p_dbus_bus_remove_match( connection, udisks2_match_properties, &error );
/* then try UDisks */
p_dbus_bus_add_match( connection, udisks_match, &error );
if (udisks_enumerate_devices()) goto found;
p_dbus_bus_remove_match( connection, udisks_match, &error );
p_dbus_connection_remove_filter( connection, udisks_filter, NULL );
/* then finally HAL */
#ifdef SONAME_LIBHAL
if (!hal_enumerate_devices())
{
p_dbus_error_free( &error );
return 1;
}
#endif
if (!hal_enumerate_devices())
{
p_dbus_error_free( &error );
return 1;
}
#endif
found:
__TRY
{
while (p_dbus_connection_read_write_dispatch( connection, -1 )) /* nothing */ ;