Beispiel #1
0
/* bitmap_list_load
 * Get bitmap list from qcow2 image. Actually reads bitmap directory,
 * checks it and convert to bitmap list.
 */
static Qcow2BitmapList *bitmap_list_load(BlockDriverState *bs, uint64_t offset,
                                         uint64_t size, Error **errp)
{
    int ret;
    BDRVQcow2State *s = bs->opaque;
    uint8_t *dir, *dir_end;
    Qcow2BitmapDirEntry *e;
    uint32_t nb_dir_entries = 0;
    Qcow2BitmapList *bm_list = NULL;

    if (size == 0) {
        error_setg(errp, "Requested bitmap directory size is zero");
        return NULL;
    }

    if (size > QCOW2_MAX_BITMAP_DIRECTORY_SIZE) {
        error_setg(errp, "Requested bitmap directory size is too big");
        return NULL;
    }

    dir = g_try_malloc(size);
    if (dir == NULL) {
        error_setg(errp, "Failed to allocate space for bitmap directory");
        return NULL;
    }
    dir_end = dir + size;

    ret = bdrv_pread(bs->file, offset, dir, size);
    if (ret < 0) {
        error_setg_errno(errp, -ret, "Failed to read bitmap directory");
        goto fail;
    }

    bm_list = bitmap_list_new();
    for (e = (Qcow2BitmapDirEntry *)dir;
         e < (Qcow2BitmapDirEntry *)dir_end;
         e = next_dir_entry(e))
    {
        Qcow2Bitmap *bm;

        if ((uint8_t *)(e + 1) > dir_end) {
            goto broken_dir;
        }

        if (++nb_dir_entries > s->nb_bitmaps) {
            error_setg(errp, "More bitmaps found than specified in header"
                       " extension");
            goto fail;
        }
        bitmap_dir_entry_to_cpu(e);

        if ((uint8_t *)next_dir_entry(e) > dir_end) {
            goto broken_dir;
        }

        if (e->extra_data_size != 0) {
            error_setg(errp, "Bitmap extra data is not supported");
            goto fail;
        }

        ret = check_dir_entry(bs, e);
        if (ret < 0) {
            error_setg(errp, "Bitmap '%.*s' doesn't satisfy the constraints",
                       e->name_size, dir_entry_name_field(e));
            goto fail;
        }

        bm = g_new0(Qcow2Bitmap, 1);
        bm->table.offset = e->bitmap_table_offset;
        bm->table.size = e->bitmap_table_size;
        bm->flags = e->flags;
        bm->granularity_bits = e->granularity_bits;
        bm->name = dir_entry_copy_name(e);
        QSIMPLEQ_INSERT_TAIL(bm_list, bm, entry);
    }

    if (nb_dir_entries != s->nb_bitmaps) {
        error_setg(errp, "Less bitmaps found than specified in header"
                         " extension");
        goto fail;
    }

    if ((uint8_t *)e != dir_end) {
        goto broken_dir;
    }

    g_free(dir);
    return bm_list;

broken_dir:
    ret = -EINVAL;
    error_setg(errp, "Broken bitmap directory");

fail:
    g_free(dir);
    bitmap_list_free(bm_list);

    return NULL;
}
Beispiel #2
0
static NTSTATUS query_directory(PIRP Irp) {
    PIO_STACK_LOCATION IrpSp;
    NTSTATUS Status, status2;
    fcb* fcb;
    ccb* ccb;
    file_ref* fileref;
    device_extension* Vcb;
    void* buf;
    UINT8 *curitem, *lastitem;
    LONG length;
    ULONG count;
    BOOL has_wildcard = FALSE, specific_file = FALSE, initial;
    dir_entry de;
    UINT64 newoffset;
    dir_child* dc = NULL;

    TRACE("query directory\n");

    IrpSp = IoGetCurrentIrpStackLocation(Irp);
    fcb = IrpSp->FileObject->FsContext;
    ccb = IrpSp->FileObject->FsContext2;
    fileref = ccb ? ccb->fileref : NULL;

    if (!fileref)
        return STATUS_INVALID_PARAMETER;

    if (!ccb) {
        ERR("ccb was NULL\n");
        return STATUS_INVALID_PARAMETER;
    }

    if (!fcb) {
        ERR("fcb was NULL\n");
        return STATUS_INVALID_PARAMETER;
    }

    if (Irp->RequestorMode == UserMode && !(ccb->access & FILE_LIST_DIRECTORY)) {
        WARN("insufficient privileges\n");
        return STATUS_ACCESS_DENIED;
    }

    Vcb = fcb->Vcb;

    if (!Vcb) {
        ERR("Vcb was NULL\n");
        return STATUS_INVALID_PARAMETER;
    }

    if (fileref->fcb == Vcb->dummy_fcb)
        return STATUS_NO_MORE_FILES;

    if (IrpSp->Flags == 0) {
        TRACE("QD flags: (none)\n");
    } else {
        ULONG flags = IrpSp->Flags;

        TRACE("QD flags:\n");

        if (flags & SL_INDEX_SPECIFIED) {
            TRACE("    SL_INDEX_SPECIFIED\n");
            flags &= ~SL_INDEX_SPECIFIED;
        }

        if (flags & SL_RESTART_SCAN) {
            TRACE("    SL_RESTART_SCAN\n");
            flags &= ~SL_RESTART_SCAN;
        }

        if (flags & SL_RETURN_SINGLE_ENTRY) {
            TRACE("    SL_RETURN_SINGLE_ENTRY\n");
            flags &= ~SL_RETURN_SINGLE_ENTRY;
        }

        if (flags != 0)
            TRACE("    unknown flags: %u\n", flags);
    }

    if (IrpSp->Flags & SL_RESTART_SCAN) {
        ccb->query_dir_offset = 0;

        if (ccb->query_string.Buffer) {
            RtlFreeUnicodeString(&ccb->query_string);
            ccb->query_string.Buffer = NULL;
        }

        ccb->has_wildcard = FALSE;
        ccb->specific_file = FALSE;
    }

    initial = !ccb->query_string.Buffer;

    if (IrpSp->Parameters.QueryDirectory.FileName && IrpSp->Parameters.QueryDirectory.FileName->Length > 1) {
        TRACE("QD filename: %.*S\n", IrpSp->Parameters.QueryDirectory.FileName->Length / sizeof(WCHAR), IrpSp->Parameters.QueryDirectory.FileName->Buffer);

        if (IrpSp->Parameters.QueryDirectory.FileName->Length > sizeof(WCHAR) || IrpSp->Parameters.QueryDirectory.FileName->Buffer[0] != L'*') {
            specific_file = TRUE;

            if (FsRtlDoesNameContainWildCards(IrpSp->Parameters.QueryDirectory.FileName)) {
                has_wildcard = TRUE;
                specific_file = FALSE;
            }
        }

        if (ccb->query_string.Buffer)
            RtlFreeUnicodeString(&ccb->query_string);

        if (has_wildcard)
            RtlUpcaseUnicodeString(&ccb->query_string, IrpSp->Parameters.QueryDirectory.FileName, TRUE);
        else {
            ccb->query_string.Buffer = ExAllocatePoolWithTag(PagedPool, IrpSp->Parameters.QueryDirectory.FileName->Length, ALLOC_TAG);
            if (!ccb->query_string.Buffer) {
                ERR("out of memory\n");
                return STATUS_INSUFFICIENT_RESOURCES;
            }

            ccb->query_string.Length = ccb->query_string.MaximumLength = IrpSp->Parameters.QueryDirectory.FileName->Length;
            RtlCopyMemory(ccb->query_string.Buffer, IrpSp->Parameters.QueryDirectory.FileName->Buffer, IrpSp->Parameters.QueryDirectory.FileName->Length);
        }

        ccb->has_wildcard = has_wildcard;
        ccb->specific_file = specific_file;
    } else {
        has_wildcard = ccb->has_wildcard;
        specific_file = ccb->specific_file;

        if (!(IrpSp->Flags & SL_RESTART_SCAN)) {
            initial = FALSE;

            if (specific_file)
                return STATUS_NO_MORE_FILES;
        }
    }

    if (ccb->query_string.Buffer) {
        TRACE("query string = %.*S\n", ccb->query_string.Length / sizeof(WCHAR), ccb->query_string.Buffer);
    }

    newoffset = ccb->query_dir_offset;

    ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE);

    ExAcquireResourceSharedLite(&fileref->fcb->nonpaged->dir_children_lock, TRUE);

    Status = next_dir_entry(fileref, &newoffset, &de, &dc);

    if (!NT_SUCCESS(Status)) {
        if (Status == STATUS_NO_MORE_FILES && initial)
            Status = STATUS_NO_SUCH_FILE;
        goto end;
    }

    ccb->query_dir_offset = newoffset;

    buf = map_user_buffer(Irp, NormalPagePriority);

    if (Irp->MdlAddress && !buf) {
        ERR("MmGetSystemAddressForMdlSafe returned NULL\n");
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto end;
    }

    length = IrpSp->Parameters.QueryDirectory.Length;

    if (specific_file) {
        BOOL found = FALSE;
        UNICODE_STRING us;
        LIST_ENTRY* le;
        UINT32 hash;
        UINT8 c;

        us.Buffer = NULL;

        if (!ccb->case_sensitive) {
            Status = RtlUpcaseUnicodeString(&us, &ccb->query_string, TRUE);
            if (!NT_SUCCESS(Status)) {
                ERR("RtlUpcaseUnicodeString returned %08x\n", Status);
                goto end;
            }

            hash = calc_crc32c(0xffffffff, (UINT8*)us.Buffer, us.Length);
        } else
            hash = calc_crc32c(0xffffffff, (UINT8*)ccb->query_string.Buffer, ccb->query_string.Length);

        c = hash >> 24;

        if (ccb->case_sensitive) {
            if (fileref->fcb->hash_ptrs[c]) {
                le = fileref->fcb->hash_ptrs[c];
                while (le != &fileref->fcb->dir_children_hash) {
                    dir_child* dc2 = CONTAINING_RECORD(le, dir_child, list_entry_hash);

                    if (dc2->hash == hash) {
                        if (dc2->name.Length == ccb->query_string.Length && RtlCompareMemory(dc2->name.Buffer, ccb->query_string.Buffer, ccb->query_string.Length) == ccb->query_string.Length) {
                            found = TRUE;

                            de.key = dc2->key;
                            de.name = dc2->name;
                            de.type = dc2->type;
                            de.dir_entry_type = DirEntryType_File;
                            de.dc = dc2;

                            break;
                        }
                    } else if (dc2->hash > hash)
                        break;

                    le = le->Flink;
                }
            }
        } else {
            if (fileref->fcb->hash_ptrs_uc[c]) {
                le = fileref->fcb->hash_ptrs_uc[c];
                while (le != &fileref->fcb->dir_children_hash_uc) {
                    dir_child* dc2 = CONTAINING_RECORD(le, dir_child, list_entry_hash_uc);

                    if (dc2->hash_uc == hash) {
                        if (dc2->name_uc.Length == us.Length && RtlCompareMemory(dc2->name_uc.Buffer, us.Buffer, us.Length) == us.Length) {
                            found = TRUE;

                            de.key = dc2->key;
                            de.name = dc2->name;
                            de.type = dc2->type;
                            de.dir_entry_type = DirEntryType_File;
                            de.dc = dc2;

                            break;
                        }
                    } else if (dc2->hash_uc > hash)
                        break;

                    le = le->Flink;
                }
            }
        }

        if (us.Buffer)
            ExFreePool(us.Buffer);

        if (!found) {
            Status = STATUS_NO_SUCH_FILE;
            goto end;
        }
    } else if (has_wildcard) {