1fc01f7e7Sbellard /* 2fc01f7e7Sbellard * QEMU System Emulator block driver 3fc01f7e7Sbellard * 4fc01f7e7Sbellard * Copyright (c) 2003 Fabrice Bellard 5fc01f7e7Sbellard * 6fc01f7e7Sbellard * Permission is hereby granted, free of charge, to any person obtaining a copy 7fc01f7e7Sbellard * of this software and associated documentation files (the "Software"), to deal 8fc01f7e7Sbellard * in the Software without restriction, including without limitation the rights 9fc01f7e7Sbellard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10fc01f7e7Sbellard * copies of the Software, and to permit persons to whom the Software is 11fc01f7e7Sbellard * furnished to do so, subject to the following conditions: 12fc01f7e7Sbellard * 13fc01f7e7Sbellard * The above copyright notice and this permission notice shall be included in 14fc01f7e7Sbellard * all copies or substantial portions of the Software. 15fc01f7e7Sbellard * 16fc01f7e7Sbellard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17fc01f7e7Sbellard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18fc01f7e7Sbellard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19fc01f7e7Sbellard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20fc01f7e7Sbellard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21fc01f7e7Sbellard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22fc01f7e7Sbellard * THE SOFTWARE. 23fc01f7e7Sbellard */ 24fc01f7e7Sbellard #include "vl.h" 25*ea2384d3Sbellard #include "block_int.h" 26fc01f7e7Sbellard 27b338082bSbellard static BlockDriverState *bdrv_first; 28*ea2384d3Sbellard static BlockDriver *first_drv; 29*ea2384d3Sbellard 30*ea2384d3Sbellard void bdrv_register(BlockDriver *bdrv) 31*ea2384d3Sbellard { 32*ea2384d3Sbellard bdrv->next = first_drv; 33*ea2384d3Sbellard first_drv = bdrv; 34*ea2384d3Sbellard } 35b338082bSbellard 36b338082bSbellard /* create a new block device (by default it is empty) */ 37b338082bSbellard BlockDriverState *bdrv_new(const char *device_name) 38fc01f7e7Sbellard { 39b338082bSbellard BlockDriverState **pbs, *bs; 40b338082bSbellard 41b338082bSbellard bs = qemu_mallocz(sizeof(BlockDriverState)); 42b338082bSbellard if(!bs) 43b338082bSbellard return NULL; 44b338082bSbellard pstrcpy(bs->device_name, sizeof(bs->device_name), device_name); 45*ea2384d3Sbellard if (device_name[0] != '\0') { 46b338082bSbellard /* insert at the end */ 47b338082bSbellard pbs = &bdrv_first; 48b338082bSbellard while (*pbs != NULL) 49b338082bSbellard pbs = &(*pbs)->next; 50b338082bSbellard *pbs = bs; 51*ea2384d3Sbellard } 52b338082bSbellard return bs; 53b338082bSbellard } 54b338082bSbellard 55*ea2384d3Sbellard BlockDriver *bdrv_find_format(const char *format_name) 56*ea2384d3Sbellard { 57*ea2384d3Sbellard BlockDriver *drv1; 58*ea2384d3Sbellard for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) { 59*ea2384d3Sbellard if (!strcmp(drv1->format_name, format_name)) 60*ea2384d3Sbellard return drv1; 61*ea2384d3Sbellard } 62*ea2384d3Sbellard return NULL; 63*ea2384d3Sbellard } 64*ea2384d3Sbellard 65*ea2384d3Sbellard int bdrv_create(BlockDriver *drv, 66*ea2384d3Sbellard const char *filename, int64_t size_in_sectors, 67*ea2384d3Sbellard const char *backing_file, int flags) 68*ea2384d3Sbellard { 69*ea2384d3Sbellard if (!drv->bdrv_create) 70*ea2384d3Sbellard return -ENOTSUP; 71*ea2384d3Sbellard return drv->bdrv_create(filename, size_in_sectors, backing_file, flags); 72*ea2384d3Sbellard } 73*ea2384d3Sbellard 74*ea2384d3Sbellard /* XXX: race condition possible */ 75*ea2384d3Sbellard static void get_tmp_filename(char *filename, int size) 76*ea2384d3Sbellard { 77*ea2384d3Sbellard int fd; 78*ea2384d3Sbellard pstrcpy(filename, size, "/tmp/vl.XXXXXX"); 79*ea2384d3Sbellard fd = mkstemp(filename); 80*ea2384d3Sbellard close(fd); 81*ea2384d3Sbellard } 82*ea2384d3Sbellard 83*ea2384d3Sbellard static BlockDriver *find_image_format(const char *filename) 84*ea2384d3Sbellard { 85*ea2384d3Sbellard int fd, ret, score, score_max; 86*ea2384d3Sbellard BlockDriver *drv1, *drv; 87*ea2384d3Sbellard uint8_t buf[1024]; 88*ea2384d3Sbellard 89*ea2384d3Sbellard fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); 90*ea2384d3Sbellard if (fd < 0) 91*ea2384d3Sbellard return NULL; 92*ea2384d3Sbellard ret = read(fd, buf, sizeof(buf)); 93*ea2384d3Sbellard if (ret < 0) { 94*ea2384d3Sbellard close(fd); 95*ea2384d3Sbellard return NULL; 96*ea2384d3Sbellard } 97*ea2384d3Sbellard close(fd); 98*ea2384d3Sbellard 99*ea2384d3Sbellard drv = NULL; 100*ea2384d3Sbellard score_max = 0; 101*ea2384d3Sbellard for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) { 102*ea2384d3Sbellard score = drv1->bdrv_probe(buf, ret, filename); 103*ea2384d3Sbellard if (score > score_max) { 104*ea2384d3Sbellard score_max = score; 105*ea2384d3Sbellard drv = drv1; 106*ea2384d3Sbellard } 107*ea2384d3Sbellard } 108*ea2384d3Sbellard return drv; 109*ea2384d3Sbellard } 110*ea2384d3Sbellard 111b338082bSbellard int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) 112b338082bSbellard { 113*ea2384d3Sbellard return bdrv_open2(bs, filename, snapshot, NULL); 114*ea2384d3Sbellard } 115*ea2384d3Sbellard 116*ea2384d3Sbellard int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot, 117*ea2384d3Sbellard BlockDriver *drv) 118*ea2384d3Sbellard { 119*ea2384d3Sbellard int ret; 120*ea2384d3Sbellard char tmp_filename[1024]; 121fc01f7e7Sbellard 1220849bf08Sbellard bs->read_only = 0; 123*ea2384d3Sbellard bs->is_temporary = 0; 124*ea2384d3Sbellard bs->encrypted = 0; 12533e3963eSbellard 12633e3963eSbellard if (snapshot) { 127*ea2384d3Sbellard BlockDriverState *bs1; 128*ea2384d3Sbellard int64_t total_size; 12933e3963eSbellard 130*ea2384d3Sbellard /* if snapshot, we create a temporary backing file and open it 131*ea2384d3Sbellard instead of opening 'filename' directly */ 132*ea2384d3Sbellard 133*ea2384d3Sbellard /* if there is a backing file, use it */ 134*ea2384d3Sbellard bs1 = bdrv_new(""); 135*ea2384d3Sbellard if (!bs1) { 136*ea2384d3Sbellard return -1; 137*ea2384d3Sbellard } 138*ea2384d3Sbellard if (bdrv_open(bs1, filename, 0) < 0) { 139*ea2384d3Sbellard bdrv_delete(bs1); 140*ea2384d3Sbellard return -1; 141*ea2384d3Sbellard } 142*ea2384d3Sbellard total_size = bs1->total_sectors; 143*ea2384d3Sbellard bdrv_delete(bs1); 144*ea2384d3Sbellard 145*ea2384d3Sbellard get_tmp_filename(tmp_filename, sizeof(tmp_filename)); 146*ea2384d3Sbellard /* XXX: use cow for linux as it is more efficient ? */ 147*ea2384d3Sbellard if (bdrv_create(&bdrv_qcow, tmp_filename, 148*ea2384d3Sbellard total_size, filename, 0) < 0) { 149*ea2384d3Sbellard return -1; 150*ea2384d3Sbellard } 151*ea2384d3Sbellard filename = tmp_filename; 152*ea2384d3Sbellard bs->is_temporary = 1; 153*ea2384d3Sbellard } 154*ea2384d3Sbellard 155*ea2384d3Sbellard pstrcpy(bs->filename, sizeof(bs->filename), filename); 156*ea2384d3Sbellard if (!drv) { 157*ea2384d3Sbellard drv = find_image_format(filename); 158*ea2384d3Sbellard if (!drv) 159*ea2384d3Sbellard return -1; 160*ea2384d3Sbellard } 161*ea2384d3Sbellard bs->drv = drv; 162*ea2384d3Sbellard bs->opaque = qemu_mallocz(drv->instance_size); 163*ea2384d3Sbellard if (bs->opaque == NULL && drv->instance_size > 0) 164*ea2384d3Sbellard return -1; 165*ea2384d3Sbellard 166*ea2384d3Sbellard ret = drv->bdrv_open(bs, filename); 167*ea2384d3Sbellard if (ret < 0) { 168*ea2384d3Sbellard qemu_free(bs->opaque); 169*ea2384d3Sbellard return -1; 170*ea2384d3Sbellard } 171*ea2384d3Sbellard #ifndef _WIN32 172*ea2384d3Sbellard if (bs->is_temporary) { 173*ea2384d3Sbellard unlink(filename); 17433e3963eSbellard } 17567b915a5Sbellard #endif 176*ea2384d3Sbellard if (bs->backing_file[0] != '\0' && drv->bdrv_is_allocated) { 177*ea2384d3Sbellard /* if there is a backing file, use it */ 178*ea2384d3Sbellard bs->backing_hd = bdrv_new(""); 179*ea2384d3Sbellard if (!bs->backing_hd) { 180*ea2384d3Sbellard fail: 181*ea2384d3Sbellard bdrv_close(bs); 182*ea2384d3Sbellard return -1; 183*ea2384d3Sbellard } 184*ea2384d3Sbellard if (bdrv_open(bs->backing_hd, bs->backing_file, 0) < 0) 185*ea2384d3Sbellard goto fail; 186*ea2384d3Sbellard } 18733e3963eSbellard 188b338082bSbellard bs->inserted = 1; 189b338082bSbellard 190b338082bSbellard /* call the change callback */ 191b338082bSbellard if (bs->change_cb) 192b338082bSbellard bs->change_cb(bs->change_opaque); 193b338082bSbellard 194b338082bSbellard return 0; 195fc01f7e7Sbellard } 196fc01f7e7Sbellard 197fc01f7e7Sbellard void bdrv_close(BlockDriverState *bs) 198fc01f7e7Sbellard { 199b338082bSbellard if (bs->inserted) { 200*ea2384d3Sbellard if (bs->backing_hd) 201*ea2384d3Sbellard bdrv_delete(bs->backing_hd); 202*ea2384d3Sbellard bs->drv->bdrv_close(bs); 203*ea2384d3Sbellard qemu_free(bs->opaque); 204*ea2384d3Sbellard #ifdef _WIN32 205*ea2384d3Sbellard if (bs->is_temporary) { 206*ea2384d3Sbellard unlink(bs->filename); 207*ea2384d3Sbellard } 20867b915a5Sbellard #endif 209*ea2384d3Sbellard bs->opaque = NULL; 210*ea2384d3Sbellard bs->drv = NULL; 211b338082bSbellard bs->inserted = 0; 212b338082bSbellard 213b338082bSbellard /* call the change callback */ 214b338082bSbellard if (bs->change_cb) 215b338082bSbellard bs->change_cb(bs->change_opaque); 216b338082bSbellard } 217b338082bSbellard } 218b338082bSbellard 219b338082bSbellard void bdrv_delete(BlockDriverState *bs) 220b338082bSbellard { 221*ea2384d3Sbellard /* XXX: remove the driver list */ 222b338082bSbellard bdrv_close(bs); 223b338082bSbellard qemu_free(bs); 224fc01f7e7Sbellard } 225fc01f7e7Sbellard 22633e3963eSbellard /* commit COW file into the raw image */ 22733e3963eSbellard int bdrv_commit(BlockDriverState *bs) 22833e3963eSbellard { 22933e3963eSbellard int64_t i; 230*ea2384d3Sbellard int n, j; 231*ea2384d3Sbellard unsigned char sector[512]; 23233e3963eSbellard 233b338082bSbellard if (!bs->inserted) 234*ea2384d3Sbellard return -ENOENT; 23533e3963eSbellard 23633e3963eSbellard if (bs->read_only) { 237*ea2384d3Sbellard return -EACCES; 23833e3963eSbellard } 23933e3963eSbellard 240*ea2384d3Sbellard if (!bs->backing_hd) { 241*ea2384d3Sbellard return -ENOTSUP; 242*ea2384d3Sbellard } 243*ea2384d3Sbellard 244*ea2384d3Sbellard for (i = 0; i < bs->total_sectors;) { 245*ea2384d3Sbellard if (bs->drv->bdrv_is_allocated(bs, i, 65536, &n)) { 246*ea2384d3Sbellard for(j = 0; j < n; j++) { 24733e3963eSbellard if (bdrv_read(bs, i, sector, 1) != 0) { 248*ea2384d3Sbellard return -EIO; 24933e3963eSbellard } 25033e3963eSbellard 251*ea2384d3Sbellard if (bdrv_write(bs->backing_hd, i, sector, 1) != 0) { 252*ea2384d3Sbellard return -EIO; 25333e3963eSbellard } 254*ea2384d3Sbellard i++; 255*ea2384d3Sbellard } 256*ea2384d3Sbellard } else { 257*ea2384d3Sbellard i += n; 25833e3963eSbellard } 25933e3963eSbellard } 26033e3963eSbellard return 0; 26133e3963eSbellard } 26233e3963eSbellard 263fc01f7e7Sbellard /* return -1 if error */ 264fc01f7e7Sbellard int bdrv_read(BlockDriverState *bs, int64_t sector_num, 265fc01f7e7Sbellard uint8_t *buf, int nb_sectors) 266fc01f7e7Sbellard { 267*ea2384d3Sbellard int ret, n; 268*ea2384d3Sbellard BlockDriver *drv = bs->drv; 269fc01f7e7Sbellard 270b338082bSbellard if (!bs->inserted) 271b338082bSbellard return -1; 272b338082bSbellard 27333e3963eSbellard while (nb_sectors > 0) { 274*ea2384d3Sbellard if (sector_num == 0 && bs->boot_sector_enabled) { 275cf98951bSbellard memcpy(buf, bs->boot_sector_data, 512); 276cf98951bSbellard n = 1; 277*ea2384d3Sbellard } else if (bs->backing_hd) { 278*ea2384d3Sbellard if (drv->bdrv_is_allocated(bs, sector_num, nb_sectors, &n)) { 279*ea2384d3Sbellard ret = drv->bdrv_read(bs, sector_num, buf, n); 280*ea2384d3Sbellard if (ret < 0) 281*ea2384d3Sbellard return -1; 28233e3963eSbellard } else { 283*ea2384d3Sbellard /* read from the base image */ 284*ea2384d3Sbellard ret = bdrv_read(bs->backing_hd, sector_num, buf, n); 285*ea2384d3Sbellard if (ret < 0) 286fc01f7e7Sbellard return -1; 28733e3963eSbellard } 288*ea2384d3Sbellard } else { 289*ea2384d3Sbellard ret = drv->bdrv_read(bs, sector_num, buf, nb_sectors); 290*ea2384d3Sbellard if (ret < 0) 291*ea2384d3Sbellard return -1; 292*ea2384d3Sbellard /* no need to loop */ 293*ea2384d3Sbellard break; 29433e3963eSbellard } 29533e3963eSbellard nb_sectors -= n; 29633e3963eSbellard sector_num += n; 29733e3963eSbellard buf += n * 512; 29833e3963eSbellard } 299fc01f7e7Sbellard return 0; 300fc01f7e7Sbellard } 301fc01f7e7Sbellard 302fc01f7e7Sbellard /* return -1 if error */ 303fc01f7e7Sbellard int bdrv_write(BlockDriverState *bs, int64_t sector_num, 304fc01f7e7Sbellard const uint8_t *buf, int nb_sectors) 305fc01f7e7Sbellard { 306b338082bSbellard if (!bs->inserted) 307b338082bSbellard return -1; 3080849bf08Sbellard if (bs->read_only) 3090849bf08Sbellard return -1; 310*ea2384d3Sbellard return bs->drv->bdrv_write(bs, sector_num, buf, nb_sectors); 311fc01f7e7Sbellard } 312fc01f7e7Sbellard 313fc01f7e7Sbellard void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr) 314fc01f7e7Sbellard { 315fc01f7e7Sbellard *nb_sectors_ptr = bs->total_sectors; 316fc01f7e7Sbellard } 317cf98951bSbellard 318cf98951bSbellard /* force a given boot sector. */ 319cf98951bSbellard void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size) 320cf98951bSbellard { 321cf98951bSbellard bs->boot_sector_enabled = 1; 322cf98951bSbellard if (size > 512) 323cf98951bSbellard size = 512; 324cf98951bSbellard memcpy(bs->boot_sector_data, data, size); 325cf98951bSbellard memset(bs->boot_sector_data + size, 0, 512 - size); 326cf98951bSbellard } 327b338082bSbellard 328b338082bSbellard void bdrv_set_geometry_hint(BlockDriverState *bs, 329b338082bSbellard int cyls, int heads, int secs) 330b338082bSbellard { 331b338082bSbellard bs->cyls = cyls; 332b338082bSbellard bs->heads = heads; 333b338082bSbellard bs->secs = secs; 334b338082bSbellard } 335b338082bSbellard 336b338082bSbellard void bdrv_set_type_hint(BlockDriverState *bs, int type) 337b338082bSbellard { 338b338082bSbellard bs->type = type; 339b338082bSbellard bs->removable = ((type == BDRV_TYPE_CDROM || 340b338082bSbellard type == BDRV_TYPE_FLOPPY)); 341b338082bSbellard } 342b338082bSbellard 343b338082bSbellard void bdrv_get_geometry_hint(BlockDriverState *bs, 344b338082bSbellard int *pcyls, int *pheads, int *psecs) 345b338082bSbellard { 346b338082bSbellard *pcyls = bs->cyls; 347b338082bSbellard *pheads = bs->heads; 348b338082bSbellard *psecs = bs->secs; 349b338082bSbellard } 350b338082bSbellard 351b338082bSbellard int bdrv_get_type_hint(BlockDriverState *bs) 352b338082bSbellard { 353b338082bSbellard return bs->type; 354b338082bSbellard } 355b338082bSbellard 356b338082bSbellard int bdrv_is_removable(BlockDriverState *bs) 357b338082bSbellard { 358b338082bSbellard return bs->removable; 359b338082bSbellard } 360b338082bSbellard 361b338082bSbellard int bdrv_is_read_only(BlockDriverState *bs) 362b338082bSbellard { 363b338082bSbellard return bs->read_only; 364b338082bSbellard } 365b338082bSbellard 366b338082bSbellard int bdrv_is_inserted(BlockDriverState *bs) 367b338082bSbellard { 368b338082bSbellard return bs->inserted; 369b338082bSbellard } 370b338082bSbellard 371b338082bSbellard int bdrv_is_locked(BlockDriverState *bs) 372b338082bSbellard { 373b338082bSbellard return bs->locked; 374b338082bSbellard } 375b338082bSbellard 376b338082bSbellard void bdrv_set_locked(BlockDriverState *bs, int locked) 377b338082bSbellard { 378b338082bSbellard bs->locked = locked; 379b338082bSbellard } 380b338082bSbellard 381b338082bSbellard void bdrv_set_change_cb(BlockDriverState *bs, 382b338082bSbellard void (*change_cb)(void *opaque), void *opaque) 383b338082bSbellard { 384b338082bSbellard bs->change_cb = change_cb; 385b338082bSbellard bs->change_opaque = opaque; 386b338082bSbellard } 387b338082bSbellard 388*ea2384d3Sbellard int bdrv_is_encrypted(BlockDriverState *bs) 389*ea2384d3Sbellard { 390*ea2384d3Sbellard if (bs->backing_hd && bs->backing_hd->encrypted) 391*ea2384d3Sbellard return 1; 392*ea2384d3Sbellard return bs->encrypted; 393*ea2384d3Sbellard } 394*ea2384d3Sbellard 395*ea2384d3Sbellard int bdrv_set_key(BlockDriverState *bs, const char *key) 396*ea2384d3Sbellard { 397*ea2384d3Sbellard int ret; 398*ea2384d3Sbellard if (bs->backing_hd && bs->backing_hd->encrypted) { 399*ea2384d3Sbellard ret = bdrv_set_key(bs->backing_hd, key); 400*ea2384d3Sbellard if (ret < 0) 401*ea2384d3Sbellard return ret; 402*ea2384d3Sbellard if (!bs->encrypted) 403*ea2384d3Sbellard return 0; 404*ea2384d3Sbellard } 405*ea2384d3Sbellard if (!bs->encrypted || !bs->drv || !bs->drv->bdrv_set_key) 406*ea2384d3Sbellard return -1; 407*ea2384d3Sbellard return bs->drv->bdrv_set_key(bs, key); 408*ea2384d3Sbellard } 409*ea2384d3Sbellard 410*ea2384d3Sbellard void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size) 411*ea2384d3Sbellard { 412*ea2384d3Sbellard if (!bs->inserted || !bs->drv) { 413*ea2384d3Sbellard buf[0] = '\0'; 414*ea2384d3Sbellard } else { 415*ea2384d3Sbellard pstrcpy(buf, buf_size, bs->drv->format_name); 416*ea2384d3Sbellard } 417*ea2384d3Sbellard } 418*ea2384d3Sbellard 419*ea2384d3Sbellard void bdrv_iterate_format(void (*it)(void *opaque, const char *name), 420*ea2384d3Sbellard void *opaque) 421*ea2384d3Sbellard { 422*ea2384d3Sbellard BlockDriver *drv; 423*ea2384d3Sbellard 424*ea2384d3Sbellard for (drv = first_drv; drv != NULL; drv = drv->next) { 425*ea2384d3Sbellard it(opaque, drv->format_name); 426*ea2384d3Sbellard } 427*ea2384d3Sbellard } 428*ea2384d3Sbellard 429b338082bSbellard BlockDriverState *bdrv_find(const char *name) 430b338082bSbellard { 431b338082bSbellard BlockDriverState *bs; 432b338082bSbellard 433b338082bSbellard for (bs = bdrv_first; bs != NULL; bs = bs->next) { 434b338082bSbellard if (!strcmp(name, bs->device_name)) 435b338082bSbellard return bs; 436b338082bSbellard } 437b338082bSbellard return NULL; 438b338082bSbellard } 439b338082bSbellard 44081d0912dSbellard void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque) 44181d0912dSbellard { 44281d0912dSbellard BlockDriverState *bs; 44381d0912dSbellard 44481d0912dSbellard for (bs = bdrv_first; bs != NULL; bs = bs->next) { 44581d0912dSbellard it(opaque, bs->device_name); 44681d0912dSbellard } 44781d0912dSbellard } 44881d0912dSbellard 449*ea2384d3Sbellard const char *bdrv_get_device_name(BlockDriverState *bs) 450*ea2384d3Sbellard { 451*ea2384d3Sbellard return bs->device_name; 452*ea2384d3Sbellard } 453*ea2384d3Sbellard 454b338082bSbellard void bdrv_info(void) 455b338082bSbellard { 456b338082bSbellard BlockDriverState *bs; 457b338082bSbellard 458b338082bSbellard for (bs = bdrv_first; bs != NULL; bs = bs->next) { 459b338082bSbellard term_printf("%s:", bs->device_name); 460b338082bSbellard term_printf(" type="); 461b338082bSbellard switch(bs->type) { 462b338082bSbellard case BDRV_TYPE_HD: 463b338082bSbellard term_printf("hd"); 464b338082bSbellard break; 465b338082bSbellard case BDRV_TYPE_CDROM: 466b338082bSbellard term_printf("cdrom"); 467b338082bSbellard break; 468b338082bSbellard case BDRV_TYPE_FLOPPY: 469b338082bSbellard term_printf("floppy"); 470b338082bSbellard break; 471b338082bSbellard } 472b338082bSbellard term_printf(" removable=%d", bs->removable); 473b338082bSbellard if (bs->removable) { 474b338082bSbellard term_printf(" locked=%d", bs->locked); 475b338082bSbellard } 476b338082bSbellard if (bs->inserted) { 477b338082bSbellard term_printf(" file=%s", bs->filename); 478*ea2384d3Sbellard if (bs->backing_file[0] != '\0') 479*ea2384d3Sbellard term_printf(" backing_file=%s", bs->backing_file); 480b338082bSbellard term_printf(" ro=%d", bs->read_only); 481*ea2384d3Sbellard term_printf(" drv=%s", bs->drv->format_name); 482*ea2384d3Sbellard if (bs->encrypted) 483*ea2384d3Sbellard term_printf(" encrypted"); 484b338082bSbellard } else { 485b338082bSbellard term_printf(" [not inserted]"); 486b338082bSbellard } 487b338082bSbellard term_printf("\n"); 488b338082bSbellard } 489b338082bSbellard } 490*ea2384d3Sbellard 491*ea2384d3Sbellard 492*ea2384d3Sbellard /**************************************************************/ 493*ea2384d3Sbellard /* RAW block driver */ 494*ea2384d3Sbellard 495*ea2384d3Sbellard typedef struct BDRVRawState { 496*ea2384d3Sbellard int fd; 497*ea2384d3Sbellard } BDRVRawState; 498*ea2384d3Sbellard 499*ea2384d3Sbellard static int raw_probe(const uint8_t *buf, int buf_size, const char *filename) 500*ea2384d3Sbellard { 501*ea2384d3Sbellard return 1; /* maybe */ 502*ea2384d3Sbellard } 503*ea2384d3Sbellard 504*ea2384d3Sbellard static int raw_open(BlockDriverState *bs, const char *filename) 505*ea2384d3Sbellard { 506*ea2384d3Sbellard BDRVRawState *s = bs->opaque; 507*ea2384d3Sbellard int fd; 508*ea2384d3Sbellard int64_t size; 509*ea2384d3Sbellard 510*ea2384d3Sbellard fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); 511*ea2384d3Sbellard if (fd < 0) { 512*ea2384d3Sbellard fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); 513*ea2384d3Sbellard if (fd < 0) 514*ea2384d3Sbellard return -1; 515*ea2384d3Sbellard bs->read_only = 1; 516*ea2384d3Sbellard } 517*ea2384d3Sbellard size = lseek64(fd, 0, SEEK_END); 518*ea2384d3Sbellard bs->total_sectors = size / 512; 519*ea2384d3Sbellard s->fd = fd; 520*ea2384d3Sbellard return 0; 521*ea2384d3Sbellard } 522*ea2384d3Sbellard 523*ea2384d3Sbellard static int raw_read(BlockDriverState *bs, int64_t sector_num, 524*ea2384d3Sbellard uint8_t *buf, int nb_sectors) 525*ea2384d3Sbellard { 526*ea2384d3Sbellard BDRVRawState *s = bs->opaque; 527*ea2384d3Sbellard int ret; 528*ea2384d3Sbellard 529*ea2384d3Sbellard lseek64(s->fd, sector_num * 512, SEEK_SET); 530*ea2384d3Sbellard ret = read(s->fd, buf, nb_sectors * 512); 531*ea2384d3Sbellard if (ret != nb_sectors * 512) 532*ea2384d3Sbellard return -1; 533*ea2384d3Sbellard return 0; 534*ea2384d3Sbellard } 535*ea2384d3Sbellard 536*ea2384d3Sbellard static int raw_write(BlockDriverState *bs, int64_t sector_num, 537*ea2384d3Sbellard const uint8_t *buf, int nb_sectors) 538*ea2384d3Sbellard { 539*ea2384d3Sbellard BDRVRawState *s = bs->opaque; 540*ea2384d3Sbellard int ret; 541*ea2384d3Sbellard 542*ea2384d3Sbellard lseek64(s->fd, sector_num * 512, SEEK_SET); 543*ea2384d3Sbellard ret = write(s->fd, buf, nb_sectors * 512); 544*ea2384d3Sbellard if (ret != nb_sectors * 512) 545*ea2384d3Sbellard return -1; 546*ea2384d3Sbellard return 0; 547*ea2384d3Sbellard } 548*ea2384d3Sbellard 549*ea2384d3Sbellard static int raw_close(BlockDriverState *bs) 550*ea2384d3Sbellard { 551*ea2384d3Sbellard BDRVRawState *s = bs->opaque; 552*ea2384d3Sbellard close(s->fd); 553*ea2384d3Sbellard } 554*ea2384d3Sbellard 555*ea2384d3Sbellard static int raw_create(const char *filename, int64_t total_size, 556*ea2384d3Sbellard const char *backing_file, int flags) 557*ea2384d3Sbellard { 558*ea2384d3Sbellard int fd; 559*ea2384d3Sbellard 560*ea2384d3Sbellard if (flags || backing_file) 561*ea2384d3Sbellard return -ENOTSUP; 562*ea2384d3Sbellard 563*ea2384d3Sbellard fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 564*ea2384d3Sbellard 0644); 565*ea2384d3Sbellard if (fd < 0) 566*ea2384d3Sbellard return -EIO; 567*ea2384d3Sbellard ftruncate64(fd, total_size * 512); 568*ea2384d3Sbellard close(fd); 569*ea2384d3Sbellard return 0; 570*ea2384d3Sbellard } 571*ea2384d3Sbellard 572*ea2384d3Sbellard BlockDriver bdrv_raw = { 573*ea2384d3Sbellard "raw", 574*ea2384d3Sbellard sizeof(BDRVRawState), 575*ea2384d3Sbellard raw_probe, 576*ea2384d3Sbellard raw_open, 577*ea2384d3Sbellard raw_read, 578*ea2384d3Sbellard raw_write, 579*ea2384d3Sbellard raw_close, 580*ea2384d3Sbellard raw_create, 581*ea2384d3Sbellard }; 582*ea2384d3Sbellard 583*ea2384d3Sbellard void bdrv_init(void) 584*ea2384d3Sbellard { 585*ea2384d3Sbellard bdrv_register(&bdrv_raw); 586*ea2384d3Sbellard #ifndef _WIN32 587*ea2384d3Sbellard bdrv_register(&bdrv_cow); 588*ea2384d3Sbellard #endif 589*ea2384d3Sbellard bdrv_register(&bdrv_qcow); 590*ea2384d3Sbellard bdrv_register(&bdrv_vmdk); 591*ea2384d3Sbellard } 592