Alexandre Julliard : mountmgr: Try to match and reuse volumes when creating /updating a drive.

Alexandre Julliard julliard at winehq.org
Thu Jul 23 09:59:17 CDT 2009


Module: wine
Branch: master
Commit: 15acd35fa27d09af01698083af21ef3772edcae1
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=15acd35fa27d09af01698083af21ef3772edcae1

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Wed Jul 22 20:56:04 2009 +0200

mountmgr: Try to match and reuse volumes when creating/updating a drive.

---

 dlls/mountmgr.sys/device.c |  104 +++++++++++++++++++++++++++++++++-----------
 1 files changed, 78 insertions(+), 26 deletions(-)

diff --git a/dlls/mountmgr.sys/device.c b/dlls/mountmgr.sys/device.c
index 35797e4..20a7826 100644
--- a/dlls/mountmgr.sys/device.c
+++ b/dlls/mountmgr.sys/device.c
@@ -361,8 +361,8 @@ static NTSTATUS create_volume( const char *udi, enum device_type type, struct vo
 }
 
 /* create the disk device for a given volume */
-static NTSTATUS create_dos_device( const char *udi, int letter, enum device_type type,
-                                   struct dos_drive **drive_ret )
+static NTSTATUS create_dos_device( struct volume *volume, const char *udi, int letter,
+                                   enum device_type type, struct dos_drive **drive_ret )
 {
     struct dos_drive *drive;
     NTSTATUS status;
@@ -371,7 +371,15 @@ static NTSTATUS create_dos_device( const char *udi, int letter, enum device_type
     drive->drive = letter;
     drive->mount = NULL;
 
-    if (!(status = create_volume( udi, type, &drive->volume )))
+    if (volume)
+    {
+        if (udi) set_volume_udi( volume, udi );
+        drive->volume = volume;
+        status = STATUS_SUCCESS;
+    }
+    else status = create_volume( udi, type, &drive->volume );
+
+    if (status == STATUS_SUCCESS)
     {
         grab_volume( drive->volume );
         list_add_tail( &drives_list, &drive->entry );
@@ -391,6 +399,31 @@ static void delete_dos_device( struct dos_drive *drive )
     RtlFreeHeap( GetProcessHeap(), 0, drive );
 }
 
+/* find a volume that matches the parameters */
+static struct volume *find_matching_volume( const char *udi, const char *device,
+                                            const char *mount_point, enum device_type type )
+{
+    struct volume *volume;
+    struct disk_device *disk_device;
+
+    LIST_FOR_EACH_ENTRY( volume, &volumes_list, struct volume, entry )
+    {
+        /* when we have a udi we only match drives added manually */
+        if (udi && volume->udi) continue;
+        /* and when we don't have a udi we only match dynamic drives */
+        if (!udi && !volume->udi) continue;
+
+        disk_device = volume->device;
+        if (disk_device->type != type) continue;
+        if (device && disk_device->unix_device && strcmp( device, disk_device->unix_device )) continue;
+        if (mount_point && disk_device->unix_mount && strcmp( mount_point, disk_device->unix_mount )) continue;
+        TRACE( "found matching volume %s for device %s mount %s type %u\n",
+               debugstr_guid(&volume->guid), debugstr_a(device), debugstr_a(mount_point), type );
+        return volume;
+    }
+    return NULL;
+}
+
 /* change the information for an existing volume */
 static NTSTATUS set_volume_info( struct volume *volume, struct dos_drive *drive, const char *device,
                                  const char *mount_point, enum device_type type, const GUID *guid )
@@ -424,7 +457,7 @@ static NTSTATUS set_volume_info( struct volume *volume, struct dos_drive *drive,
     disk_device->unix_device = strdupA( device );
     disk_device->unix_mount = strdupA( mount_point );
 
-    if (memcmp( &volume->guid, guid, sizeof(volume->guid) ))
+    if (guid && memcmp( &volume->guid, guid, sizeof(volume->guid) ))
     {
         volume->guid = *guid;
         if (volume->mount)
@@ -450,17 +483,23 @@ static NTSTATUS set_volume_info( struct volume *volume, struct dos_drive *drive,
     return STATUS_SUCCESS;
 }
 
-/* set or change the drive letter for an existing drive */
-static void set_drive_letter( struct dos_drive *drive, int letter )
+/* change the drive letter or volume for an existing drive */
+static void set_drive_info( struct dos_drive *drive, int letter, struct volume *volume )
 {
-    struct volume *volume = drive->volume;
-
-    if (drive->drive == letter) return;
-    if (drive->mount) delete_mount_point( drive->mount );
-    if (volume->mount) delete_mount_point( volume->mount );
-    drive->drive = letter;
-    drive->mount = NULL;
-    volume->mount = NULL;
+    if (drive->drive != letter)
+    {
+        if (drive->mount) delete_mount_point( drive->mount );
+        drive->mount = NULL;
+        drive->drive = letter;
+    }
+    if (drive->volume != volume)
+    {
+        if (drive->mount) delete_mount_point( drive->mount );
+        drive->mount = NULL;
+        grab_volume( volume );
+        release_volume( drive->volume );
+        drive->volume = volume;
+    }
 }
 
 static inline int is_valid_device( struct stat *st )
@@ -552,6 +591,7 @@ static void create_drive_devices(void)
 {
     char *path, *p, *link, *device;
     struct dos_drive *drive;
+    struct volume *volume;
     unsigned int i;
     HKEY drives_key;
     enum device_type drive_type;
@@ -588,9 +628,12 @@ static void create_drive_devices(void)
             }
         }
 
-        if (!create_dos_device( NULL, i, drive_type, &drive ))
+        volume = find_matching_volume( NULL, device, link, drive_type );
+        if (!create_dos_device( volume, NULL, i, drive_type, &drive ))
         {
-            set_volume_info( drive->volume, drive, device, link, drive_type, get_default_uuid(i) );
+            /* don't reset uuid if we used an existing volume */
+            const GUID *guid = volume ? NULL : get_default_uuid(i);
+            set_volume_info( drive->volume, drive, device, link, drive_type, guid );
         }
         else
         {
@@ -615,7 +658,12 @@ NTSTATUS add_volume( const char *udi, const char *device, const char *mount_poin
     LIST_FOR_EACH_ENTRY( volume, &volumes_list, struct volume, entry )
         if (volume->udi && !strcmp( udi, volume->udi )) goto found;
 
-    if ((status = create_volume( udi, type, &volume ))) return status;
+    /* udi not found, search for a non-dynamic volume */
+    if ((volume = find_matching_volume( udi, device, mount_point, type )))
+    {
+        set_volume_udi( volume, udi );
+    }
+    else if ((status = create_volume( udi, type, &volume ))) return status;
 
 found:
     return set_volume_info( volume, NULL, device, mount_point, type, guid );
@@ -644,6 +692,7 @@ NTSTATUS add_dos_device( int letter, const char *udi, const char *device,
     HKEY hkey;
     NTSTATUS status = STATUS_SUCCESS;
     struct dos_drive *drive, *next;
+    struct volume *volume = find_matching_volume( udi, device, mount_point, type );
 
     if (!(path = get_dosdevices_path( &p ))) return STATUS_NO_MEMORY;
 
@@ -664,25 +713,28 @@ NTSTATUS add_dos_device( int letter, const char *udi, const char *device,
     }
     else  /* simply reset the device symlink */
     {
-        *p = 'a' + letter;
         LIST_FOR_EACH_ENTRY( drive, &drives_list, struct dos_drive, entry )
+            if (drive->drive == letter) break;
+
+        *p = 'a' + letter;
+        if (&drive->entry == &drives_list) update_symlink( path, device, NULL );
+        else
         {
-            if (drive->drive != letter) continue;
             update_symlink( path, device, drive->volume->device->unix_device );
-            goto found;
+            delete_dos_device( drive );
         }
-        update_symlink( path, device, NULL );
     }
 
-    if ((status = create_dos_device( udi, letter, type, &drive ))) goto done;
+    if ((status = create_dos_device( volume, udi, letter, type, &drive ))) goto done;
 
 found:
-    if (!guid) guid = get_default_uuid( letter );
+    if (!guid && !volume) guid = get_default_uuid( letter );
+    if (!volume) volume = drive->volume;
+    set_drive_info( drive, letter, volume );
     p[0] = 'a' + drive->drive;
     p[2] = 0;
-    update_symlink( path, mount_point, drive->volume->device->unix_mount );
-    set_drive_letter( drive, letter );
-    set_volume_info( drive->volume, drive, device, mount_point, type, guid );
+    update_symlink( path, mount_point, volume->device->unix_mount );
+    set_volume_info( volume, drive, device, mount_point, type, guid );
 
     TRACE( "added device %c: udi %s for %s on %s type %u\n",
            'a' + drive->drive, wine_dbgstr_a(udi), wine_dbgstr_a(device),




More information about the wine-cvs mailing list