static int cloop_open(BlockDriverState *bs, const char *filename, int flags) { BDRVCloopState *s = bs->opaque; uint32_t offsets_size,max_compressed_block_size=1,i; s->fd = open(filename, O_RDONLY | O_BINARY); if (s->fd < 0) return -errno; bs->read_only = 1; /* read header */ if(lseek(s->fd,128,SEEK_SET)<0) { cloop_close: close(s->fd); return -1; } if(qemu_read_ok(s->fd,&s->block_size,4)<0) goto cloop_close; s->block_size=be32_to_cpu(s->block_size); if(qemu_read_ok(s->fd,&s->n_blocks,4)<0) goto cloop_close; s->n_blocks=be32_to_cpu(s->n_blocks); /* read offsets */ offsets_size=s->n_blocks*sizeof(uint64_t); if(!(s->offsets=(uint64_t*)malloc(offsets_size))) goto cloop_close; if(qemu_read_ok(s->fd,s->offsets,offsets_size)<0) goto cloop_close; for(i=0;i<s->n_blocks;i++) { s->offsets[i]=be64_to_cpu(s->offsets[i]); if(i>0) { uint32_t size=s->offsets[i]-s->offsets[i-1]; if(size>max_compressed_block_size) max_compressed_block_size=size; } } /* initialize zlib engine */ if(!(s->compressed_block = malloc(max_compressed_block_size+1))) goto cloop_close; if(!(s->uncompressed_block = malloc(s->block_size))) goto cloop_close; if(inflateInit(&s->zstream) != Z_OK) goto cloop_close; s->current_block=s->n_blocks; s->sectors_per_block = s->block_size/512; bs->total_sectors = s->n_blocks*s->sectors_per_block; return 0; }
static inline int cloop_read_block(BDRVCloopState *s,int block_num) { if(s->current_block != block_num) { int ret; uint32_t bytes = s->offsets[block_num+1]-s->offsets[block_num]; lseek(s->fd, s->offsets[block_num], SEEK_SET); ret = qemu_read_ok(s->fd, s->compressed_block, bytes); if (ret < 0) return -1; s->zstream.next_in = s->compressed_block; s->zstream.avail_in = bytes; s->zstream.next_out = s->uncompressed_block; s->zstream.avail_out = s->block_size; ret = inflateReset(&s->zstream); if(ret != Z_OK) return -1; ret = inflate(&s->zstream, Z_FINISH); if(ret != Z_STREAM_END || s->zstream.total_out != s->block_size) return -1; s->current_block = block_num; } return 0; }
static off_t read_off(int fd) { uint64_t buffer; if(qemu_read_ok(fd,&buffer,8)<0) return 0; return be64_to_cpu(buffer); }
static off_t read_uint32(int fd) { uint32_t buffer; if(qemu_read_ok(fd,&buffer,4)<0) return 0; return be32_to_cpu(buffer); }
static inline int dmg_read_chunk(BDRVDMGState *s,int sector_num) { if(!is_sector_in_chunk(s,s->current_chunk,sector_num)) { int ret; uint32_t chunk = search_chunk(s,sector_num); if(chunk>=s->n_chunks) return -1; s->current_chunk = s->n_chunks; switch(s->types[chunk]) { case 0x80000005: { /* zlib compressed */ ret = lseek(s->fd, s->offsets[chunk], SEEK_SET); if(ret<0) return -1; /* we need to buffer, because only the chunk as whole can be * inflated. */ ret = qemu_read_ok(s->fd, s->compressed_chunk, s->lengths[chunk]); if (ret < 0) return -1; s->zstream.next_in = s->compressed_chunk; s->zstream.avail_in = s->lengths[chunk]; s->zstream.next_out = s->uncompressed_chunk; s->zstream.avail_out = 512*s->sectorcounts[chunk]; ret = inflateReset(&s->zstream); if(ret != Z_OK) return -1; ret = inflate(&s->zstream, Z_FINISH); if(ret != Z_STREAM_END || s->zstream.total_out != 512*s->sectorcounts[chunk]) return -1; break; } case 1: /* copy */ ret = qemu_read_ok(s->fd, s->uncompressed_chunk, s->lengths[chunk]); if (ret < 0) return -1; break; case 2: /* zero */ memset(s->uncompressed_chunk, 0, 512*s->sectorcounts[chunk]); break; } s->current_chunk = chunk; } return 0; }