Module: wine Branch: master Commit: 2143dee78a0acf8be8c07062e84cc12ef18ef7cb URL: http://source.winehq.org/git/wine.git/?a=commit;h=2143dee78a0acf8be8c07062e8...
Author: Alexandre Julliard julliard@winehq.org Date: Fri Jan 4 14:24:59 2008 +0100
mountmgr.sys: Create disk devices for all configured drives.
---
dlls/mountmgr.sys/mountmgr.c | 199 ++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 199 insertions(+), 0 deletions(-)
diff --git a/dlls/mountmgr.sys/mountmgr.c b/dlls/mountmgr.sys/mountmgr.c index f6c0f20..c24c78c 100644 --- a/dlls/mountmgr.sys/mountmgr.c +++ b/dlls/mountmgr.sys/mountmgr.c @@ -38,6 +38,178 @@
WINE_DEFAULT_DEBUG_CHANNEL(mountmgr);
+#define MAX_DOS_DRIVES 26 +#define MAX_MOUNT_POINTS (2 * MAX_DOS_DRIVES) + +/* extra info for disk devices, stored in DeviceExtension */ +struct disk_device_info +{ + UNICODE_STRING name; /* device name */ +}; + +struct mount_point +{ + DEVICE_OBJECT *device; + UNICODE_STRING link; /* DOS device symlink */ + void *id; /* device unique id */ + unsigned int id_len; +}; + +static struct mount_point mount_points[MAX_MOUNT_POINTS]; + +static inline UNICODE_STRING *get_device_name( DEVICE_OBJECT *dev ) +{ + return &((struct disk_device_info *)dev->DeviceExtension)->name; +} + +/* read a Unix symlink; returned buffer must be freed by caller */ +static char *read_symlink( const char *path ) +{ + char *buffer; + int ret, size = 128; + + for (;;) + { + if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, size ))) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return 0; + } + ret = readlink( path, buffer, size ); + if (ret == -1) + { + RtlFreeHeap( GetProcessHeap(), 0, buffer ); + return 0; + } + if (ret != size) + { + buffer[ret] = 0; + return buffer; + } + RtlFreeHeap( GetProcessHeap(), 0, buffer ); + size *= 2; + } +} + +static NTSTATUS create_disk_device( DRIVER_OBJECT *driver, DWORD type, DEVICE_OBJECT **dev_obj ) +{ + static const WCHAR harddiskW[] = {'\','D','e','v','i','c','e', + '\','H','a','r','d','d','i','s','k','V','o','l','u','m','e','%','u',0}; + static const WCHAR cdromW[] = {'\','D','e','v','i','c','e','\','C','d','R','o','m','%','u',0}; + static const WCHAR floppyW[] = {'\','D','e','v','i','c','e','\','F','l','o','p','p','y','%','u',0}; + + UINT i, first = 0; + NTSTATUS status = 0; + const WCHAR *format; + UNICODE_STRING name; + struct disk_device_info *info; + + switch(type) + { + case DRIVE_REMOVABLE: + format = floppyW; + break; + case DRIVE_CDROM: + format = cdromW; + break; + case DRIVE_FIXED: + default: /* FIXME */ + format = harddiskW; + first = 1; /* harddisk volumes start counting from 1 */ + break; + } + + name.MaximumLength = (strlenW(format) + 10) * sizeof(WCHAR); + name.Buffer = RtlAllocateHeap( GetProcessHeap(), 0, name.MaximumLength ); + for (i = first; i < 32; i++) + { + sprintfW( name.Buffer, format, i ); + name.Length = strlenW(name.Buffer) * sizeof(WCHAR); + status = IoCreateDevice( driver, sizeof(*info), &name, 0, 0, FALSE, dev_obj ); + if (status != STATUS_OBJECT_NAME_COLLISION) break; + } + if (!status) + { + info = (*dev_obj)->DeviceExtension; + info->name = name; + } + else + { + FIXME( "IoCreateDevice %s got %x\n", debugstr_w(name.Buffer), status ); + RtlFreeUnicodeString( &name ); + } + return status; +} + + +static NTSTATUS add_mount_point( DRIVER_OBJECT *driver, DWORD type, int drive, + const void *id, unsigned int id_len ) +{ + static const WCHAR driveW[] = {'\','D','o','s','D','e','v','i','c','e','s','\','%','c',':',0}; + static const WCHAR volumeW[] = {'\','?','?','\','V','o','l','u','m','e','{', + '%','0','8','x','-','%','0','4','x','-','%','0','4','x','-', + '%','0','2','x','%','0','2','x','-','%','0','2','x','%','0','2','x', + '%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','}',0}; + WCHAR *drive_link, *volume_link; + NTSTATUS status; + GUID guid; + UINT i; + struct mount_point *mount_drive = NULL, *mount_volume = NULL; + + /* find two free mount points */ + + for (i = 0; i < MAX_MOUNT_POINTS; i++) + { + if (mount_points[i].device) continue; + if (!mount_drive) + { + mount_drive = &mount_points[i]; + continue; + } + mount_volume = &mount_points[i]; + break; + } + if (!mount_volume) return STATUS_NO_MEMORY; + + /* create the volume */ + + memset( &guid, 0, sizeof(guid) ); /* FIXME */ + guid.Data4[7] = 'A' + drive; + + drive_link = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(driveW) ); + volume_link = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(volumeW) ); + sprintfW( drive_link, driveW, 'A' + drive ); + sprintfW( volume_link, volumeW, guid.Data1, guid.Data2, guid.Data3, + guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], + guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]); + + RtlInitUnicodeString( &mount_drive->link, drive_link ); + RtlInitUnicodeString( &mount_volume->link, volume_link ); + status = create_disk_device( driver, type, &mount_drive->device ); + if (status) + { + RtlFreeUnicodeString( &mount_drive->link ); + RtlFreeUnicodeString( &mount_volume->link ); + return status; + } + + mount_volume->device = mount_drive->device; /* FIXME: incr ref count */ + mount_drive->id = RtlAllocateHeap( GetProcessHeap(), 0, id_len ); + mount_drive->id_len = id_len; + memcpy( mount_drive->id, id, id_len ); + mount_volume->id = RtlAllocateHeap( GetProcessHeap(), 0, id_len ); + mount_volume->id_len = id_len; + memcpy( mount_volume->id, id, id_len ); + + IoCreateSymbolicLink( &mount_drive->link, get_device_name(mount_drive->device) ); + IoCreateSymbolicLink( &mount_volume->link, get_device_name(mount_volume->device) ); + + TRACE( "created device %s symlinks %s %s\n", debugstr_w(get_device_name(mount_drive->device)->Buffer), + debugstr_w(mount_drive->link.Buffer), debugstr_w(mount_volume->link.Buffer) ); + + return STATUS_SUCCESS; +} + /* handler for ioctls on the mount manager device */ static NTSTATUS WINAPI mountmgr_ioctl( DEVICE_OBJECT *device, IRP *irp ) { @@ -78,6 +250,31 @@ static NTSTATUS WINAPI harddisk_ioctl( DEVICE_OBJECT *device, IRP *irp ) return irp->IoStatus.u.Status; }
+/* create mount points for mapped drives */ +static void create_drive_mount_points( DRIVER_OBJECT *driver ) +{ + const char *config_dir = wine_get_config_dir(); + char *buffer, *p, *link; + unsigned int i; + + if ((buffer = RtlAllocateHeap( GetProcessHeap(), 0, + strlen(config_dir) + sizeof("/dosdevices/a:") ))) + { + strcpy( buffer, config_dir ); + strcat( buffer, "/dosdevices/a:" ); + p = buffer + strlen(buffer) - 2; + + for (i = 0; i < MAX_DOS_DRIVES; i++) + { + *p = 'a' + i; + if (!(link = read_symlink( buffer ))) continue; + add_mount_point( driver, DRIVE_FIXED, i, link, strlen(link) ); + RtlFreeHeap( GetProcessHeap(), 0, link ); + } + RtlFreeHeap( GetProcessHeap(), 0, buffer ); + } +} + /* driver entry point for the harddisk driver */ static NTSTATUS WINAPI harddisk_driver_entry( DRIVER_OBJECT *driver, UNICODE_STRING *path ) { @@ -101,6 +298,8 @@ static NTSTATUS WINAPI harddisk_driver_entry( DRIVER_OBJECT *driver, UNICODE_STR return status; }
+ create_drive_mount_points( driver ); + return status; }