Home | History | Annotate | Download | only in block
      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-common.h"
     25 #include "block_int.h"
     26 #include "module.h"
     27 #include <zlib.h>
     28 
     29 typedef struct BDRVCloopState {
     30     uint32_t block_size;
     31     uint32_t n_blocks;
     32     uint64_t* offsets;
     33     uint32_t sectors_per_block;
     34     uint32_t current_block;
     35     uint8_t *compressed_block;
     36     uint8_t *uncompressed_block;
     37     z_stream zstream;
     38 } BDRVCloopState;
     39 
     40 static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename)
     41 {
     42     const char* magic_version_2_0="#!/bin/sh\n"
     43 	"#V2.0 Format\n"
     44 	"modprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n";
     45     int length=strlen(magic_version_2_0);
     46     if(length>buf_size)
     47 	length=buf_size;
     48     if(!memcmp(magic_version_2_0,buf,length))
     49 	return 2;
     50     return 0;
     51 }
     52 
     53 static int cloop_open(BlockDriverState *bs, int flags)
     54 {
     55     BDRVCloopState *s = bs->opaque;
     56     uint32_t offsets_size,max_compressed_block_size=1,i;
     57 
     58     bs->read_only = 1;
     59 
     60     /* read header */
     61     if (bdrv_pread(bs->file, 128, &s->block_size, 4) < 4) {
     62         goto cloop_close;
     63     }
     64     s->block_size = be32_to_cpu(s->block_size);
     65 
     66     if (bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4) < 4) {
     67         goto cloop_close;
     68     }
     69     s->n_blocks = be32_to_cpu(s->n_blocks);
     70 
     71     /* read offsets */
     72     offsets_size = s->n_blocks * sizeof(uint64_t);
     73     s->offsets = qemu_malloc(offsets_size);
     74     if (bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size) <
     75             offsets_size) {
     76 	goto cloop_close;
     77     }
     78     for(i=0;i<s->n_blocks;i++) {
     79 	s->offsets[i]=be64_to_cpu(s->offsets[i]);
     80 	if(i>0) {
     81 	    uint32_t size=s->offsets[i]-s->offsets[i-1];
     82 	    if(size>max_compressed_block_size)
     83 		max_compressed_block_size=size;
     84 	}
     85     }
     86 
     87     /* initialize zlib engine */
     88     s->compressed_block = qemu_malloc(max_compressed_block_size+1);
     89     s->uncompressed_block = qemu_malloc(s->block_size);
     90     if(inflateInit(&s->zstream) != Z_OK)
     91 	goto cloop_close;
     92     s->current_block=s->n_blocks;
     93 
     94     s->sectors_per_block = s->block_size/512;
     95     bs->total_sectors = s->n_blocks*s->sectors_per_block;
     96     return 0;
     97 
     98 cloop_close:
     99     return -1;
    100 }
    101 
    102 static inline int cloop_read_block(BlockDriverState *bs, int block_num)
    103 {
    104     BDRVCloopState *s = bs->opaque;
    105 
    106     if(s->current_block != block_num) {
    107 	int ret;
    108         uint32_t bytes = s->offsets[block_num+1]-s->offsets[block_num];
    109 
    110         ret = bdrv_pread(bs->file, s->offsets[block_num], s->compressed_block,
    111                          bytes);
    112         if (ret != bytes)
    113             return -1;
    114 
    115 	s->zstream.next_in = s->compressed_block;
    116 	s->zstream.avail_in = bytes;
    117 	s->zstream.next_out = s->uncompressed_block;
    118 	s->zstream.avail_out = s->block_size;
    119 	ret = inflateReset(&s->zstream);
    120 	if(ret != Z_OK)
    121 	    return -1;
    122 	ret = inflate(&s->zstream, Z_FINISH);
    123 	if(ret != Z_STREAM_END || s->zstream.total_out != s->block_size)
    124 	    return -1;
    125 
    126 	s->current_block = block_num;
    127     }
    128     return 0;
    129 }
    130 
    131 static int cloop_read(BlockDriverState *bs, int64_t sector_num,
    132                     uint8_t *buf, int nb_sectors)
    133 {
    134     BDRVCloopState *s = bs->opaque;
    135     int i;
    136 
    137     for(i=0;i<nb_sectors;i++) {
    138 	uint32_t sector_offset_in_block=((sector_num+i)%s->sectors_per_block),
    139 	    block_num=(sector_num+i)/s->sectors_per_block;
    140 	if(cloop_read_block(bs, block_num) != 0)
    141 	    return -1;
    142 	memcpy(buf+i*512,s->uncompressed_block+sector_offset_in_block*512,512);
    143     }
    144     return 0;
    145 }
    146 
    147 static void cloop_close(BlockDriverState *bs)
    148 {
    149     BDRVCloopState *s = bs->opaque;
    150     if(s->n_blocks>0)
    151 	free(s->offsets);
    152     free(s->compressed_block);
    153     free(s->uncompressed_block);
    154     inflateEnd(&s->zstream);
    155 }
    156 
    157 static BlockDriver bdrv_cloop = {
    158     .format_name	= "cloop",
    159     .instance_size	= sizeof(BDRVCloopState),
    160     .bdrv_probe		= cloop_probe,
    161     .bdrv_open		= cloop_open,
    162     .bdrv_read		= cloop_read,
    163     .bdrv_close		= cloop_close,
    164 };
    165 
    166 static void bdrv_cloop_init(void)
    167 {
    168     bdrv_register(&bdrv_cloop);
    169 }
    170 
    171 block_init(bdrv_cloop_init);
    172