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

This commit is contained in:
Alexandre Julliard 2009-07-22 20:56:04 +02:00
parent 0da2e46eaf
commit 15acd35fa2
1 changed files with 78 additions and 26 deletions

View File

@ -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 )
{
if (drive->drive != letter)
{
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;
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),