mountmgr: Move the DBus support to the Unix library.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2021-11-26 15:38:17 +01:00
parent c210a0e607
commit 95615a4afb
5 changed files with 238 additions and 71 deletions

View file

@ -18,27 +18,29 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include "wine/port.h"
#if 0
#pragma makedep unix
#endif
#include "config.h"
#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <dlfcn.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifdef SONAME_LIBDBUS_1
# include <dbus/dbus.h>
#endif
#include "mountmgr.h"
#include "winnls.h"
#include "excpt.h"
#define USE_WS_PREFIX
#include "winsock2.h"
#include "ws2ipdef.h"
#include "ip2string.h"
#include "dhcpcsdk.h"
#include "unixlib.h"
#include "wine/exception.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(mountmgr);
@ -82,13 +84,6 @@ DBUS_FUNCS;
static int udisks_timeout = -1;
static DBusConnection *connection;
static LONG WINAPI assert_fault(EXCEPTION_POINTERS *eptr)
{
if (eptr->ExceptionRecord->ExceptionCode == EXCEPTION_WINE_ASSERTION)
return EXCEPTION_EXECUTE_HANDLER;
return EXCEPTION_CONTINUE_SEARCH;
}
static inline int starts_with( const char *str, const char *prefix )
{
return !strncmp( str, prefix, strlen(prefix) );
@ -97,19 +92,32 @@ static inline int starts_with( const char *str, const char *prefix )
static GUID *parse_uuid( GUID *guid, const char *str )
{
/* standard uuid format */
if (strlen(str) == 36)
if (strlen(str) == 36 && str[8] == '-' && str[13] == '-' && str[18] == '-' && str[23] == '-')
{
UNICODE_STRING strW;
WCHAR buffer[39];
int i;
unsigned char *out = guid->Data4;
if (MultiByteToWideChar( CP_UNIXCP, 0, str, 36, buffer + 1, 36 ))
if (sscanf( str, "%x-%hx-%hx-", &guid->Data1, &guid->Data2, &guid->Data3 ) != 3) return NULL;
for (i = 19; i < 36; i++)
{
buffer[0] = '{';
buffer[37] = '}';
buffer[38] = 0;
RtlInitUnicodeString( &strW, buffer );
if (!RtlGUIDFromString( &strW, guid )) return guid;
unsigned char val;
if (i == 23) continue;
if (str[i] >= '0' && str[i] <= '9') val = str[i] - '0';
else if (str[i] >= 'a' && str[i] <= 'f') val = str[i] - 'a' + 10;
else if (str[i] >= 'A' && str[i] <= 'F') val = str[i] - 'A' + 10;
else return NULL;
val <<= 4;
i++;
if (str[i] >= '0' && str[i] <= '9') val += str[i] - '0';
else if (str[i] >= 'a' && str[i] <= 'f') val += str[i] - 'a' + 10;
else if (str[i] >= 'A' && str[i] <= 'F') val += str[i] - 'A' + 10;
else return NULL;
*out++ = val;
}
return guid;
}
/* check for xxxx-xxxx format (FAT serial number) */
@ -257,8 +265,8 @@ static void udisks_new_device( const char *udi )
if (device)
{
if (removable) add_dos_device( -1, udi, device, mount_point, drive_type, guid_ptr, NULL );
else if (guid_ptr) add_volume( udi, device, mount_point, DEVICE_HARDDISK_VOL, guid_ptr, NULL, NULL );
if (removable) queue_device_op( ADD_DOS_DEVICE, udi, device, mount_point, drive_type, guid_ptr, NULL, NULL );
else if (guid_ptr) queue_device_op( ADD_VOLUME, udi, device, mount_point, DEVICE_HARDDISK_VOL, guid_ptr, NULL, NULL );
}
p_dbus_message_unref( reply );
@ -268,8 +276,7 @@ static void udisks_new_device( const char *udi )
static void udisks_removed_device( const char *udi )
{
TRACE( "removed %s\n", wine_dbgstr_a(udi) );
if (!remove_dos_device( -1, udi )) remove_volume( udi );
queue_device_op( REMOVE_DEVICE, udi, NULL, NULL, 0, NULL, NULL, NULL );
}
/* UDisks callback for changed device */
@ -426,8 +433,8 @@ static void udisks2_add_device( const char *udi, DBusMessageIter *dict, DBusMess
}
if (device)
{
if (removable) add_dos_device( -1, udi, device, mount_point, drive_type, guid_ptr, NULL );
else if (guid_ptr) add_volume( udi, device, mount_point, DEVICE_HARDDISK_VOL, guid_ptr, id, NULL );
if (removable) queue_device_op( ADD_DOS_DEVICE, udi, device, mount_point, drive_type, guid_ptr, id, NULL );
else if (guid_ptr) queue_device_op( ADD_VOLUME, udi, device, mount_point, DEVICE_HARDDISK_VOL, guid_ptr, id, NULL );
}
}
@ -522,7 +529,7 @@ static DBusHandlerResult udisks_filter( DBusConnection *ctx, DBusMessage *msg, v
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static DWORD WINAPI dbus_thread( void *arg )
void run_dbus_loop(void)
{
static const char udisks_match[] = "type='signal',"
"interface='org.freedesktop.UDisks',"
@ -536,12 +543,14 @@ static DWORD WINAPI dbus_thread( void *arg )
DBusError error;
if (!load_dbus_functions()) return;
p_dbus_error_init( &error );
if (!(connection = 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;
return;
}
/* first try UDisks2 */
@ -561,27 +570,7 @@ static DWORD WINAPI dbus_thread( void *arg )
p_dbus_connection_remove_filter( connection, udisks_filter, NULL );
found:
__TRY
{
while (p_dbus_connection_read_write_dispatch( connection, -1 )) /* nothing */ ;
}
__EXCEPT( assert_fault )
{
WARN( "dbus assertion failure, disabling support\n" );
return 1;
}
__ENDTRY;
return 0;
}
void initialize_dbus(void)
{
HANDLE handle;
if (!load_dbus_functions()) return;
if (!(handle = CreateThread( NULL, 0, dbus_thread, NULL, 0, NULL ))) return;
CloseHandle( handle );
while (p_dbus_connection_read_write_dispatch( connection, -1 )) /* nothing */ ;
}
#if !defined(HAVE_SYSTEMCONFIGURATION_SCDYNAMICSTORECOPYDHCPINFO_H) || !defined(HAVE_SYSTEMCONFIGURATION_SCNETWORKCONFIGURATION_H)
@ -776,28 +765,29 @@ static const char *map_option( ULONG option )
}
}
ULONG get_dhcp_request_param( const char *unix_name, struct mountmgr_dhcp_request_param *param, char *buf, ULONG offset,
ULONG size )
NTSTATUS dhcp_request( void *args )
{
const struct dhcp_request_params *params = args;
DBusMessage *reply;
const char *value;
ULONG ret = 0;
param->offset = param->size = 0;
params->req->offset = params->req->size = 0;
if (!(reply = dhcp4_config_option_request( unix_name, map_option(param->id), &value ))) return 0;
if (!(reply = dhcp4_config_option_request( params->unix_name, map_option(params->req->id), &value ))) return 0;
switch (param->id)
switch (params->req->id)
{
case OPTION_SUBNET_MASK:
case OPTION_ROUTER_ADDRESS:
case OPTION_BROADCAST_ADDRESS:
{
IN_ADDR *ptr = (IN_ADDR *)(buf + offset);
if (value && size >= sizeof(IN_ADDR) && !RtlIpv4StringToAddressA( value, TRUE, NULL, ptr ))
IN_ADDR *ptr = (IN_ADDR *)(params->buffer + params->offset);
if (value && params->size >= sizeof(IN_ADDR))
{
param->offset = offset;
param->size = sizeof(*ptr);
ptr->S_un.S_addr = inet_addr( value );
params->req->offset = params->offset;
params->req->size = sizeof(*ptr);
TRACE( "returning %08x\n", *(DWORD *)ptr );
}
ret = sizeof(*ptr);
@ -807,33 +797,39 @@ ULONG get_dhcp_request_param( const char *unix_name, struct mountmgr_dhcp_reques
case OPTION_DOMAIN_NAME:
case OPTION_MSFT_IE_PROXY:
{
char *ptr = buf + offset;
char *ptr = params->buffer + params->offset;
int len = value ? strlen( value ) : 0;
if (len && size >= len)
if (len && params->size >= len)
{
memcpy( ptr, value, len );
param->offset = offset;
param->size = len;
params->req->offset = params->offset;
params->req->size = len;
TRACE( "returning %s\n", debugstr_an(ptr, len) );
}
ret = len;
break;
}
default:
FIXME( "option %u not supported\n", param->id );
FIXME( "option %u not supported\n", params->req->id );
break;
}
p_dbus_message_unref( reply );
return ret;
*params->ret_size = ret;
return STATUS_SUCCESS;
}
#endif
#else /* SONAME_LIBDBUS_1 */
void initialize_dbus(void)
void run_dbus_loop(void)
{
TRACE( "Skipping, DBUS support not compiled in\n" );
}
NTSTATUS dhcp_request( void *args )
{
return STATUS_NOT_SUPPORTED;
}
#endif /* SONAME_LIBDBUS_1 */

View file

@ -408,7 +408,15 @@ static void WINAPI query_dhcp_request_params( TP_CALLBACK_INSTANCE *instance, vo
offset = FIELD_OFFSET(struct mountmgr_dhcp_request_params, params[query->count]);
for (i = 0; i < query->count; i++)
{
#ifdef __APPLE__
offset += get_dhcp_request_param( query->unix_name, &query->params[i], (char *)query, offset, outsize - offset );
#else
ULONG ret_size;
struct dhcp_request_params params = { query->unix_name, &query->params[i],
(char *)query, offset, outsize - offset, &ret_size };
MOUNTMGR_CALL( dhcp_request, &params );
offset += ret_size;
#endif
if (offset > outsize)
{
if (offset >= sizeof(query->size)) query->size = offset;
@ -438,6 +446,30 @@ static void WINAPI query_symbol_file_callback( TP_CALLBACK_INSTANCE *instance, v
IoCompleteRequest( irp, IO_NO_INCREMENT );
}
/* NT APC called from Unix side to add/remove devices */
static void CALLBACK device_op( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 )
{
struct device_info info;
struct dequeue_device_op_params params = { arg1, &info };
if (MOUNTMGR_CALL( dequeue_device_op, &params )) return;
switch (info.op)
{
case ADD_DOS_DEVICE:
add_dos_device( -1, info.udi, info.device, info.mount_point,
info.type, info.guid, info.scsi_info );
break;
case ADD_VOLUME:
add_volume( info.udi, info.device, info.mount_point, DEVICE_HARDDISK_VOL,
info.guid, info.serial, info.scsi_info );
break;
case REMOVE_DEVICE:
if (!remove_dos_device( -1, info.udi )) remove_volume( info.udi );
break;
}
}
/* handler for ioctls on the mount manager device */
static NTSTATUS WINAPI mountmgr_ioctl( DEVICE_OBJECT *device, IRP *irp )
{
@ -579,6 +611,18 @@ static NTSTATUS WINAPI mountmgr_ioctl( DEVICE_OBJECT *device, IRP *irp )
return status;
}
static DWORD WINAPI device_op_thread( void *arg )
{
for (;;) SleepEx( INFINITE, TRUE ); /* wait for APCs */
return 0;
}
static DWORD WINAPI run_loop_thread( void *arg )
{
return MOUNTMGR_CALL( run_loop, arg );
}
/* main entry point for the mount point manager driver */
NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path )
{
@ -606,6 +650,7 @@ NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path )
DEVICE_OBJECT *device;
HKEY devicemap_key;
NTSTATUS status;
struct run_loop_params params;
TRACE( "%s\n", debugstr_w(path->Buffer) );
@ -636,7 +681,10 @@ NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path )
RtlInitUnicodeString( &nameW, harddiskW );
status = IoCreateDriver( &nameW, harddisk_driver_entry );
initialize_dbus();
params.op_thread = CreateThread( NULL, 0, device_op_thread, NULL, 0, NULL );
params.op_apc = device_op;
CloseHandle( CreateThread( NULL, 0, run_loop_thread, &params, 0, NULL ));
initialize_diskarbitration();
#ifdef _WIN64

View file

@ -36,7 +36,6 @@
#define WINE_MOUNTMGR_EXTENSIONS
#include "ddk/mountmgr.h"
extern void initialize_dbus(void) DECLSPEC_HIDDEN;
extern void initialize_diskarbitration(void) DECLSPEC_HIDDEN;
extern WCHAR *strdupW( const WCHAR * ) DECLSPEC_HIDDEN;
@ -115,6 +114,8 @@ extern struct mount_point *add_volume_mount_point( DEVICE_OBJECT *device, UNICOD
extern void delete_mount_point( struct mount_point *mount ) DECLSPEC_HIDDEN;
extern void set_mount_point_id( struct mount_point *mount, const void *id, unsigned int id_len ) DECLSPEC_HIDDEN;
#ifdef __APPLE__
extern ULONG get_dhcp_request_param( const char *unix_name, struct mountmgr_dhcp_request_param *param,
char *buf, ULONG offset, ULONG size ) DECLSPEC_HIDDEN;
#endif
#endif /* __WINE_MOUNTMGR_H */

View file

@ -34,6 +34,7 @@
#include "unixlib.h"
static struct run_loop_params run_loop_params;
static char *get_dosdevices_path( const char *dev )
{
@ -87,6 +88,69 @@ static void detect_devices( const char **paths, char *names, ULONG size )
*names = 0;
}
void queue_device_op( enum device_op op, const char *udi, const char *device,
const char *mount_point, enum device_type type, const GUID *guid,
const char *serial, const struct scsi_info *scsi_info )
{
struct device_info *info;
char *str, *end;
info = calloc( 1, sizeof(*info) );
str = info->str_buffer;
end = info->str_buffer + sizeof(info->str_buffer);
info->op = op;
info->type = type;
#define ADD_STR(s) if (s && str + strlen(s) + 1 <= end) \
{ \
info->s = strcpy( str, s ); \
str += strlen(str) + 1; \
}
ADD_STR(udi);
ADD_STR(device);
ADD_STR(mount_point);
ADD_STR(serial);
#undef ADD_STR
if (guid)
{
info->guid_buffer = *guid;
info->guid = &info->guid_buffer;
}
if (scsi_info)
{
info->scsi_buffer = *scsi_info;
info->scsi_info = &info->scsi_buffer;
}
NtQueueApcThread( run_loop_params.op_thread, run_loop_params.op_apc, (ULONG_PTR)info, 0, 0 );
}
static NTSTATUS run_loop( void *args )
{
const struct run_loop_params *params = args;
run_loop_params = *params;
run_dbus_loop();
return STATUS_SUCCESS;
}
static NTSTATUS dequeue_device_op( void *args )
{
const struct dequeue_device_op_params *params = args;
struct device_info *src = (struct device_info *)params->arg;
struct device_info *dst = params->info;
/* copy info to client address space and fix up pointers */
*dst = *src;
if (dst->udi) dst->udi = (char *)dst + (src->udi - (char *)src);
if (dst->device) dst->device = (char *)dst + (src->device - (char *)src);
if (dst->mount_point) dst->mount_point = (char *)dst + (src->mount_point - (char *)src);
if (dst->serial) dst->serial = (char *)dst + (src->serial - (char *)src);
if (dst->guid) dst->guid = &dst->guid_buffer;
if (dst->scsi_info) dst->scsi_info = &dst->scsi_buffer;
free( src );
return STATUS_SUCCESS;
}
/* find or create a DOS drive for the corresponding Unix device */
static NTSTATUS add_drive( void *args )
{
@ -361,6 +425,8 @@ static NTSTATUS get_shell_folder( void *args )
const unixlib_entry_t __wine_unix_call_funcs[] =
{
run_loop,
dequeue_device_op,
add_drive,
get_dosdev_symlink,
set_dosdev_symlink,
@ -371,4 +437,5 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
detect_parallel_ports,
set_shell_folder,
get_shell_folder,
dhcp_request,
};

View file

@ -21,6 +21,42 @@
#include "mountmgr.h"
#include "wine/unixlib.h"
enum device_op
{
ADD_DOS_DEVICE,
ADD_VOLUME,
REMOVE_DEVICE
};
struct device_info
{
enum device_op op;
enum device_type type;
const char *udi;
const char *device;
const char *mount_point;
const char *serial;
GUID *guid;
struct scsi_info *scsi_info;
/* buffer space for pointers */
GUID guid_buffer;
struct scsi_info scsi_buffer;
char str_buffer[1024];
};
struct run_loop_params
{
HANDLE op_thread;
PNTAPCFUNC op_apc;
};
struct dequeue_device_op_params
{
ULONG_PTR arg;
struct device_info *info;
};
struct add_drive_params
{
const char *device;
@ -81,8 +117,20 @@ struct get_shell_folder_params
ULONG size;
};
struct dhcp_request_params
{
const char *unix_name;
struct mountmgr_dhcp_request_param *req;
char *buffer;
ULONG offset;
ULONG size;
ULONG *ret_size;
};
enum mountmgr_funcs
{
unix_run_loop,
unix_dequeue_device_op,
unix_add_drive,
unix_get_dosdev_symlink,
unix_set_dosdev_symlink,
@ -93,12 +141,19 @@ enum mountmgr_funcs
unix_detect_parallel_ports,
unix_set_shell_folder,
unix_get_shell_folder,
unix_dhcp_request,
};
extern unixlib_handle_t mountmgr_handle;
#define MOUNTMGR_CALL( func, params ) __wine_unix_call( mountmgr_handle, unix_ ## func, params )
extern void queue_device_op( enum device_op op, const char *udi, const char *device,
const char *mount_point, enum device_type type, const GUID *guid,
const char *disk_serial, const struct scsi_info *info ) DECLSPEC_HIDDEN;
extern void run_dbus_loop(void) DECLSPEC_HIDDEN;
extern NTSTATUS dhcp_request( void *args ) DECLSPEC_HIDDEN;
extern NTSTATUS query_symbol_file( void *buff, ULONG insize, ULONG outsize, ULONG *info ) DECLSPEC_HIDDEN;
extern NTSTATUS read_credential( void *buff, ULONG insize, ULONG outsize, ULONG *info ) DECLSPEC_HIDDEN;
extern NTSTATUS write_credential( void *buff, ULONG insize, ULONG outsize, ULONG *info ) DECLSPEC_HIDDEN;