18b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* 28b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * QEMU Block driver for CLOOP images 38b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 48b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Copyright (c) 2004 Johannes E. Schindelin 58b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 68b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Permission is hereby granted, free of charge, to any person obtaining a copy 78b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * of this software and associated documentation files (the "Software"), to deal 88b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * in the Software without restriction, including without limitation the rights 98b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * copies of the Software, and to permit persons to whom the Software is 118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * furnished to do so, subject to the following conditions: 128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * The above copyright notice and this permission notice shall be included in 148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * all copies or substantial portions of the Software. 158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * THE SOFTWARE. 238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "qemu-common.h" 258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "block_int.h" 265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "module.h" 278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include <zlib.h> 288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct BDRVCloopState { 308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t block_size; 318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t n_blocks; 328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint64_t* offsets; 338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t sectors_per_block; 348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t current_block; 358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint8_t *compressed_block; 368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint8_t *uncompressed_block; 378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project z_stream zstream; 388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} BDRVCloopState; 398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int cloop_probe(const uint8_t *buf, int buf_size, const char *filename) 418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project const char* magic_version_2_0="#!/bin/sh\n" 438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project "#V2.0 Format\n" 448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project "modprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n"; 458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int length=strlen(magic_version_2_0); 468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(length>buf_size) 478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project length=buf_size; 488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(!memcmp(magic_version_2_0,buf,length)) 498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 2; 508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 53cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turnerstatic int cloop_open(BlockDriverState *bs, int flags) 548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BDRVCloopState *s = bs->opaque; 568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t offsets_size,max_compressed_block_size=1,i; 578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bs->read_only = 1; 598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* read header */ 61cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner if (bdrv_pread(bs->file, 128, &s->block_size, 4) < 4) { 62cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner goto cloop_close; 638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 64cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner s->block_size = be32_to_cpu(s->block_size); 65cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner 66cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner if (bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4) < 4) { 67cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner goto cloop_close; 68cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner } 69cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner s->n_blocks = be32_to_cpu(s->n_blocks); 708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* read offsets */ 72cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner offsets_size = s->n_blocks * sizeof(uint64_t); 73cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner s->offsets = qemu_malloc(offsets_size); 74cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner if (bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size) < 75cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner offsets_size) { 768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto cloop_close; 77cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner } 788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for(i=0;i<s->n_blocks;i++) { 798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->offsets[i]=be64_to_cpu(s->offsets[i]); 808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(i>0) { 818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t size=s->offsets[i]-s->offsets[i-1]; 828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(size>max_compressed_block_size) 838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project max_compressed_block_size=size; 848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* initialize zlib engine */ 885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->compressed_block = qemu_malloc(max_compressed_block_size+1); 895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->uncompressed_block = qemu_malloc(s->block_size); 908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(inflateInit(&s->zstream) != Z_OK) 918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto cloop_close; 928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->current_block=s->n_blocks; 938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->sectors_per_block = s->block_size/512; 958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bs->total_sectors = s->n_blocks*s->sectors_per_block; 968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 97cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner 98cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turnercloop_close: 99cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner return -1; 1008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 102cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turnerstatic inline int cloop_read_block(BlockDriverState *bs, int block_num) 1038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 104cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner BDRVCloopState *s = bs->opaque; 105cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner 1068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(s->current_block != block_num) { 1078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int ret; 1088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t bytes = s->offsets[block_num+1]-s->offsets[block_num]; 1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 110cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner ret = bdrv_pread(bs->file, s->offsets[block_num], s->compressed_block, 111cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner bytes); 1128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (ret != bytes) 1138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return -1; 1148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->zstream.next_in = s->compressed_block; 1168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->zstream.avail_in = bytes; 1178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->zstream.next_out = s->uncompressed_block; 1188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->zstream.avail_out = s->block_size; 1198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ret = inflateReset(&s->zstream); 1208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(ret != Z_OK) 1218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return -1; 1228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ret = inflate(&s->zstream, Z_FINISH); 1238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(ret != Z_STREAM_END || s->zstream.total_out != s->block_size) 1248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return -1; 1258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->current_block = block_num; 1278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 1298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int cloop_read(BlockDriverState *bs, int64_t sector_num, 1328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint8_t *buf, int nb_sectors) 1338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BDRVCloopState *s = bs->opaque; 1358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int i; 1368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for(i=0;i<nb_sectors;i++) { 1388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t sector_offset_in_block=((sector_num+i)%s->sectors_per_block), 1398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project block_num=(sector_num+i)/s->sectors_per_block; 140cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner if(cloop_read_block(bs, block_num) != 0) 1418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return -1; 1428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memcpy(buf+i*512,s->uncompressed_block+sector_offset_in_block*512,512); 1438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 1458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void cloop_close(BlockDriverState *bs) 1488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BDRVCloopState *s = bs->opaque; 1508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if(s->n_blocks>0) 1518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project free(s->offsets); 1528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project free(s->compressed_block); 1538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project free(s->uncompressed_block); 1548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project inflateEnd(&s->zstream); 1558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic BlockDriver bdrv_cloop = { 1585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .format_name = "cloop", 1595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .instance_size = sizeof(BDRVCloopState), 1605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .bdrv_probe = cloop_probe, 1615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .bdrv_open = cloop_open, 1625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .bdrv_read = cloop_read, 1635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .bdrv_close = cloop_close, 1648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}; 1658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bdrv_cloop_init(void) 1675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdrv_register(&bdrv_cloop); 1695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerblock_init(bdrv_cloop_init); 172