Beispiel #1
0
static NTSTATUS query_dir_item(fcb* fcb, ccb* ccb, void* buf, LONG* len, PIRP Irp, dir_entry* de, root* r) {
    PIO_STACK_LOCATION IrpSp;
    LONG needed;
    UINT64 inode;
    INODE_ITEM ii;
    NTSTATUS Status;
    ULONG atts = 0, ealen = 0;
    file_ref* fileref = ccb->fileref;

    IrpSp = IoGetCurrentIrpStackLocation(Irp);

    if (de->key.obj_type == TYPE_ROOT_ITEM) { // subvol
        LIST_ENTRY* le;

        r = NULL;

        le = fcb->Vcb->roots.Flink;
        while (le != &fcb->Vcb->roots) {
            root* subvol = CONTAINING_RECORD(le, root, list_entry);

            if (subvol->id == de->key.obj_id) {
                r = subvol;
                break;
            }

            le = le->Flink;
        }

        if (r && r->parent != fcb->subvol->id)
            r = NULL;

        inode = SUBVOL_ROOT_INODE;
    } else {
        inode = de->key.obj_id;
    }

    if (IrpSp->Parameters.QueryDirectory.FileInformationClass != FileNamesInformation) { // FIXME - object ID and reparse point classes too?
        switch (de->dir_entry_type) {
            case DirEntryType_File:
            {
                if (!r) {
                    LARGE_INTEGER time;

                    ii = fcb->Vcb->dummy_fcb->inode_item;
                    atts = fcb->Vcb->dummy_fcb->atts;
                    ealen = fcb->Vcb->dummy_fcb->ealen;

                    KeQuerySystemTime(&time);
                    win_time_to_unix(time, &ii.otime);
                    ii.st_atime = ii.st_mtime = ii.st_ctime = ii.otime;
                } else {
                    BOOL found = FALSE;

                    if (de->dc && de->dc->fileref && de->dc->fileref->fcb) {
                        ii = de->dc->fileref->fcb->inode_item;
                        atts = de->dc->fileref->fcb->atts;
                        ealen = de->dc->fileref->fcb->ealen;
                        found = TRUE;
                    }

                    if (!found) {
                        KEY searchkey;
                        traverse_ptr tp;

                        searchkey.obj_id = inode;
                        searchkey.obj_type = TYPE_INODE_ITEM;
                        searchkey.offset = 0xffffffffffffffff;

                        Status = find_item(fcb->Vcb, r, &tp, &searchkey, FALSE, Irp);
                        if (!NT_SUCCESS(Status)) {
                            ERR("error - find_item returned %08x\n", Status);
                            return Status;
                        }

                        if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) {
                            ERR("could not find inode item for inode %llx in root %llx\n", inode, r->id);
                            return STATUS_INTERNAL_ERROR;
                        }

                        RtlZeroMemory(&ii, sizeof(INODE_ITEM));

                        if (tp.item->size > 0)
                            RtlCopyMemory(&ii, tp.item->data, min(sizeof(INODE_ITEM), tp.item->size));

                        if (IrpSp->Parameters.QueryDirectory.FileInformationClass == FileBothDirectoryInformation ||
                            IrpSp->Parameters.QueryDirectory.FileInformationClass == FileDirectoryInformation ||
                            IrpSp->Parameters.QueryDirectory.FileInformationClass == FileFullDirectoryInformation ||
                            IrpSp->Parameters.QueryDirectory.FileInformationClass == FileIdBothDirectoryInformation ||
                            IrpSp->Parameters.QueryDirectory.FileInformationClass == FileIdFullDirectoryInformation) {

                            BOOL dotfile = de->name.Length > sizeof(WCHAR) && de->name.Buffer[0] == '.';

                            atts = get_file_attributes(fcb->Vcb, r, inode, de->type, dotfile, FALSE, Irp);
                        }

                        if (IrpSp->Parameters.QueryDirectory.FileInformationClass == FileBothDirectoryInformation ||
                            IrpSp->Parameters.QueryDirectory.FileInformationClass == FileFullDirectoryInformation ||
                            IrpSp->Parameters.QueryDirectory.FileInformationClass == FileIdBothDirectoryInformation ||
                            IrpSp->Parameters.QueryDirectory.FileInformationClass == FileIdFullDirectoryInformation) {
                            ealen = get_ea_len(fcb->Vcb, r, inode, Irp);
                        }
                    }
                }

                break;
            }

            case DirEntryType_Self:
                ii = fcb->inode_item;
                r = fcb->subvol;
                inode = fcb->inode;
                atts = fcb->atts;
                ealen = fcb->ealen;
                break;

            case DirEntryType_Parent:
                if (fileref && fileref->parent) {
                    ii = fileref->parent->fcb->inode_item;
                    r = fileref->parent->fcb->subvol;
                    inode = fileref->parent->fcb->inode;
                    atts = fileref->parent->fcb->atts;
                    ealen = fileref->parent->fcb->ealen;
                } else {
                    ERR("no fileref\n");
                    return STATUS_INTERNAL_ERROR;
                }
                break;
        }

        if (atts == 0)
            atts = FILE_ATTRIBUTE_NORMAL;
    }

    switch (IrpSp->Parameters.QueryDirectory.FileInformationClass) {
        case FileBothDirectoryInformation:
        {
            FILE_BOTH_DIR_INFORMATION* fbdi = buf;

            TRACE("FileBothDirectoryInformation\n");

            needed = sizeof(FILE_BOTH_DIR_INFORMATION) - sizeof(WCHAR) + de->name.Length;

            if (needed > *len) {
                TRACE("buffer overflow - %u > %u\n", needed, *len);
                return STATUS_BUFFER_OVERFLOW;
            }

            fbdi->NextEntryOffset = 0;
            fbdi->FileIndex = 0;
            fbdi->CreationTime.QuadPart = unix_time_to_win(&ii.otime);
            fbdi->LastAccessTime.QuadPart = unix_time_to_win(&ii.st_atime);
            fbdi->LastWriteTime.QuadPart = unix_time_to_win(&ii.st_mtime);
            fbdi->ChangeTime.QuadPart = unix_time_to_win(&ii.st_ctime);
            fbdi->EndOfFile.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_size;

            if (de->type == BTRFS_TYPE_SYMLINK)
                fbdi->AllocationSize.QuadPart = 0;
            else if (atts & FILE_ATTRIBUTE_SPARSE_FILE)
                fbdi->AllocationSize.QuadPart = ii.st_blocks;
            else
                fbdi->AllocationSize.QuadPart = sector_align(ii.st_size, fcb->Vcb->superblock.sector_size);

            fbdi->FileAttributes = atts;
            fbdi->FileNameLength = de->name.Length;
            fbdi->EaSize = (r && atts & FILE_ATTRIBUTE_REPARSE_POINT) ? get_reparse_tag(fcb->Vcb, r, inode, de->type, atts, ccb->lxss, Irp) : ealen;
            fbdi->ShortNameLength = 0;

            RtlCopyMemory(fbdi->FileName, de->name.Buffer, de->name.Length);

            *len -= needed;

            return STATUS_SUCCESS;
        }

        case FileDirectoryInformation:
        {
            FILE_DIRECTORY_INFORMATION* fdi = buf;

            TRACE("FileDirectoryInformation\n");

            needed = sizeof(FILE_DIRECTORY_INFORMATION) - sizeof(WCHAR) + de->name.Length;

            if (needed > *len) {
                TRACE("buffer overflow - %u > %u\n", needed, *len);
                return STATUS_BUFFER_OVERFLOW;
            }

            fdi->NextEntryOffset = 0;
            fdi->FileIndex = 0;
            fdi->CreationTime.QuadPart = unix_time_to_win(&ii.otime);
            fdi->LastAccessTime.QuadPart = unix_time_to_win(&ii.st_atime);
            fdi->LastWriteTime.QuadPart = unix_time_to_win(&ii.st_mtime);
            fdi->ChangeTime.QuadPart = unix_time_to_win(&ii.st_ctime);
            fdi->EndOfFile.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_size;

            if (de->type == BTRFS_TYPE_SYMLINK)
                fdi->AllocationSize.QuadPart = 0;
            else if (atts & FILE_ATTRIBUTE_SPARSE_FILE)
                fdi->AllocationSize.QuadPart = ii.st_blocks;
            else
                fdi->AllocationSize.QuadPart = sector_align(ii.st_size, fcb->Vcb->superblock.sector_size);

            fdi->FileAttributes = atts;
            fdi->FileNameLength = de->name.Length;

            RtlCopyMemory(fdi->FileName, de->name.Buffer, de->name.Length);

            *len -= needed;

            return STATUS_SUCCESS;
        }

        case FileFullDirectoryInformation:
        {
            FILE_FULL_DIR_INFORMATION* ffdi = buf;

            TRACE("FileFullDirectoryInformation\n");

            needed = sizeof(FILE_FULL_DIR_INFORMATION) - sizeof(WCHAR) + de->name.Length;

            if (needed > *len) {
                TRACE("buffer overflow - %u > %u\n", needed, *len);
                return STATUS_BUFFER_OVERFLOW;
            }

            ffdi->NextEntryOffset = 0;
            ffdi->FileIndex = 0;
            ffdi->CreationTime.QuadPart = unix_time_to_win(&ii.otime);
            ffdi->LastAccessTime.QuadPart = unix_time_to_win(&ii.st_atime);
            ffdi->LastWriteTime.QuadPart = unix_time_to_win(&ii.st_mtime);
            ffdi->ChangeTime.QuadPart = unix_time_to_win(&ii.st_ctime);
            ffdi->EndOfFile.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_size;

            if (de->type == BTRFS_TYPE_SYMLINK)
                ffdi->AllocationSize.QuadPart = 0;
            else if (atts & FILE_ATTRIBUTE_SPARSE_FILE)
                ffdi->AllocationSize.QuadPart = ii.st_blocks;
            else
                ffdi->AllocationSize.QuadPart = sector_align(ii.st_size, fcb->Vcb->superblock.sector_size);

            ffdi->FileAttributes = atts;
            ffdi->FileNameLength = de->name.Length;
            ffdi->EaSize = (r && atts & FILE_ATTRIBUTE_REPARSE_POINT) ? get_reparse_tag(fcb->Vcb, r, inode, de->type, atts, ccb->lxss, Irp) : ealen;

            RtlCopyMemory(ffdi->FileName, de->name.Buffer, de->name.Length);

            *len -= needed;

            return STATUS_SUCCESS;
        }

        case FileIdBothDirectoryInformation:
        {
            FILE_ID_BOTH_DIR_INFORMATION* fibdi = buf;

            TRACE("FileIdBothDirectoryInformation\n");

            needed = sizeof(FILE_ID_BOTH_DIR_INFORMATION) - sizeof(WCHAR) + de->name.Length;

            if (needed > *len) {
                TRACE("buffer overflow - %u > %u\n", needed, *len);
                return STATUS_BUFFER_OVERFLOW;
            }

            fibdi->NextEntryOffset = 0;
            fibdi->FileIndex = 0;
            fibdi->CreationTime.QuadPart = unix_time_to_win(&ii.otime);
            fibdi->LastAccessTime.QuadPart = unix_time_to_win(&ii.st_atime);
            fibdi->LastWriteTime.QuadPart = unix_time_to_win(&ii.st_mtime);
            fibdi->ChangeTime.QuadPart = unix_time_to_win(&ii.st_ctime);
            fibdi->EndOfFile.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_size;

            if (de->type == BTRFS_TYPE_SYMLINK)
                fibdi->AllocationSize.QuadPart = 0;
            else if (atts & FILE_ATTRIBUTE_SPARSE_FILE)
                fibdi->AllocationSize.QuadPart = ii.st_blocks;
            else
                fibdi->AllocationSize.QuadPart = sector_align(ii.st_size, fcb->Vcb->superblock.sector_size);

            fibdi->FileAttributes = atts;
            fibdi->FileNameLength = de->name.Length;
            fibdi->EaSize = (r && atts & FILE_ATTRIBUTE_REPARSE_POINT) ? get_reparse_tag(fcb->Vcb, r, inode, de->type, atts, ccb->lxss, Irp) : ealen;
            fibdi->ShortNameLength = 0;
            fibdi->FileId.QuadPart = r ? make_file_id(r, inode) : make_file_id(fcb->Vcb->dummy_fcb->subvol, fcb->Vcb->dummy_fcb->inode);

            RtlCopyMemory(fibdi->FileName, de->name.Buffer, de->name.Length);

            *len -= needed;

            return STATUS_SUCCESS;
        }

        case FileIdFullDirectoryInformation:
        {
            FILE_ID_FULL_DIR_INFORMATION* fifdi = buf;

            TRACE("FileIdFullDirectoryInformation\n");

            needed = sizeof(FILE_ID_FULL_DIR_INFORMATION) - sizeof(WCHAR) + de->name.Length;

            if (needed > *len) {
                TRACE("buffer overflow - %u > %u\n", needed, *len);
                return STATUS_BUFFER_OVERFLOW;
            }

            fifdi->NextEntryOffset = 0;
            fifdi->FileIndex = 0;
            fifdi->CreationTime.QuadPart = unix_time_to_win(&ii.otime);
            fifdi->LastAccessTime.QuadPart = unix_time_to_win(&ii.st_atime);
            fifdi->LastWriteTime.QuadPart = unix_time_to_win(&ii.st_mtime);
            fifdi->ChangeTime.QuadPart = unix_time_to_win(&ii.st_ctime);
            fifdi->EndOfFile.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_size;

            if (de->type == BTRFS_TYPE_SYMLINK)
                fifdi->AllocationSize.QuadPart = 0;
            else if (atts & FILE_ATTRIBUTE_SPARSE_FILE)
                fifdi->AllocationSize.QuadPart = ii.st_blocks;
            else
                fifdi->AllocationSize.QuadPart = sector_align(ii.st_size, fcb->Vcb->superblock.sector_size);

            fifdi->FileAttributes = atts;
            fifdi->FileNameLength = de->name.Length;
            fifdi->EaSize = (r && atts & FILE_ATTRIBUTE_REPARSE_POINT) ? get_reparse_tag(fcb->Vcb, r, inode, de->type, atts, ccb->lxss, Irp) : ealen;
            fifdi->FileId.QuadPart = r ? make_file_id(r, inode) : make_file_id(fcb->Vcb->dummy_fcb->subvol, fcb->Vcb->dummy_fcb->inode);

            RtlCopyMemory(fifdi->FileName, de->name.Buffer, de->name.Length);

            *len -= needed;

            return STATUS_SUCCESS;
        }

        case FileNamesInformation:
        {
            FILE_NAMES_INFORMATION* fni = buf;

            TRACE("FileNamesInformation\n");

            needed = sizeof(FILE_NAMES_INFORMATION) - sizeof(WCHAR) + de->name.Length;

            if (needed > *len) {
                TRACE("buffer overflow - %u > %u\n", needed, *len);
                return STATUS_BUFFER_OVERFLOW;
            }

            fni->NextEntryOffset = 0;
            fni->FileIndex = 0;
            fni->FileNameLength = de->name.Length;

            RtlCopyMemory(fni->FileName, de->name.Buffer, de->name.Length);

            *len -= needed;

            return STATUS_SUCCESS;
        }

        case FileObjectIdInformation:
            FIXME("STUB: FileObjectIdInformation\n");
            return STATUS_NOT_IMPLEMENTED;

        case FileQuotaInformation:
            FIXME("STUB: FileQuotaInformation\n");
            return STATUS_NOT_IMPLEMENTED;

        case FileReparsePointInformation:
            FIXME("STUB: FileReparsePointInformation\n");
            return STATUS_NOT_IMPLEMENTED;

        default:
            WARN("Unknown FileInformationClass %u\n", IrpSp->Parameters.QueryDirectory.FileInformationClass);
            return STATUS_NOT_IMPLEMENTED;
    }

    return STATUS_NO_MORE_FILES;
}
Beispiel #2
0
static void STDCALL test_vol(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT mountmgr, PUNICODE_STRING pardir, PUNICODE_STRING us, BOOL part0, LIST_ENTRY* volumes) {
    KEVENT Event;
    PIRP Irp;
    IO_STATUS_BLOCK IoStatusBlock;
    NTSTATUS Status;
    PFILE_OBJECT FileObject;
    PDEVICE_OBJECT DeviceObject;
    LARGE_INTEGER Offset;
    ULONG toread;
    UINT8* data;
    UNICODE_STRING us2;
    BOOL added_entry = FALSE;
    UINT32 sector_size;
    
    TRACE("%.*S\n", us->Length / sizeof(WCHAR), us->Buffer);
    
    us2.Length = pardir->Length + sizeof(WCHAR) + us->Length;
    us2.MaximumLength = us2.Length;
    us2.Buffer = ExAllocatePoolWithTag(PagedPool, us2.Length, ALLOC_TAG);
    if (!us2.Buffer) {
        ERR("out of memory\n");
        return;
    }
    
    RtlCopyMemory(us2.Buffer, pardir->Buffer, pardir->Length);
    us2.Buffer[pardir->Length / sizeof(WCHAR)] = '\\';
    RtlCopyMemory(&us2.Buffer[(pardir->Length / sizeof(WCHAR))+1], us->Buffer, us->Length);
    
    TRACE("%.*S\n", us2.Length / sizeof(WCHAR), us2.Buffer);
    
    Status = IoGetDeviceObjectPointer(&us2, FILE_READ_ATTRIBUTES, &FileObject, &DeviceObject);
    if (!NT_SUCCESS(Status)) {
        ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
        goto exit;
    }

    sector_size = DeviceObject->SectorSize;
    
    if (sector_size == 0) {
        DISK_GEOMETRY geometry;
        IO_STATUS_BLOCK iosb;
        
        Status = dev_ioctl(DeviceObject, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
                        &geometry, sizeof(DISK_GEOMETRY), TRUE, &iosb);
        
        if (!NT_SUCCESS(Status)) {
            ERR("%.*S had a sector size of 0, and IOCTL_DISK_GET_DRIVE_GEOMETRY returned %08x\n",
                us2.Length / sizeof(WCHAR), us2.Buffer, Status);
            goto exit;
        }
        
        if (iosb.Information < sizeof(DISK_GEOMETRY)) {
            ERR("%.*S: IOCTL_DISK_GET_DRIVE_GEOMETRY returned %u bytes, expected %u\n",
                us2.Length / sizeof(WCHAR), us2.Buffer, iosb.Information, sizeof(DISK_GEOMETRY));
        }
        
        sector_size = geometry.BytesPerSector;
        
        if (sector_size == 0) {
            ERR("%.*S had a sector size of 0\n", us2.Length / sizeof(WCHAR), us2.Buffer);
            goto exit;
        }
    }
    
    KeInitializeEvent(&Event, NotificationEvent, FALSE);

    Offset.QuadPart = superblock_addrs[0];
    
    toread = sector_align(sizeof(superblock), sector_size);
    data = ExAllocatePoolWithTag(NonPagedPool, toread, ALLOC_TAG);
    if (!data) {
        ERR("out of memory\n");
        goto deref;
    }

    Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, DeviceObject, data, toread, &Offset, &Event, &IoStatusBlock);
    
    if (!Irp) {
        ERR("IoBuildSynchronousFsdRequest failed\n");
        goto deref;
    }

    Status = IoCallDriver(DeviceObject, Irp);

    if (Status == STATUS_PENDING) {
        KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
        Status = IoStatusBlock.Status;
    }

    if (NT_SUCCESS(Status) && IoStatusBlock.Information > 0 && ((superblock*)data)->magic == BTRFS_MAGIC) {
        int i;
        GET_LENGTH_INFORMATION gli;
        superblock* sb = (superblock*)data;
        volume* v = ExAllocatePoolWithTag(PagedPool, sizeof(volume), ALLOC_TAG);
        
        if (!v) {
            ERR("out of memory\n");
            goto deref;
        }
        
        Status = dev_ioctl(DeviceObject, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0,
                           &gli, sizeof(gli), TRUE, NULL);
        if (!NT_SUCCESS(Status)) {
            ERR("error reading length information: %08x\n", Status);
            goto deref;
        }
        
        if (part0) {
            UNICODE_STRING us3;
            
            Status = create_part0(DriverObject, DeviceObject, pardir, &us3, &sb->dev_item.device_uuid);
            
            if (!NT_SUCCESS(Status)) {
                ERR("create_part0 returned %08x\n", Status);
                goto deref;
            }
            
            ExFreePool(us2.Buffer);
            us2 = us3;
        }
        
        RtlCopyMemory(&v->fsuuid, &sb->uuid, sizeof(BTRFS_UUID));
        RtlCopyMemory(&v->devuuid, &sb->dev_item.device_uuid, sizeof(BTRFS_UUID));
        v->devnum = sb->dev_item.dev_id;
        v->devpath = us2;
        v->processed = FALSE;
        v->length = gli.Length.QuadPart;
        v->gen1 = sb->generation;
        v->gen2 = 0;
        InsertTailList(volumes, &v->list_entry);
        
        i = 1;
        while (superblock_addrs[i] != 0 && superblock_addrs[i] + toread <= v->length) {
            KeInitializeEvent(&Event, NotificationEvent, FALSE);
            
            Offset.QuadPart = superblock_addrs[i];
            
            Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, DeviceObject, data, toread, &Offset, &Event, &IoStatusBlock);
            
            if (!Irp) {
                ERR("IoBuildSynchronousFsdRequest failed\n");
                goto deref;
            }

            Status = IoCallDriver(DeviceObject, Irp);

            if (Status == STATUS_PENDING) {
                KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
                Status = IoStatusBlock.Status;
            }
            
            if (NT_SUCCESS(Status)) {
                UINT32 crc32 = ~calc_crc32c(0xffffffff, (UINT8*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum));
                
                if (crc32 != *((UINT32*)sb->checksum))
                    WARN("superblock %u CRC error\n", i);
                else if (sb->generation > v->gen1) {
                    v->gen2 = v->gen1;
                    v->gen1 = sb->generation;
                }
            } else {
                ERR("got error %08x while reading superblock %u\n", Status, i);
            }
            
            i++;
        }
        
        TRACE("volume found\n");
        TRACE("gen1 = %llx, gen2 = %llx\n", v->gen1, v->gen2);
        TRACE("FS uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
              v->fsuuid.uuid[0], v->fsuuid.uuid[1], v->fsuuid.uuid[2], v->fsuuid.uuid[3], v->fsuuid.uuid[4], v->fsuuid.uuid[5], v->fsuuid.uuid[6], v->fsuuid.uuid[7],
              v->fsuuid.uuid[8], v->fsuuid.uuid[9], v->fsuuid.uuid[10], v->fsuuid.uuid[11], v->fsuuid.uuid[12], v->fsuuid.uuid[13], v->fsuuid.uuid[14], v->fsuuid.uuid[15]);
        TRACE("device uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
              v->devuuid.uuid[0], v->devuuid.uuid[1], v->devuuid.uuid[2], v->devuuid.uuid[3], v->devuuid.uuid[4], v->devuuid.uuid[5], v->devuuid.uuid[6], v->devuuid.uuid[7],
              v->devuuid.uuid[8], v->devuuid.uuid[9], v->devuuid.uuid[10], v->devuuid.uuid[11], v->devuuid.uuid[12], v->devuuid.uuid[13], v->devuuid.uuid[14], v->devuuid.uuid[15]);
        TRACE("device number %llx\n", v->devnum);

        added_entry = TRUE;
    }
    
deref:
    ExFreePool(data);
    ObDereferenceObject(FileObject);
    
exit:
    if (!added_entry)
        ExFreePool(us2.Buffer);
}
Beispiel #3
0
static void test_vol(PDEVICE_OBJECT mountmgr, PDEVICE_OBJECT DeviceObject, PUNICODE_STRING devpath,
                     DWORD disk_num, DWORD part_num, UINT64 length) {
    NTSTATUS Status;
    ULONG toread;
    UINT8* data = NULL;
    UINT32 sector_size;

    TRACE("%.*S\n", devpath->Length / sizeof(WCHAR), devpath->Buffer);

    sector_size = DeviceObject->SectorSize;

    if (sector_size == 0) {
        DISK_GEOMETRY geometry;
        IO_STATUS_BLOCK iosb;

        Status = dev_ioctl(DeviceObject, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
                           &geometry, sizeof(DISK_GEOMETRY), TRUE, &iosb);

        if (!NT_SUCCESS(Status)) {
            ERR("%.*S had a sector size of 0, and IOCTL_DISK_GET_DRIVE_GEOMETRY returned %08x\n",
                devpath->Length / sizeof(WCHAR), devpath->Buffer, Status);
            goto deref;
        }

        if (iosb.Information < sizeof(DISK_GEOMETRY)) {
            ERR("%.*S: IOCTL_DISK_GET_DRIVE_GEOMETRY returned %u bytes, expected %u\n",
                devpath->Length / sizeof(WCHAR), devpath->Buffer, iosb.Information, sizeof(DISK_GEOMETRY));
        }

        sector_size = geometry.BytesPerSector;

        if (sector_size == 0) {
            ERR("%.*S had a sector size of 0\n", devpath->Length / sizeof(WCHAR), devpath->Buffer);
            goto deref;
        }
    }

    toread = (ULONG)sector_align(sizeof(superblock), sector_size);
    data = ExAllocatePoolWithTag(NonPagedPool, toread, ALLOC_TAG);
    if (!data) {
        ERR("out of memory\n");
        goto deref;
    }

    Status = sync_read_phys(DeviceObject, superblock_addrs[0], toread, data, TRUE);

    if (NT_SUCCESS(Status) && ((superblock*)data)->magic == BTRFS_MAGIC) {
        superblock* sb = (superblock*)data;
        UINT32 crc32 = ~calc_crc32c(0xffffffff, (UINT8*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum));

        if (crc32 != *((UINT32*)sb->checksum))
            ERR("checksum error on superblock\n");
        else {
            TRACE("volume found\n");

            if (length >= superblock_addrs[1] + toread) {
                ULONG i = 1;

                superblock* sb2 = ExAllocatePoolWithTag(NonPagedPool, toread, ALLOC_TAG);
                if (!sb2) {
                    ERR("out of memory\n");
                    goto deref;
                }

                while (superblock_addrs[i] > 0 && length >= superblock_addrs[i] + toread) {
                    Status = sync_read_phys(DeviceObject, superblock_addrs[i], toread, (PUCHAR)sb2, TRUE);

                    if (NT_SUCCESS(Status) && sb2->magic == BTRFS_MAGIC) {
                        crc32 = ~calc_crc32c(0xffffffff, (UINT8*)&sb2->uuid, (ULONG)sizeof(superblock) - sizeof(sb2->checksum));

                        if (crc32 == *((UINT32*)sb2->checksum) && sb2->generation > sb->generation)
                            RtlCopyMemory(sb, sb2, toread);
                    }

                    i++;
                }

                ExFreePool(sb2);
            }

            if (!fs_ignored(&sb->uuid)) {
                DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
                add_volume_device(sb, mountmgr, devpath, length, disk_num, part_num);
            }
        }
    }

deref:
    if (data)
        ExFreePool(data);
}
Beispiel #4
0
NTSTATUS STDCALL read_file(device_extension* Vcb, root* subvol, UINT64 inode, UINT8* data, UINT64 start, UINT64 length, ULONG* pbr) {
    KEY searchkey;
    NTSTATUS Status;
    traverse_ptr tp, next_tp;
    EXTENT_DATA* ed;
    UINT64 bytes_read = 0;
    
    TRACE("(%p, %llx, %llx, %p, %llx, %llx, %p)\n", Vcb, subvol->id, inode, data, start, length, pbr);
    
    if (pbr)
        *pbr = 0;
    
    searchkey.obj_id = inode;
    searchkey.obj_type = TYPE_EXTENT_DATA;
    searchkey.offset = start;

    Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE);
    if (!NT_SUCCESS(Status)) {
        ERR("error - find_item returned %08x\n", Status);
        goto exit;
    }

    if (tp.item->key.obj_id < searchkey.obj_id || tp.item->key.obj_type < searchkey.obj_type) {
        if (find_next_item(Vcb, &tp, &next_tp, FALSE)) {
            tp = next_tp;
            
            TRACE("moving on to %llx,%x,%llx\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
        }
    }
    
    if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) {
        ERR("couldn't find EXTENT_DATA for inode %llx in subvol %llx\n", searchkey.obj_id, subvol->id);
        Status = STATUS_INTERNAL_ERROR;
        goto exit;
    }
    
    if (tp.item->key.offset > start) {
        ERR("first EXTENT_DATA was after offset\n");
        Status = STATUS_INTERNAL_ERROR;
        goto exit;
    }
    
//     while (TRUE) {
//         BOOL foundnext = find_next_item(Vcb, &tp, &next_tp, NULL, FALSE);
//         
//         if (!foundnext || next_tp.item->key.obj_id != inode ||
//             next_tp.item->key.obj_type != TYPE_EXTENT_DATA || next_tp.item->key.offset > start) {
//             if (foundnext)
//                 free_traverse_ptr(&next_tp);
//             
//             break;
//         }
//         
//         free_traverse_ptr(&tp);
//         tp = next_tp;
//     }
    
    do {
        UINT64 len;
        EXTENT_DATA2* ed2;
        
        ed = (EXTENT_DATA*)tp.item->data;
        
        if (tp.item->size < sizeof(EXTENT_DATA)) {
            ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(EXTENT_DATA));
            Status = STATUS_INTERNAL_ERROR;
            goto exit;
        }
        
        if ((ed->type == EXTENT_TYPE_REGULAR || ed->type == EXTENT_TYPE_PREALLOC) && tp.item->size < sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2)) {
            ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2));
            Status = STATUS_INTERNAL_ERROR;
            goto exit;
        }
        
        ed2 = (EXTENT_DATA2*)ed->data;
        
        len = ed->type == EXTENT_TYPE_INLINE ? ed->decoded_size : ed2->num_bytes;
        
        if (tp.item->key.offset + len < start) {
            ERR("Tried to read beyond end of file\n");
            Status = STATUS_END_OF_FILE;
            goto exit;
        }
        
        if (ed->compression != BTRFS_COMPRESSION_NONE) {
            FIXME("FIXME - compression not yet supported\n");
            Status = STATUS_NOT_IMPLEMENTED;
            goto exit;
        }
        
        if (ed->encryption != BTRFS_ENCRYPTION_NONE) {
            WARN("Encryption not supported\n");
            Status = STATUS_NOT_IMPLEMENTED;
            goto exit;
        }
        
        if (ed->encoding != BTRFS_ENCODING_NONE) {
            WARN("Other encodings not supported\n");
            Status = STATUS_NOT_IMPLEMENTED;
            goto exit;
        }
        
        switch (ed->type) {
            case EXTENT_TYPE_INLINE:
            {
                UINT64 off = start + bytes_read - tp.item->key.offset;
                UINT64 read = len - off;
                
                if (read > length) read = length;
                
                RtlCopyMemory(data + bytes_read, &ed->data[off], read);
                
                bytes_read += read;
                length -= read;
                break;
            }
            
            case EXTENT_TYPE_REGULAR:
            {
                UINT64 off = start + bytes_read - tp.item->key.offset;
                UINT32 to_read, read;
                UINT8* buf;
                
                read = len - off;
                if (read > length) read = length;
                
                if (ed2->address == 0) {
                    RtlZeroMemory(data + bytes_read, read);
                } else {
                    to_read = sector_align(read, Vcb->superblock.sector_size);
                    
                    buf = ExAllocatePoolWithTag(PagedPool, to_read, ALLOC_TAG);
                    
                    if (!buf) {
                        ERR("out of memory\n");
                        Status = STATUS_INSUFFICIENT_RESOURCES;
                        goto exit;
                    }
                    
                    // FIXME - load checksums
                    
                    Status = read_data(Vcb, ed2->address + ed2->offset + off, to_read, buf);
                    if (!NT_SUCCESS(Status)) {
                        ERR("read_data returned %08x\n", Status);
                        ExFreePool(buf);
                        goto exit;
                    }
                    
                    RtlCopyMemory(data + bytes_read, buf, read);
                    
                    ExFreePool(buf);
                }
                
                bytes_read += read;
                length -= read;
                
                break;
            }
           
            case EXTENT_TYPE_PREALLOC:
            {
                UINT64 off = start + bytes_read - tp.item->key.offset;
                UINT32 read = len - off;
                
                if (read > length) read = length;

                RtlZeroMemory(data + bytes_read, read);

                bytes_read += read;
                length -= read;
                
                break;
            }
                
            default:
                WARN("Unsupported extent data type %u\n", ed->type);
                Status = STATUS_NOT_IMPLEMENTED;
                goto exit;
        }
        
        if (length > 0) {
            BOOL foundnext = find_next_item(Vcb, &tp, &next_tp, FALSE);
            
            if (!foundnext)
                break;
            else if (next_tp.item->key.obj_id != inode ||
                next_tp.item->key.obj_type != TYPE_EXTENT_DATA ||
                next_tp.item->key.offset != tp.item->key.offset + len
            ) {
                break;
            } else {
                TRACE("found next key (%llx,%x,%llx)\n", next_tp.item->key.obj_id, next_tp.item->key.obj_type, next_tp.item->key.offset);
                
                tp = next_tp;
            }
        } else
            break;
    } while (TRUE);
    
    Status = STATUS_SUCCESS;
    if (pbr)
        *pbr = bytes_read;
    
exit:
    return Status;
}