NTSTATUS vol_close(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { volume_device_extension* vde = DeviceObject->DeviceExtension; pdo_device_extension* pdode = vde->pdode; TRACE("(%p, %p)\n", DeviceObject, Irp); Irp->IoStatus.Information = 0; ExAcquireResourceExclusiveLite(&pdo_list_lock, TRUE); ExAcquireResourceSharedLite(&pdode->child_lock, TRUE); if (InterlockedDecrement(&vde->open_count) == 0 && vde->removing) { NTSTATUS Status; UNICODE_STRING mmdevpath; PDEVICE_OBJECT mountmgr; PFILE_OBJECT mountmgrfo; PDEVICE_OBJECT pdo; RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME); Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &mountmgrfo, &mountmgr); if (!NT_SUCCESS(Status)) ERR("IoGetDeviceObjectPointer returned %08x\n", Status); else { remove_drive_letter(mountmgr, &vde->name); ObDereferenceObject(mountmgrfo); } if (vde->mounted_device) { device_extension* Vcb = vde->mounted_device->DeviceExtension; Vcb->vde = NULL; } if (vde->name.Buffer) ExFreePool(vde->name.Buffer); ExReleaseResourceLite(&pdode->child_lock); ExDeleteResourceLite(&pdode->child_lock); if (vde->pdo->AttachedDevice) IoDetachDevice(vde->pdo); pdo = vde->pdo; IoDeleteDevice(vde->device); if (!no_pnp) IoDeleteDevice(pdo); } else ExReleaseResourceLite(&pdode->child_lock); ExReleaseResourceLite(&pdo_list_lock); return STATUS_SUCCESS; }
void add_volume_device(superblock* sb, PDEVICE_OBJECT mountmgr, PUNICODE_STRING devpath, UINT64 length, ULONG disk_num, ULONG part_num) { NTSTATUS Status; LIST_ENTRY* le; PDEVICE_OBJECT DeviceObject; volume_child* vc; PFILE_OBJECT FileObject; UNICODE_STRING devpath2; BOOL inserted = FALSE, new_pdo = FALSE; pdo_device_extension* pdode = NULL; PDEVICE_OBJECT pdo = NULL; if (devpath->Length == 0) return; ExAcquireResourceExclusiveLite(&pdo_list_lock, TRUE); le = pdo_list.Flink; while (le != &pdo_list) { pdo_device_extension* pdode2 = CONTAINING_RECORD(le, pdo_device_extension, list_entry); if (RtlCompareMemory(&pdode2->uuid, &sb->uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) { pdode = pdode2; break; } le = le->Flink; } Status = IoGetDeviceObjectPointer(devpath, FILE_READ_ATTRIBUTES, &FileObject, &DeviceObject); if (!NT_SUCCESS(Status)) { ERR("IoGetDeviceObjectPointer returned %08x\n", Status); ExReleaseResourceLite(&pdo_list_lock); return; } if (!pdode) { if (no_pnp) { Status = IoReportDetectedDevice(drvobj, InterfaceTypeUndefined, 0xFFFFFFFF, 0xFFFFFFFF, NULL, NULL, 0, &pdo); if (!NT_SUCCESS(Status)) { ERR("IoReportDetectedDevice returned %08x\n", Status); ExReleaseResourceLite(&pdo_list_lock); return; } pdode = ExAllocatePoolWithTag(NonPagedPool, sizeof(pdo_device_extension), ALLOC_TAG); if (!pdode) { ERR("out of memory\n"); ExReleaseResourceLite(&pdo_list_lock); return; } } else { Status = IoCreateDevice(drvobj, sizeof(pdo_device_extension), NULL, FILE_DEVICE_DISK, FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, FALSE, &pdo); if (!NT_SUCCESS(Status)) { ERR("IoCreateDevice returned %08x\n", Status); ExReleaseResourceLite(&pdo_list_lock); goto fail; } pdo->Flags |= DO_BUS_ENUMERATED_DEVICE; pdode = pdo->DeviceExtension; } RtlZeroMemory(pdode, sizeof(pdo_device_extension)); pdode->type = VCB_TYPE_PDO; pdode->pdo = pdo; pdode->uuid = sb->uuid; ExInitializeResourceLite(&pdode->child_lock); InitializeListHead(&pdode->children); pdode->num_children = sb->num_devices; pdode->children_loaded = 0; pdo->Flags &= ~DO_DEVICE_INITIALIZING; pdo->SectorSize = (USHORT)sb->sector_size; ExAcquireResourceExclusiveLite(&pdode->child_lock, TRUE); new_pdo = TRUE; } else { ExAcquireResourceExclusiveLite(&pdode->child_lock, TRUE); ExConvertExclusiveToSharedLite(&pdo_list_lock); le = pdode->children.Flink; while (le != &pdode->children) { volume_child* vc2 = CONTAINING_RECORD(le, volume_child, list_entry); if (RtlCompareMemory(&vc2->uuid, &sb->dev_item.device_uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) { // duplicate, ignore ExReleaseResourceLite(&pdode->child_lock); ExReleaseResourceLite(&pdo_list_lock); goto fail; } le = le->Flink; } } vc = ExAllocatePoolWithTag(PagedPool, sizeof(volume_child), ALLOC_TAG); if (!vc) { ERR("out of memory\n"); ExReleaseResourceLite(&pdode->child_lock); ExReleaseResourceLite(&pdo_list_lock); goto fail; } vc->uuid = sb->dev_item.device_uuid; vc->devid = sb->dev_item.dev_id; vc->generation = sb->generation; vc->notification_entry = NULL; Status = IoRegisterPlugPlayNotification(EventCategoryTargetDeviceChange, 0, FileObject, drvobj, pnp_removal, pdode, &vc->notification_entry); if (!NT_SUCCESS(Status)) WARN("IoRegisterPlugPlayNotification returned %08x\n", Status); vc->devobj = DeviceObject; vc->fileobj = FileObject; devpath2 = *devpath; // The PNP path sometimes begins \\?\ and sometimes \??\. We need to remove this prefix // so we can compare properly if the device is removed. if (devpath->Length > 4 * sizeof(WCHAR) && devpath->Buffer[0] == '\\' && (devpath->Buffer[1] == '\\' || devpath->Buffer[1] == '?') && devpath->Buffer[2] == '?' && devpath->Buffer[3] == '\\') { devpath2.Buffer = &devpath2.Buffer[3]; devpath2.Length -= 3 * sizeof(WCHAR); devpath2.MaximumLength -= 3 * sizeof(WCHAR); } vc->pnp_name.Length = vc->pnp_name.MaximumLength = devpath2.Length; vc->pnp_name.Buffer = ExAllocatePoolWithTag(PagedPool, devpath2.Length, ALLOC_TAG); if (vc->pnp_name.Buffer) RtlCopyMemory(vc->pnp_name.Buffer, devpath2.Buffer, devpath2.Length); else { ERR("out of memory\n"); vc->pnp_name.Length = vc->pnp_name.MaximumLength = 0; } vc->size = length; vc->seeding = sb->flags & BTRFS_SUPERBLOCK_FLAGS_SEEDING ? TRUE : FALSE; vc->disk_num = disk_num; vc->part_num = part_num; vc->had_drive_letter = FALSE; le = pdode->children.Flink; while (le != &pdode->children) { volume_child* vc2 = CONTAINING_RECORD(le, volume_child, list_entry); if (vc2->generation < vc->generation) { if (le == pdode->children.Flink) pdode->num_children = sb->num_devices; InsertHeadList(vc2->list_entry.Blink, &vc->list_entry); inserted = TRUE; break; } le = le->Flink; } if (!inserted) InsertTailList(&pdode->children, &vc->list_entry); pdode->children_loaded++; if (pdode->vde && pdode->vde->mounted_device) { device_extension* Vcb = pdode->vde->mounted_device->DeviceExtension; ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE); le = Vcb->devices.Flink; while (le != &Vcb->devices) { device* dev = CONTAINING_RECORD(le, device, list_entry); if (!dev->devobj && RtlCompareMemory(&dev->devitem.device_uuid, &sb->dev_item.device_uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) { dev->devobj = DeviceObject; dev->disk_num = disk_num; dev->part_num = part_num; init_device(Vcb, dev, FALSE); break; } le = le->Flink; } ExReleaseResourceLite(&Vcb->tree_lock); } if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) { pdode->removable = TRUE; if (pdode->vde && pdode->vde->device) pdode->vde->device->Characteristics |= FILE_REMOVABLE_MEDIA; } if (pdode->num_children == pdode->children_loaded || (pdode->children_loaded == 1 && allow_degraded_mount(&sb->uuid))) { if (pdode->num_children == 1) { Status = remove_drive_letter(mountmgr, devpath); if (!NT_SUCCESS(Status) && Status != STATUS_NOT_FOUND) WARN("remove_drive_letter returned %08x\n", Status); vc->had_drive_letter = NT_SUCCESS(Status); } else { le = pdode->children.Flink; while (le != &pdode->children) { UNICODE_STRING name; vc = CONTAINING_RECORD(le, volume_child, list_entry); name.Length = name.MaximumLength = vc->pnp_name.Length + (3 * sizeof(WCHAR)); name.Buffer = ExAllocatePoolWithTag(PagedPool, name.Length, ALLOC_TAG); if (!name.Buffer) { ERR("out of memory\n"); ExReleaseResourceLite(&pdode->child_lock); ExReleaseResourceLite(&pdo_list_lock); goto fail; } RtlCopyMemory(name.Buffer, L"\\??", 3 * sizeof(WCHAR)); RtlCopyMemory(&name.Buffer[3], vc->pnp_name.Buffer, vc->pnp_name.Length); Status = remove_drive_letter(mountmgr, &name); if (!NT_SUCCESS(Status) && Status != STATUS_NOT_FOUND) WARN("remove_drive_letter returned %08x\n", Status); ExFreePool(name.Buffer); vc->had_drive_letter = NT_SUCCESS(Status); le = le->Flink; } } if ((!new_pdo || !no_pnp) && pdode->vde) { Status = IoSetDeviceInterfaceState(&pdode->vde->bus_name, TRUE); if (!NT_SUCCESS(Status)) WARN("IoSetDeviceInterfaceState returned %08x\n", Status); } } ExReleaseResourceLite(&pdode->child_lock); if (new_pdo) { control_device_extension* cde = master_devobj->DeviceExtension; InsertTailList(&pdo_list, &pdode->list_entry); if (!no_pnp) IoInvalidateDeviceRelations(cde->buspdo, BusRelations); } ExReleaseResourceLite(&pdo_list_lock); if (new_pdo && no_pnp) AddDevice(drvobj, pdo); return; fail: ObDereferenceObject(FileObject); }
void STDCALL look_for_vols(PDRIVER_OBJECT DriverObject, LIST_ENTRY* volumes) { PFILE_OBJECT FileObject; PDEVICE_OBJECT mountmgr; OBJECT_ATTRIBUTES attr; UNICODE_STRING mmdevpath, us; HANDLE h; OBJECT_DIRECTORY_INFORMATION* odi; ULONG odisize; ULONG context; BOOL restart; NTSTATUS Status; LIST_ENTRY* le; static const WCHAR directory[] = L"Directory"; static const WCHAR harddisk[] = L"Harddisk"; RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME); Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &FileObject, &mountmgr); if (!NT_SUCCESS(Status)) { ERR("IoGetDeviceObjectPointer returned %08x\n", Status); return; } RtlInitUnicodeString(&us, devpath); attr.Length = sizeof(attr); attr.RootDirectory = 0; attr.Attributes = OBJ_CASE_INSENSITIVE; attr.ObjectName = &us; attr.SecurityDescriptor = NULL; attr.SecurityQualityOfService = NULL; Status = ZwOpenDirectoryObject(&h, DIRECTORY_TRAVERSE, &attr); if (!NT_SUCCESS(Status)) { ERR("ZwOpenDirectoryObject returned %08x\n", Status); return; } odisize = sizeof(OBJECT_DIRECTORY_INFORMATION) * 16; odi = ExAllocatePoolWithTag(PagedPool, odisize, ALLOC_TAG); if (!odi) { ERR("out of memory\n"); ZwClose(h); return; } restart = TRUE; do { Status = ZwQueryDirectoryObject(h, odi, odisize, FALSE, restart, &context, NULL/*&retlen*/); restart = FALSE; if (!NT_SUCCESS(Status)) { if (Status != STATUS_NO_MORE_ENTRIES) ERR("ZwQueryDirectoryObject returned %08x\n", Status); } else { OBJECT_DIRECTORY_INFORMATION* odi2 = odi; while (odi2->Name.Buffer) { if (odi2->TypeName.Length == wcslen(directory) * sizeof(WCHAR) && RtlCompareMemory(odi2->TypeName.Buffer, directory, odi2->TypeName.Length) == odi2->TypeName.Length && odi2->Name.Length > wcslen(harddisk) * sizeof(WCHAR) && RtlCompareMemory(odi2->Name.Buffer, harddisk, wcslen(harddisk) * sizeof(WCHAR)) == wcslen(harddisk) * sizeof(WCHAR)) { look_in_harddisk_dir(DriverObject, mountmgr, &odi2->Name, volumes); } odi2 = &odi2[1]; } } } while (NT_SUCCESS(Status)); ExFreePool(odi); ZwClose(h); le = volumes->Flink; while (le != volumes) { volume* v = CONTAINING_RECORD(le, volume, list_entry); if (!v->processed) { LIST_ENTRY* le2 = le; volume* mountvol = v; while (le2 != volumes) { volume* v2 = CONTAINING_RECORD(le2, volume, list_entry); if (RtlCompareMemory(&v2->fsuuid, &v->fsuuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) { v2->processed = TRUE; if (v2->devnum < mountvol->devnum) { remove_drive_letter(mountmgr, mountvol); mountvol = v2; } else if (v2->devnum > mountvol->devnum) remove_drive_letter(mountmgr, v2); } le2 = le2->Flink; } add_volume(mountmgr, &mountvol->devpath); } le = le->Flink; } ObDereferenceObject(FileObject); }