/* * Block driver to use composite images * * Copyright (c) 2007 Jim Brown * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "block_composite.h" static int composite_probe(const uint8_t *buf, int buf_size, const char *filename) { if (strstart(filename, "composite:", NULL)) return 100; return 0; } static int composite_open(BlockDriverState *bs, const char *nfilename, int flags) { BDRVPartState *s = bs->opaque; BlockDriverState * slave_bs; int previous_start, file_count = 1, i; const char * zfilename = &(nfilename[10]), * nptr = zfilename; char * filename; bs->read_only = 0; s->slave_count = 0; previous_start = 0; while (nptr != NULL) { nptr = strchr(nptr, ',')+1; if ((nptr-1) != NULL) { file_count++; } else { nptr = NULL; } } s->slave_bs = qemu_mallocz(sizeof(SlaveDriverState)*file_count); if (s->slave_bs == NULL) return -1; nptr = zfilename; while (nptr != NULL) { nptr = strchr(zfilename, ',')+1; if ((nptr-1) != NULL) { filename = strndup(zfilename, (size_t)((nptr-1)-zfilename)); zfilename = nptr; } else { filename = strdup(zfilename); nptr = NULL; } slave_bs = qemu_mallocz(sizeof(BlockDriverState)); if ((slave_bs == NULL) || (bdrv_open2(slave_bs, filename, 0, NULL) != 0)) { for (i = 0; i < s->slave_count; i++) { bdrv_close(s->slave_bs[i].bs); qemu_free(s->slave_bs[i].bs); } qemu_free(s->slave_bs); return -1; } free(filename); s->slave_bs[s->slave_count].bs = slave_bs; s->slave_bs[s->slave_count].start_sector = previous_start; previous_start = previous_start + s->slave_bs[s->slave_count].bs->total_sectors; s->slave_count++; if (slave_bs->read_only) { bs->read_only = 1; } } bs->total_sectors = previous_start; return 0; } static int composite_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors) { BDRVPartState *s = bs->opaque; int ret,sstart,send,i; sstart = -1; for (i = 0; i < s->slave_count; i++) { if ((s->slave_bs[i].start_sector + s->slave_bs[i].bs->total_sectors > sector_num) && (s->slave_bs[i].start_sector <= sector_num)) { sstart = i; break; } } if (sstart == -1) return -1; send = -1; for (i = 0; i < s->slave_count; i++) { if((s->slave_bs[i].start_sector + s->slave_bs[i].bs->total_sectors > sector_num+nb_sectors) && (s->slave_bs[i].start_sector <= sector_num+nb_sectors)) { send = i; break; } } if (send == -1) return -1; if (sstart > send) return -2; //wtf??? int a = 0, b = 0, bufpos = 0; i = sstart; while (i < send) { a = s->slave_bs[i].bs->total_sectors; ret = bdrv_read(s->slave_bs[i].bs, sector_num+b, &(buf[bufpos]), a); if (ret != 0) return ret; b = b+a; bufpos = bufpos + (a * 512); i++; } return bdrv_read(s->slave_bs[send].bs, sector_num+b, &(buf[bufpos]), nb_sectors-b); } static int composite_write(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors) { BDRVPartState *s = bs->opaque; int ret,sstart,send,i; sstart = -1; for (i = 0; i < s->slave_count; i++) { if ((s->slave_bs[i].start_sector + s->slave_bs[i].bs->total_sectors > sector_num) && (s->slave_bs[i].start_sector <= sector_num)) { sstart = i; break; } } if (sstart == -1) return -1; send = -1; for (i = 0; i < s->slave_count; i++) { if((s->slave_bs[i].start_sector + s->slave_bs[i].bs->total_sectors > sector_num+nb_sectors) && (s->slave_bs[i].start_sector <= sector_num+nb_sectors)) { send = i; break; } } if (send == -1) return -1; if (sstart > send) return -2; //wtf??? int a = 0, b = 0, bufpos = 0; i = sstart; while (i < send) { a = s->slave_bs[i].bs->total_sectors; ret = bdrv_write(s->slave_bs[i].bs, sector_num+b, &(buf[bufpos]), a); if (ret != 0) return ret; b = b+a; bufpos = bufpos + (a * 512); i++; } i= bdrv_write(s->slave_bs[send].bs, sector_num+b, &(buf[bufpos]), nb_sectors-b); return i; } static void composite_close(BlockDriverState *bs) { BDRVPartState *s = bs->opaque; int i; for (i = 0; i < s->slave_count; i++) { bdrv_close(s->slave_bs[i].bs); qemu_free(s->slave_bs[i].bs); } qemu_free(s->slave_bs); s->slave_bs = NULL; } static int composite_create(const char *filename, int64_t total_size, const char *backing_file, int flags) { /* what would be the point... just make a raw or qcow */ return -ENOTSUP; } BlockDriver bdrv_composite = { "composite", sizeof(BDRVPartState), composite_probe, composite_open, composite_read, composite_write, composite_close, composite_create, .protocol_name = "composite", };