/* remove an existing dos drive, by letter or udi */ NTSTATUS remove_dos_device( int letter, const char *udi ) { HKEY hkey; struct dos_drive *drive; LIST_FOR_EACH_ENTRY( drive, &drives_list, struct dos_drive, entry ) { if (letter != -1 && drive->drive != letter) continue; if (udi) { if (!drive->udi) continue; if (strcmp( udi, drive->udi )) continue; } if (drive->drive != -1) { BOOL modified = set_unix_mount_point( drive, NULL ); /* clear the registry key too */ if (!RegOpenKeyW( HKEY_LOCAL_MACHINE, drives_keyW, &hkey )) { WCHAR name[3] = {'a',':',0}; name[0] += drive->drive; RegDeleteValueW( hkey, name ); RegCloseKey( hkey ); } if (modified && udi) send_notify( drive->drive, DBT_DEVICEREMOVECOMPLETE ); } delete_disk_device( drive ); return STATUS_SUCCESS; } return STATUS_NO_SUCH_DEVICE; }
/* 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 ) { void *id = NULL; unsigned int id_len = 0; struct disk_device *disk_device = volume->device; NTSTATUS status; if (type != disk_device->type) { if ((status = create_disk_device( type, &disk_device ))) return status; if (volume->mount) { delete_mount_point( volume->mount ); volume->mount = NULL; } if (drive && drive->mount) { delete_mount_point( drive->mount ); drive->mount = NULL; } delete_disk_device( volume->device ); volume->device = disk_device; } else { RtlFreeHeap( GetProcessHeap(), 0, disk_device->unix_device ); RtlFreeHeap( GetProcessHeap(), 0, disk_device->unix_mount ); } disk_device->unix_device = strdupA( device ); disk_device->unix_mount = strdupA( mount_point ); if (guid && memcmp( &volume->guid, guid, sizeof(volume->guid) )) { volume->guid = *guid; if (volume->mount) { delete_mount_point( volume->mount ); volume->mount = NULL; } } if (!volume->mount) volume->mount = add_volume_mount_point( disk_device->dev_obj, &disk_device->name, &volume->guid ); if (drive && !drive->mount) drive->mount = add_dosdev_mount_point( disk_device->dev_obj, &disk_device->name, drive->drive ); if (disk_device->unix_mount) { id = disk_device->unix_mount; id_len = strlen( disk_device->unix_mount ) + 1; } if (volume->mount) set_mount_point_id( volume->mount, id, id_len, -1 ); if (drive && drive->mount) set_mount_point_id( drive->mount, id, id_len, drive->drive ); return STATUS_SUCCESS; }
/* release a volume and delete the corresponding disk device when refcount is 0 */ static unsigned int release_volume( struct volume *volume ) { unsigned int ret = --volume->ref; if (!ret) { TRACE( "%s udi %s\n", debugstr_guid(&volume->guid), debugstr_a(volume->udi) ); assert( !volume->udi ); list_remove( &volume->entry ); if (volume->mount) delete_mount_point( volume->mount ); delete_disk_device( volume->device ); RtlFreeHeap( GetProcessHeap(), 0, volume ); } return ret; }
/* create a new dos drive */ NTSTATUS add_dos_device( int letter, const char *udi, const char *device, const char *mount_point, enum device_type type ) { struct dos_drive *drive, *next; if (letter == -1) /* auto-assign a letter */ { letter = add_drive( device, type ); if (letter == -1) return STATUS_OBJECT_NAME_COLLISION; } else /* simply reset the device symlink */ { char *path, *p; if (!(path = get_dosdevices_path( &p ))) return STATUS_NO_MEMORY; *p = 'a' + letter; unlink( path ); if (device) symlink( device, path ); } LIST_FOR_EACH_ENTRY_SAFE( drive, next, &drives_list, struct dos_drive, entry ) { if (udi && drive->udi && !strcmp( udi, drive->udi )) { if (type == drive->type) goto found; delete_disk_device( drive ); continue; } if (drive->drive == letter) delete_disk_device( drive ); } if (create_disk_device( udi, type, &drive )) return STATUS_NO_MEMORY; found: RtlFreeHeap( GetProcessHeap(), 0, drive->unix_device ); drive->unix_device = strdupA( device ); set_drive_letter( drive, letter ); set_unix_mount_point( drive, mount_point ); if (drive->drive != -1) { HKEY hkey; TRACE( "added device %c: udi %s for %s on %s type %u\n", 'a' + drive->drive, wine_dbgstr_a(udi), wine_dbgstr_a(device), wine_dbgstr_a(mount_point), type ); /* hack: force the drive type in the registry */ if (!RegCreateKeyW( HKEY_LOCAL_MACHINE, drives_keyW, &hkey )) { const WCHAR *type_name = drive_types[type]; WCHAR name[3] = {'a',':',0}; name[0] += drive->drive; if (!type_name[0] && type == DEVICE_HARDDISK) type_name = drive_types[DEVICE_FLOPPY]; if (type_name[0]) RegSetValueExW( hkey, name, 0, REG_SZ, (const BYTE *)type_name, (strlenW(type_name) + 1) * sizeof(WCHAR) ); else RegDeleteValueW( hkey, name ); RegCloseKey( hkey ); } if (udi) send_notify( drive->drive, DBT_DEVICEARRIVAL ); } return STATUS_SUCCESS; }