Commit 585d0ed98b032cdd062b9d43a6d0ef478fc914e8

Authored by bellard
1 parent a483b654

.dmg disk image format support (Johannes Schindelin)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1171 c046a42c-6fe2-441c-8c8c-71466251a162
Changelog
... ... @@ -5,6 +5,7 @@ version 0.6.2:
5 5 - undocumented FPU ops support
6 6 - Cirrus VGA: support for 1280x1024x[8,15,16] modes
7 7 - 'pidfile' option
  8 + - .dmg disk image format support (Johannes Schindelin)
8 9  
9 10 version 0.6.1:
10 11  
... ...
Makefile
... ... @@ -21,7 +21,7 @@ all: dyngen$(EXESUF) $(TOOLS) $(DOCS)
21 21 $(MAKE) -C $$d $@ || exit 1 ; \
22 22 done
23 23  
24   -qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c
  24 +qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c
25 25 $(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS)
26 26  
27 27 dyngen$(EXESUF): dyngen.c
... ...
Makefile.target
... ... @@ -265,7 +265,7 @@ endif
265 265  
266 266 # must use static linking to avoid leaving stuff in virtual address space
267 267 VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o
268   -VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o
  268 +VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o
269 269  
270 270 SOUND_HW = sb16.o
271 271 AUDIODRV = audio.o noaudio.o wavaudio.o
... ...
block-cloop.c
1 1 /*
2   - * QEMU System Emulator block driver
  2 + * QEMU Block driver for CLOOP images
3 3 *
4 4 * Copyright (c) 2004 Johannes E. Schindelin
5 5 *
... ... @@ -149,6 +149,8 @@ static void cloop_close(BlockDriverState *bs)
149 149 {
150 150 BDRVCloopState *s = bs->opaque;
151 151 close(s->fd);
  152 + if(s->n_blocks>0)
  153 + free(s->offsets);
152 154 free(s->compressed_block);
153 155 free(s->uncompressed_block);
154 156 inflateEnd(&s->zstream);
... ...
block-dmg.c 0 → 100644
  1 +/*
  2 + * QEMU Block driver for DMG 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 "vl.h"
  25 +#include "block_int.h"
  26 +#include "bswap.h"
  27 +#include <zlib.h>
  28 +
  29 +typedef struct BDRVDMGState {
  30 + int fd;
  31 +
  32 + /* each chunk contains a certain number of sectors,
  33 + * offsets[i] is the offset in the .dmg file,
  34 + * lengths[i] is the length of the compressed chunk,
  35 + * sectors[i] is the sector beginning at offsets[i],
  36 + * sectorcounts[i] is the number of sectors in that chunk,
  37 + * the sectors array is ordered
  38 + * 0<=i<n_chunks */
  39 +
  40 + uint32_t n_chunks;
  41 + uint32_t* types;
  42 + uint64_t* offsets;
  43 + uint64_t* lengths;
  44 + uint64_t* sectors;
  45 + uint64_t* sectorcounts;
  46 + uint32_t current_chunk;
  47 + char* compressed_chunk;
  48 + char* uncompressed_chunk;
  49 + z_stream zstream;
  50 +} BDRVDMGState;
  51 +
  52 +static int dmg_probe(const uint8_t *buf, int buf_size, const char *filename)
  53 +{
  54 + int len=strlen(filename);
  55 + if(len>4 && !strcmp(filename+len-4,".dmg"))
  56 + return 2;
  57 + return 0;
  58 +}
  59 +
  60 +static off_t read_off(int fd)
  61 +{
  62 + uint64_t buffer;
  63 + if(read(fd,&buffer,8)<8)
  64 + return 0;
  65 + return be64_to_cpu(buffer);
  66 +}
  67 +
  68 +static off_t read_uint32(int fd)
  69 +{
  70 + uint32_t buffer;
  71 + if(read(fd,&buffer,4)<4)
  72 + return 0;
  73 + return be32_to_cpu(buffer);
  74 +}
  75 +
  76 +static int dmg_open(BlockDriverState *bs, const char *filename)
  77 +{
  78 + BDRVDMGState *s = bs->opaque;
  79 + off_t info_begin,info_end,last_in_offset,last_out_offset;
  80 + uint32_t count;
  81 + uint32_t max_compressed_size=1,max_sectors_per_chunk=1,i;
  82 +
  83 + s->fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
  84 + if (s->fd < 0)
  85 + return -1;
  86 + bs->read_only = 1;
  87 + s->n_chunks = 0;
  88 + s->offsets = s->lengths = s->sectors = s->sectorcounts = 0;
  89 +
  90 + /* read offset of info blocks */
  91 + if(lseek(s->fd,-0x1d8,SEEK_END)<0) {
  92 +dmg_close:
  93 + close(s->fd);
  94 + return -1;
  95 + }
  96 + info_begin=read_off(s->fd);
  97 + if(info_begin==0)
  98 + goto dmg_close;
  99 + if(lseek(s->fd,info_begin,SEEK_SET)<0)
  100 + goto dmg_close;
  101 + if(read_uint32(s->fd)!=0x100)
  102 + goto dmg_close;
  103 + if((count = read_uint32(s->fd))==0)
  104 + goto dmg_close;
  105 + info_end = info_begin+count;
  106 + if(lseek(s->fd,0xf8,SEEK_CUR)<0)
  107 + goto dmg_close;
  108 +
  109 + /* read offsets */
  110 + last_in_offset = last_out_offset = 0;
  111 + while(lseek(s->fd,0,SEEK_CUR)<info_end) {
  112 + count = read_uint32(s->fd);
  113 + if(count==0)
  114 + goto dmg_close;
  115 + uint32_t type = read_uint32(s->fd);
  116 + if(type!=0x6d697368 || count<244)
  117 + lseek(s->fd,count-4,SEEK_CUR);
  118 + else {
  119 + int new_size, chunk_count;
  120 + if(lseek(s->fd,200,SEEK_CUR)<0)
  121 + goto dmg_close;
  122 + chunk_count = (count-204)/40;
  123 + new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count);
  124 + s->types = realloc(s->types, new_size/2);
  125 + s->offsets = realloc(s->offsets, new_size);
  126 + s->lengths = realloc(s->lengths, new_size);
  127 + s->sectors = realloc(s->sectors, new_size);
  128 + s->sectorcounts = realloc(s->sectorcounts, new_size);
  129 +
  130 + for(i=s->n_chunks;i<s->n_chunks+chunk_count;i++) {
  131 + s->types[i] = read_uint32(s->fd);
  132 + if(s->types[i]!=0x80000005 && s->types[i]!=1 && s->types[i]!=2) {
  133 + if(s->types[i]==0xffffffff) {
  134 + last_in_offset = s->offsets[i-1]+s->lengths[i-1];
  135 + last_out_offset = s->sectors[i-1]+s->sectorcounts[i-1];
  136 + }
  137 + chunk_count--;
  138 + i--;
  139 + if(lseek(s->fd,36,SEEK_CUR)<0)
  140 + goto dmg_close;
  141 + continue;
  142 + }
  143 + read_uint32(s->fd);
  144 + s->sectors[i] = last_out_offset+read_off(s->fd);
  145 + s->sectorcounts[i] = read_off(s->fd);
  146 + s->offsets[i] = last_in_offset+read_off(s->fd);
  147 + s->lengths[i] = read_off(s->fd);
  148 + if(s->lengths[i]>max_compressed_size)
  149 + max_compressed_size = s->lengths[i];
  150 + if(s->sectorcounts[i]>max_sectors_per_chunk)
  151 + max_sectors_per_chunk = s->sectorcounts[i];
  152 + }
  153 + s->n_chunks+=chunk_count;
  154 + }
  155 + }
  156 +
  157 + /* initialize zlib engine */
  158 + if(!(s->compressed_chunk=(char*)malloc(max_compressed_size+1)))
  159 + goto dmg_close;
  160 + if(!(s->uncompressed_chunk=(char*)malloc(512*max_sectors_per_chunk)))
  161 + goto dmg_close;
  162 + if(inflateInit(&s->zstream) != Z_OK)
  163 + goto dmg_close;
  164 +
  165 + s->current_chunk = s->n_chunks;
  166 +
  167 + return 0;
  168 +}
  169 +
  170 +static inline int is_sector_in_chunk(BDRVDMGState* s,
  171 + uint32_t chunk_num,int sector_num)
  172 +{
  173 + if(chunk_num>=s->n_chunks || s->sectors[chunk_num]>sector_num ||
  174 + s->sectors[chunk_num]+s->sectorcounts[chunk_num]<=sector_num)
  175 + return 0;
  176 + else
  177 + return -1;
  178 +}
  179 +
  180 +static inline uint32_t search_chunk(BDRVDMGState* s,int sector_num)
  181 +{
  182 + /* binary search */
  183 + uint32_t chunk1=0,chunk2=s->n_chunks,chunk3;
  184 + while(chunk1!=chunk2) {
  185 + chunk3 = (chunk1+chunk2)/2;
  186 + if(s->sectors[chunk3]>sector_num)
  187 + chunk2 = chunk3;
  188 + else if(s->sectors[chunk3]+s->sectorcounts[chunk3]>sector_num)
  189 + return chunk3;
  190 + else
  191 + chunk1 = chunk3;
  192 + }
  193 + return s->n_chunks; /* error */
  194 +}
  195 +
  196 +static inline int dmg_read_chunk(BDRVDMGState *s,int sector_num)
  197 +{
  198 + if(!is_sector_in_chunk(s,s->current_chunk,sector_num)) {
  199 + int ret;
  200 + uint32_t chunk = search_chunk(s,sector_num);
  201 +
  202 + if(chunk>=s->n_chunks)
  203 + return -1;
  204 +
  205 + s->current_chunk = s->n_chunks;
  206 + switch(s->types[chunk]) {
  207 + case 0x80000005: { /* zlib compressed */
  208 + int i;
  209 +
  210 + ret = lseek(s->fd, s->offsets[chunk], SEEK_SET);
  211 + if(ret<0)
  212 + return -1;
  213 +
  214 + /* we need to buffer, because only the chunk as whole can be
  215 + * inflated. */
  216 + i=0;
  217 + do {
  218 + ret = read(s->fd, s->compressed_chunk+i, s->lengths[chunk]-i);
  219 + if(ret<0 && errno==EINTR)
  220 + ret=0;
  221 + i+=ret;
  222 + } while(ret>=0 && ret+i<s->lengths[chunk]);
  223 +
  224 + if (ret != s->lengths[chunk])
  225 + return -1;
  226 +
  227 + s->zstream.next_in = s->compressed_chunk;
  228 + s->zstream.avail_in = s->lengths[chunk];
  229 + s->zstream.next_out = s->uncompressed_chunk;
  230 + s->zstream.avail_out = 512*s->sectorcounts[chunk];
  231 + ret = inflateReset(&s->zstream);
  232 + if(ret != Z_OK)
  233 + return -1;
  234 + ret = inflate(&s->zstream, Z_FINISH);
  235 + if(ret != Z_STREAM_END || s->zstream.total_out != 512*s->sectorcounts[chunk])
  236 + return -1;
  237 + break; }
  238 + case 1: /* copy */
  239 + ret = read(s->fd, s->uncompressed_chunk, s->lengths[chunk]);
  240 + if (ret != s->lengths[chunk])
  241 + return -1;
  242 + break;
  243 + case 2: /* zero */
  244 + memset(s->uncompressed_chunk, 0, 512*s->sectorcounts[chunk]);
  245 + break;
  246 + }
  247 + s->current_chunk = chunk;
  248 + }
  249 + return 0;
  250 +}
  251 +
  252 +static int dmg_read(BlockDriverState *bs, int64_t sector_num,
  253 + uint8_t *buf, int nb_sectors)
  254 +{
  255 + BDRVDMGState *s = bs->opaque;
  256 + int i;
  257 +
  258 + for(i=0;i<nb_sectors;i++) {
  259 + uint32_t sector_offset_in_chunk;
  260 + if(dmg_read_chunk(s, sector_num+i) != 0)
  261 + return -1;
  262 + sector_offset_in_chunk = sector_num+i-s->sectors[s->current_chunk];
  263 + memcpy(buf+i*512,s->uncompressed_chunk+sector_offset_in_chunk*512,512);
  264 + }
  265 + return 0;
  266 +}
  267 +
  268 +static void dmg_close(BlockDriverState *bs)
  269 +{
  270 + BDRVDMGState *s = bs->opaque;
  271 + close(s->fd);
  272 + if(s->n_chunks>0) {
  273 + free(s->types);
  274 + free(s->offsets);
  275 + free(s->lengths);
  276 + free(s->sectors);
  277 + free(s->sectorcounts);
  278 + }
  279 + free(s->compressed_chunk);
  280 + free(s->uncompressed_chunk);
  281 + inflateEnd(&s->zstream);
  282 +}
  283 +
  284 +BlockDriver bdrv_dmg = {
  285 + "dmg",
  286 + sizeof(BDRVDMGState),
  287 + dmg_probe,
  288 + dmg_open,
  289 + dmg_read,
  290 + NULL,
  291 + dmg_close,
  292 +};
  293 +
... ...
... ... @@ -607,4 +607,5 @@ void bdrv_init(void)
607 607 bdrv_register(&bdrv_qcow);
608 608 bdrv_register(&bdrv_vmdk);
609 609 bdrv_register(&bdrv_cloop);
  610 + bdrv_register(&bdrv_dmg);
610 611 }
... ...
... ... @@ -360,6 +360,7 @@ extern BlockDriver bdrv_cow;
360 360 extern BlockDriver bdrv_qcow;
361 361 extern BlockDriver bdrv_vmdk;
362 362 extern BlockDriver bdrv_cloop;
  363 +extern BlockDriver bdrv_dmg;
363 364  
364 365 void bdrv_init(void);
365 366 BlockDriver *bdrv_find_format(const char *format_name);
... ...