qemu/block/cloop.c
<<
>>
Prefs
   1/*
   2 * QEMU Block driver for CLOOP images
   3 *
   4 * Copyright (c) 2004 Johannes E. Schindelin
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24#include "qemu/osdep.h"
  25#include "qapi/error.h"
  26#include "qemu-common.h"
  27#include "block/block_int.h"
  28#include "qemu/module.h"
  29#include <zlib.h>
  30
  31/* Maximum compressed block size */
  32#define MAX_BLOCK_SIZE (64 * 1024 * 1024)
  33
  34typedef struct BDRVCloopState {
  35    CoMutex lock;
  36    uint32_t block_size;
  37    uint32_t n_blocks;
  38    uint64_t *offsets;
  39    uint32_t sectors_per_block;
  40    uint32_t current_block;
  41    uint8_t *compressed_block;
  42    uint8_t *uncompressed_block;
  43    z_stream zstream;
  44} BDRVCloopState;
  45
  46static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename)
  47{
  48    const char *magic_version_2_0 = "#!/bin/sh\n"
  49        "#V2.0 Format\n"
  50        "modprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n";
  51    int length = strlen(magic_version_2_0);
  52    if (length > buf_size) {
  53        length = buf_size;
  54    }
  55    if (!memcmp(magic_version_2_0, buf, length)) {
  56        return 2;
  57    }
  58    return 0;
  59}
  60
  61static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
  62                      Error **errp)
  63{
  64    BDRVCloopState *s = bs->opaque;
  65    uint32_t offsets_size, max_compressed_block_size = 1, i;
  66    int ret;
  67
  68    bs->read_only = 1;
  69
  70    /* read header */
  71    ret = bdrv_pread(bs->file->bs, 128, &s->block_size, 4);
  72    if (ret < 0) {
  73        return ret;
  74    }
  75    s->block_size = be32_to_cpu(s->block_size);
  76    if (s->block_size % 512) {
  77        error_setg(errp, "block_size %" PRIu32 " must be a multiple of 512",
  78                   s->block_size);
  79        return -EINVAL;
  80    }
  81    if (s->block_size == 0) {
  82        error_setg(errp, "block_size cannot be zero");
  83        return -EINVAL;
  84    }
  85
  86    /* cloop's create_compressed_fs.c warns about block sizes beyond 256 KB but
  87     * we can accept more.  Prevent ridiculous values like 4 GB - 1 since we
  88     * need a buffer this big.
  89     */
  90    if (s->block_size > MAX_BLOCK_SIZE) {
  91        error_setg(errp, "block_size %" PRIu32 " must be %u MB or less",
  92                   s->block_size,
  93                   MAX_BLOCK_SIZE / (1024 * 1024));
  94        return -EINVAL;
  95    }
  96
  97    ret = bdrv_pread(bs->file->bs, 128 + 4, &s->n_blocks, 4);
  98    if (ret < 0) {
  99        return ret;
 100    }
 101    s->n_blocks = be32_to_cpu(s->n_blocks);
 102
 103    /* read offsets */
 104    if (s->n_blocks > (UINT32_MAX - 1) / sizeof(uint64_t)) {
 105        /* Prevent integer overflow */
 106        error_setg(errp, "n_blocks %" PRIu32 " must be %zu or less",
 107                   s->n_blocks,
 108                   (UINT32_MAX - 1) / sizeof(uint64_t));
 109        return -EINVAL;
 110    }
 111    offsets_size = (s->n_blocks + 1) * sizeof(uint64_t);
 112    if (offsets_size > 512 * 1024 * 1024) {
 113        /* Prevent ridiculous offsets_size which causes memory allocation to
 114         * fail or overflows bdrv_pread() size.  In practice the 512 MB
 115         * offsets[] limit supports 16 TB images at 256 KB block size.
 116         */
 117        error_setg(errp, "image requires too many offsets, "
 118                   "try increasing block size");
 119        return -EINVAL;
 120    }
 121
 122    s->offsets = g_try_malloc(offsets_size);
 123    if (s->offsets == NULL) {
 124        error_setg(errp, "Could not allocate offsets table");
 125        return -ENOMEM;
 126    }
 127
 128    ret = bdrv_pread(bs->file->bs, 128 + 4 + 4, s->offsets, offsets_size);
 129    if (ret < 0) {
 130        goto fail;
 131    }
 132
 133    for (i = 0; i < s->n_blocks + 1; i++) {
 134        uint64_t size;
 135
 136        s->offsets[i] = be64_to_cpu(s->offsets[i]);
 137        if (i == 0) {
 138            continue;
 139        }
 140
 141        if (s->offsets[i] < s->offsets[i - 1]) {
 142            error_setg(errp, "offsets not monotonically increasing at "
 143                       "index %" PRIu32 ", image file is corrupt", i);
 144            ret = -EINVAL;
 145            goto fail;
 146        }
 147
 148        size = s->offsets[i] - s->offsets[i - 1];
 149
 150        /* Compressed blocks should be smaller than the uncompressed block size
 151         * but maybe compression performed poorly so the compressed block is
 152         * actually bigger.  Clamp down on unrealistic values to prevent
 153         * ridiculous s->compressed_block allocation.
 154         */
 155        if (size > 2 * MAX_BLOCK_SIZE) {
 156            error_setg(errp, "invalid compressed block size at index %" PRIu32
 157                       ", image file is corrupt", i);
 158            ret = -EINVAL;
 159            goto fail;
 160        }
 161
 162        if (size > max_compressed_block_size) {
 163            max_compressed_block_size = size;
 164        }
 165    }
 166
 167    /* initialize zlib engine */
 168    s->compressed_block = g_try_malloc(max_compressed_block_size + 1);
 169    if (s->compressed_block == NULL) {
 170        error_setg(errp, "Could not allocate compressed_block");
 171        ret = -ENOMEM;
 172        goto fail;
 173    }
 174
 175    s->uncompressed_block = g_try_malloc(s->block_size);
 176    if (s->uncompressed_block == NULL) {
 177        error_setg(errp, "Could not allocate uncompressed_block");
 178        ret = -ENOMEM;
 179        goto fail;
 180    }
 181
 182    if (inflateInit(&s->zstream) != Z_OK) {
 183        ret = -EINVAL;
 184        goto fail;
 185    }
 186    s->current_block = s->n_blocks;
 187
 188    s->sectors_per_block = s->block_size/512;
 189    bs->total_sectors = s->n_blocks * s->sectors_per_block;
 190    qemu_co_mutex_init(&s->lock);
 191    return 0;
 192
 193fail:
 194    g_free(s->offsets);
 195    g_free(s->compressed_block);
 196    g_free(s->uncompressed_block);
 197    return ret;
 198}
 199
 200static inline int cloop_read_block(BlockDriverState *bs, int block_num)
 201{
 202    BDRVCloopState *s = bs->opaque;
 203
 204    if (s->current_block != block_num) {
 205        int ret;
 206        uint32_t bytes = s->offsets[block_num + 1] - s->offsets[block_num];
 207
 208        ret = bdrv_pread(bs->file->bs, s->offsets[block_num],
 209                         s->compressed_block, bytes);
 210        if (ret != bytes) {
 211            return -1;
 212        }
 213
 214        s->zstream.next_in = s->compressed_block;
 215        s->zstream.avail_in = bytes;
 216        s->zstream.next_out = s->uncompressed_block;
 217        s->zstream.avail_out = s->block_size;
 218        ret = inflateReset(&s->zstream);
 219        if (ret != Z_OK) {
 220            return -1;
 221        }
 222        ret = inflate(&s->zstream, Z_FINISH);
 223        if (ret != Z_STREAM_END || s->zstream.total_out != s->block_size) {
 224            return -1;
 225        }
 226
 227        s->current_block = block_num;
 228    }
 229    return 0;
 230}
 231
 232static int cloop_read(BlockDriverState *bs, int64_t sector_num,
 233                    uint8_t *buf, int nb_sectors)
 234{
 235    BDRVCloopState *s = bs->opaque;
 236    int i;
 237
 238    for (i = 0; i < nb_sectors; i++) {
 239        uint32_t sector_offset_in_block =
 240            ((sector_num + i) % s->sectors_per_block),
 241            block_num = (sector_num + i) / s->sectors_per_block;
 242        if (cloop_read_block(bs, block_num) != 0) {
 243            return -1;
 244        }
 245        memcpy(buf + i * 512,
 246            s->uncompressed_block + sector_offset_in_block * 512, 512);
 247    }
 248    return 0;
 249}
 250
 251static coroutine_fn int cloop_co_read(BlockDriverState *bs, int64_t sector_num,
 252                                      uint8_t *buf, int nb_sectors)
 253{
 254    int ret;
 255    BDRVCloopState *s = bs->opaque;
 256    qemu_co_mutex_lock(&s->lock);
 257    ret = cloop_read(bs, sector_num, buf, nb_sectors);
 258    qemu_co_mutex_unlock(&s->lock);
 259    return ret;
 260}
 261
 262static void cloop_close(BlockDriverState *bs)
 263{
 264    BDRVCloopState *s = bs->opaque;
 265    g_free(s->offsets);
 266    g_free(s->compressed_block);
 267    g_free(s->uncompressed_block);
 268    inflateEnd(&s->zstream);
 269}
 270
 271static BlockDriver bdrv_cloop = {
 272    .format_name    = "cloop",
 273    .instance_size  = sizeof(BDRVCloopState),
 274    .bdrv_probe     = cloop_probe,
 275    .bdrv_open      = cloop_open,
 276    .bdrv_read      = cloop_co_read,
 277    .bdrv_close     = cloop_close,
 278};
 279
 280static void bdrv_cloop_init(void)
 281{
 282    bdrv_register(&bdrv_cloop);
 283}
 284
 285block_init(bdrv_cloop_init);
 286