Esempio n. 1
0
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;
}
Esempio n. 2
0
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);
}
Esempio n. 3
0
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);
}