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 "qemu-common.h" 25 #include "block_int.h" 26 #include "bswap.h" 27 #include "module.h" 28 #include <zlib.h> 29 30 typedef struct BDRVDMGState { 31 CoMutex lock; 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 uint8_t *compressed_chunk; 48 uint8_t *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(BlockDriverState *bs, int64_t offset) 61 { 62 uint64_t buffer; 63 if (bdrv_pread(bs->file, offset, &buffer, 8) < 8) 64 return 0; 65 return be64_to_cpu(buffer); 66 } 67 68 static off_t read_uint32(BlockDriverState *bs, int64_t offset) 69 { 70 uint32_t buffer; 71 if (bdrv_pread(bs->file, offset, &buffer, 4) < 4) 72 return 0; 73 return be32_to_cpu(buffer); 74 } 75 76 static int dmg_open(BlockDriverState *bs, int flags) 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 int64_t offset; 83 84 bs->read_only = 1; 85 s->n_chunks = 0; 86 s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL; 87 88 /* read offset of info blocks */ 89 offset = bdrv_getlength(bs->file); 90 if (offset < 0) { 91 goto fail; 92 } 93 offset -= 0x1d8; 94 95 info_begin = read_off(bs, offset); 96 if (info_begin == 0) { 97 goto fail; 98 } 99 100 if (read_uint32(bs, info_begin) != 0x100) { 101 goto fail; 102 } 103 104 count = read_uint32(bs, info_begin + 4); 105 if (count == 0) { 106 goto fail; 107 } 108 info_end = info_begin + count; 109 110 offset = info_begin + 0x100; 111 112 /* read offsets */ 113 last_in_offset = last_out_offset = 0; 114 while (offset < info_end) { 115 uint32_t type; 116 117 count = read_uint32(bs, offset); 118 if(count==0) 119 goto fail; 120 offset += 4; 121 122 type = read_uint32(bs, offset); 123 if (type == 0x6d697368 && count >= 244) { 124 int new_size, chunk_count; 125 126 offset += 4; 127 offset += 200; 128 129 chunk_count = (count-204)/40; 130 new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count); 131 s->types = g_realloc(s->types, new_size/2); 132 s->offsets = g_realloc(s->offsets, new_size); 133 s->lengths = g_realloc(s->lengths, new_size); 134 s->sectors = g_realloc(s->sectors, new_size); 135 s->sectorcounts = g_realloc(s->sectorcounts, new_size); 136 137 for(i=s->n_chunks;i<s->n_chunks+chunk_count;i++) { 138 s->types[i] = read_uint32(bs, offset); 139 offset += 4; 140 if(s->types[i]!=0x80000005 && s->types[i]!=1 && s->types[i]!=2) { 141 if(s->types[i]==0xffffffff) { 142 last_in_offset = s->offsets[i-1]+s->lengths[i-1]; 143 last_out_offset = s->sectors[i-1]+s->sectorcounts[i-1]; 144 } 145 chunk_count--; 146 i--; 147 offset += 36; 148 continue; 149 } 150 offset += 4; 151 152 s->sectors[i] = last_out_offset+read_off(bs, offset); 153 offset += 8; 154 155 s->sectorcounts[i] = read_off(bs, offset); 156 offset += 8; 157 158 s->offsets[i] = last_in_offset+read_off(bs, offset); 159 offset += 8; 160 161 s->lengths[i] = read_off(bs, offset); 162 offset += 8; 163 164 if(s->lengths[i]>max_compressed_size) 165 max_compressed_size = s->lengths[i]; 166 if(s->sectorcounts[i]>max_sectors_per_chunk) 167 max_sectors_per_chunk = s->sectorcounts[i]; 168 } 169 s->n_chunks+=chunk_count; 170 } 171 } 172 173 /* initialize zlib engine */ 174 s->compressed_chunk = g_malloc(max_compressed_size+1); 175 s->uncompressed_chunk = g_malloc(512*max_sectors_per_chunk); 176 if(inflateInit(&s->zstream) != Z_OK) 177 goto fail; 178 179 s->current_chunk = s->n_chunks; 180 181 qemu_co_mutex_init(&s->lock); 182 return 0; 183 fail: 184 return -1; 185 } 186 187 static inline int is_sector_in_chunk(BDRVDMGState* s, 188 uint32_t chunk_num,int sector_num) 189 { 190 if(chunk_num>=s->n_chunks || s->sectors[chunk_num]>sector_num || 191 s->sectors[chunk_num]+s->sectorcounts[chunk_num]<=sector_num) 192 return 0; 193 else 194 return -1; 195 } 196 197 static inline uint32_t search_chunk(BDRVDMGState* s,int sector_num) 198 { 199 /* binary search */ 200 uint32_t chunk1=0,chunk2=s->n_chunks,chunk3; 201 while(chunk1!=chunk2) { 202 chunk3 = (chunk1+chunk2)/2; 203 if(s->sectors[chunk3]>sector_num) 204 chunk2 = chunk3; 205 else if(s->sectors[chunk3]+s->sectorcounts[chunk3]>sector_num) 206 return chunk3; 207 else 208 chunk1 = chunk3; 209 } 210 return s->n_chunks; /* error */ 211 } 212 213 static inline int dmg_read_chunk(BlockDriverState *bs, int sector_num) 214 { 215 BDRVDMGState *s = bs->opaque; 216 217 if(!is_sector_in_chunk(s,s->current_chunk,sector_num)) { 218 int ret; 219 uint32_t chunk = search_chunk(s,sector_num); 220 221 if(chunk>=s->n_chunks) 222 return -1; 223 224 s->current_chunk = s->n_chunks; 225 switch(s->types[chunk]) { 226 case 0x80000005: { /* zlib compressed */ 227 int i; 228 229 /* we need to buffer, because only the chunk as whole can be 230 * inflated. */ 231 i=0; 232 do { 233 ret = bdrv_pread(bs->file, s->offsets[chunk] + i, 234 s->compressed_chunk+i, s->lengths[chunk]-i); 235 if(ret<0 && errno==EINTR) 236 ret=0; 237 i+=ret; 238 } while(ret>=0 && ret+i<s->lengths[chunk]); 239 240 if (ret != s->lengths[chunk]) 241 return -1; 242 243 s->zstream.next_in = s->compressed_chunk; 244 s->zstream.avail_in = s->lengths[chunk]; 245 s->zstream.next_out = s->uncompressed_chunk; 246 s->zstream.avail_out = 512*s->sectorcounts[chunk]; 247 ret = inflateReset(&s->zstream); 248 if(ret != Z_OK) 249 return -1; 250 ret = inflate(&s->zstream, Z_FINISH); 251 if(ret != Z_STREAM_END || s->zstream.total_out != 512*s->sectorcounts[chunk]) 252 return -1; 253 break; } 254 case 1: /* copy */ 255 ret = bdrv_pread(bs->file, s->offsets[chunk], 256 s->uncompressed_chunk, s->lengths[chunk]); 257 if (ret != s->lengths[chunk]) 258 return -1; 259 break; 260 case 2: /* zero */ 261 memset(s->uncompressed_chunk, 0, 512*s->sectorcounts[chunk]); 262 break; 263 } 264 s->current_chunk = chunk; 265 } 266 return 0; 267 } 268 269 static int dmg_read(BlockDriverState *bs, int64_t sector_num, 270 uint8_t *buf, int nb_sectors) 271 { 272 BDRVDMGState *s = bs->opaque; 273 int i; 274 275 for(i=0;i<nb_sectors;i++) { 276 uint32_t sector_offset_in_chunk; 277 if(dmg_read_chunk(bs, sector_num+i) != 0) 278 return -1; 279 sector_offset_in_chunk = sector_num+i-s->sectors[s->current_chunk]; 280 memcpy(buf+i*512,s->uncompressed_chunk+sector_offset_in_chunk*512,512); 281 } 282 return 0; 283 } 284 285 static coroutine_fn int dmg_co_read(BlockDriverState *bs, int64_t sector_num, 286 uint8_t *buf, int nb_sectors) 287 { 288 int ret; 289 BDRVDMGState *s = bs->opaque; 290 qemu_co_mutex_lock(&s->lock); 291 ret = dmg_read(bs, sector_num, buf, nb_sectors); 292 qemu_co_mutex_unlock(&s->lock); 293 return ret; 294 } 295 296 static void dmg_close(BlockDriverState *bs) 297 { 298 BDRVDMGState *s = bs->opaque; 299 if(s->n_chunks>0) { 300 free(s->types); 301 free(s->offsets); 302 free(s->lengths); 303 free(s->sectors); 304 free(s->sectorcounts); 305 } 306 free(s->compressed_chunk); 307 free(s->uncompressed_chunk); 308 inflateEnd(&s->zstream); 309 } 310 311 static BlockDriver bdrv_dmg = { 312 .format_name = "dmg", 313 .instance_size = sizeof(BDRVDMGState), 314 .bdrv_probe = dmg_probe, 315 .bdrv_open = dmg_open, 316 .bdrv_read = dmg_co_read, 317 .bdrv_close = dmg_close, 318 }; 319 320 static void bdrv_dmg_init(void) 321 { 322 bdrv_register(&bdrv_dmg); 323 } 324 325 block_init(bdrv_dmg_init); 326