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" 25ea2384d3Sbellard #include "block_int.h" 26fc01f7e7Sbellard 27*7674e7bfSbellard #ifdef _BSD 28*7674e7bfSbellard #include <sys/types.h> 29*7674e7bfSbellard #include <sys/stat.h> 30*7674e7bfSbellard #include <sys/ioctl.h> 31*7674e7bfSbellard #include <sys/queue.h> 32*7674e7bfSbellard #include <sys/disk.h> 33*7674e7bfSbellard #endif 34*7674e7bfSbellard 35b338082bSbellard static BlockDriverState *bdrv_first; 36ea2384d3Sbellard static BlockDriver *first_drv; 37ea2384d3Sbellard 38ea2384d3Sbellard void bdrv_register(BlockDriver *bdrv) 39ea2384d3Sbellard { 40ea2384d3Sbellard bdrv->next = first_drv; 41ea2384d3Sbellard first_drv = bdrv; 42ea2384d3Sbellard } 43b338082bSbellard 44b338082bSbellard /* create a new block device (by default it is empty) */ 45b338082bSbellard BlockDriverState *bdrv_new(const char *device_name) 46fc01f7e7Sbellard { 47b338082bSbellard BlockDriverState **pbs, *bs; 48b338082bSbellard 49b338082bSbellard bs = qemu_mallocz(sizeof(BlockDriverState)); 50b338082bSbellard if(!bs) 51b338082bSbellard return NULL; 52b338082bSbellard pstrcpy(bs->device_name, sizeof(bs->device_name), device_name); 53ea2384d3Sbellard if (device_name[0] != '\0') { 54b338082bSbellard /* insert at the end */ 55b338082bSbellard pbs = &bdrv_first; 56b338082bSbellard while (*pbs != NULL) 57b338082bSbellard pbs = &(*pbs)->next; 58b338082bSbellard *pbs = bs; 59ea2384d3Sbellard } 60b338082bSbellard return bs; 61b338082bSbellard } 62b338082bSbellard 63ea2384d3Sbellard BlockDriver *bdrv_find_format(const char *format_name) 64ea2384d3Sbellard { 65ea2384d3Sbellard BlockDriver *drv1; 66ea2384d3Sbellard for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) { 67ea2384d3Sbellard if (!strcmp(drv1->format_name, format_name)) 68ea2384d3Sbellard return drv1; 69ea2384d3Sbellard } 70ea2384d3Sbellard return NULL; 71ea2384d3Sbellard } 72ea2384d3Sbellard 73ea2384d3Sbellard int bdrv_create(BlockDriver *drv, 74ea2384d3Sbellard const char *filename, int64_t size_in_sectors, 75ea2384d3Sbellard const char *backing_file, int flags) 76ea2384d3Sbellard { 77ea2384d3Sbellard if (!drv->bdrv_create) 78ea2384d3Sbellard return -ENOTSUP; 79ea2384d3Sbellard return drv->bdrv_create(filename, size_in_sectors, backing_file, flags); 80ea2384d3Sbellard } 81ea2384d3Sbellard 82d5249393Sbellard #ifdef _WIN32 83d5249393Sbellard static void get_tmp_filename(char *filename, int size) 84d5249393Sbellard { 85d5249393Sbellard /* XXX: find a better function */ 86d5249393Sbellard tmpnam(filename); 87d5249393Sbellard } 88d5249393Sbellard #else 89ea2384d3Sbellard static void get_tmp_filename(char *filename, int size) 90ea2384d3Sbellard { 91ea2384d3Sbellard int fd; 92d5249393Sbellard /* XXX: race condition possible */ 93ea2384d3Sbellard pstrcpy(filename, size, "/tmp/vl.XXXXXX"); 94ea2384d3Sbellard fd = mkstemp(filename); 95ea2384d3Sbellard close(fd); 96ea2384d3Sbellard } 97d5249393Sbellard #endif 98ea2384d3Sbellard 99*7674e7bfSbellard /* XXX: force raw format if block or character device ? It would 100*7674e7bfSbellard simplify the BSD case */ 101ea2384d3Sbellard static BlockDriver *find_image_format(const char *filename) 102ea2384d3Sbellard { 103ea2384d3Sbellard int fd, ret, score, score_max; 104ea2384d3Sbellard BlockDriver *drv1, *drv; 105*7674e7bfSbellard uint8_t *buf; 106*7674e7bfSbellard size_t bufsize = 1024; 107ea2384d3Sbellard 108ea2384d3Sbellard fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); 109ea2384d3Sbellard if (fd < 0) 110ea2384d3Sbellard return NULL; 111*7674e7bfSbellard #ifdef DIOCGSECTORSIZE 112*7674e7bfSbellard { 113*7674e7bfSbellard unsigned int sectorsize = 512; 114*7674e7bfSbellard if (!ioctl(fd, DIOCGSECTORSIZE, §orsize) && 115*7674e7bfSbellard sectorsize > bufsize) 116*7674e7bfSbellard bufsize = sectorsize; 117*7674e7bfSbellard } 118*7674e7bfSbellard #endif 119*7674e7bfSbellard buf = malloc(bufsize); 120*7674e7bfSbellard if (!buf) 121*7674e7bfSbellard return NULL; 122*7674e7bfSbellard ret = read(fd, buf, bufsize); 123ea2384d3Sbellard if (ret < 0) { 124ea2384d3Sbellard close(fd); 125*7674e7bfSbellard free(buf); 126ea2384d3Sbellard return NULL; 127ea2384d3Sbellard } 128ea2384d3Sbellard close(fd); 129ea2384d3Sbellard 130ea2384d3Sbellard drv = NULL; 131ea2384d3Sbellard score_max = 0; 132ea2384d3Sbellard for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) { 133ea2384d3Sbellard score = drv1->bdrv_probe(buf, ret, filename); 134ea2384d3Sbellard if (score > score_max) { 135ea2384d3Sbellard score_max = score; 136ea2384d3Sbellard drv = drv1; 137ea2384d3Sbellard } 138ea2384d3Sbellard } 139*7674e7bfSbellard free(buf); 140ea2384d3Sbellard return drv; 141ea2384d3Sbellard } 142ea2384d3Sbellard 143b338082bSbellard int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) 144b338082bSbellard { 145ea2384d3Sbellard return bdrv_open2(bs, filename, snapshot, NULL); 146ea2384d3Sbellard } 147ea2384d3Sbellard 148ea2384d3Sbellard int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot, 149ea2384d3Sbellard BlockDriver *drv) 150ea2384d3Sbellard { 151ea2384d3Sbellard int ret; 152ea2384d3Sbellard char tmp_filename[1024]; 153fc01f7e7Sbellard 1540849bf08Sbellard bs->read_only = 0; 155ea2384d3Sbellard bs->is_temporary = 0; 156ea2384d3Sbellard bs->encrypted = 0; 15733e3963eSbellard 15833e3963eSbellard if (snapshot) { 159ea2384d3Sbellard BlockDriverState *bs1; 160ea2384d3Sbellard int64_t total_size; 16133e3963eSbellard 162ea2384d3Sbellard /* if snapshot, we create a temporary backing file and open it 163ea2384d3Sbellard instead of opening 'filename' directly */ 164ea2384d3Sbellard 165ea2384d3Sbellard /* if there is a backing file, use it */ 166ea2384d3Sbellard bs1 = bdrv_new(""); 167ea2384d3Sbellard if (!bs1) { 168ea2384d3Sbellard return -1; 169ea2384d3Sbellard } 170ea2384d3Sbellard if (bdrv_open(bs1, filename, 0) < 0) { 171ea2384d3Sbellard bdrv_delete(bs1); 172ea2384d3Sbellard return -1; 173ea2384d3Sbellard } 174ea2384d3Sbellard total_size = bs1->total_sectors; 175ea2384d3Sbellard bdrv_delete(bs1); 176ea2384d3Sbellard 177ea2384d3Sbellard get_tmp_filename(tmp_filename, sizeof(tmp_filename)); 178ea2384d3Sbellard /* XXX: use cow for linux as it is more efficient ? */ 179ea2384d3Sbellard if (bdrv_create(&bdrv_qcow, tmp_filename, 180ea2384d3Sbellard total_size, filename, 0) < 0) { 181ea2384d3Sbellard return -1; 182ea2384d3Sbellard } 183ea2384d3Sbellard filename = tmp_filename; 184ea2384d3Sbellard bs->is_temporary = 1; 185ea2384d3Sbellard } 186ea2384d3Sbellard 187ea2384d3Sbellard pstrcpy(bs->filename, sizeof(bs->filename), filename); 188ea2384d3Sbellard if (!drv) { 189ea2384d3Sbellard drv = find_image_format(filename); 190ea2384d3Sbellard if (!drv) 191ea2384d3Sbellard return -1; 192ea2384d3Sbellard } 193ea2384d3Sbellard bs->drv = drv; 194ea2384d3Sbellard bs->opaque = qemu_mallocz(drv->instance_size); 195ea2384d3Sbellard if (bs->opaque == NULL && drv->instance_size > 0) 196ea2384d3Sbellard return -1; 197ea2384d3Sbellard 198ea2384d3Sbellard ret = drv->bdrv_open(bs, filename); 199ea2384d3Sbellard if (ret < 0) { 200ea2384d3Sbellard qemu_free(bs->opaque); 201ea2384d3Sbellard return -1; 202ea2384d3Sbellard } 203ea2384d3Sbellard #ifndef _WIN32 204ea2384d3Sbellard if (bs->is_temporary) { 205ea2384d3Sbellard unlink(filename); 20633e3963eSbellard } 20767b915a5Sbellard #endif 208ea2384d3Sbellard if (bs->backing_file[0] != '\0' && drv->bdrv_is_allocated) { 209ea2384d3Sbellard /* if there is a backing file, use it */ 210ea2384d3Sbellard bs->backing_hd = bdrv_new(""); 211ea2384d3Sbellard if (!bs->backing_hd) { 212ea2384d3Sbellard fail: 213ea2384d3Sbellard bdrv_close(bs); 214ea2384d3Sbellard return -1; 215ea2384d3Sbellard } 216ea2384d3Sbellard if (bdrv_open(bs->backing_hd, bs->backing_file, 0) < 0) 217ea2384d3Sbellard goto fail; 218ea2384d3Sbellard } 21933e3963eSbellard 220b338082bSbellard bs->inserted = 1; 221b338082bSbellard 222b338082bSbellard /* call the change callback */ 223b338082bSbellard if (bs->change_cb) 224b338082bSbellard bs->change_cb(bs->change_opaque); 225b338082bSbellard 226b338082bSbellard return 0; 227fc01f7e7Sbellard } 228fc01f7e7Sbellard 229fc01f7e7Sbellard void bdrv_close(BlockDriverState *bs) 230fc01f7e7Sbellard { 231b338082bSbellard if (bs->inserted) { 232ea2384d3Sbellard if (bs->backing_hd) 233ea2384d3Sbellard bdrv_delete(bs->backing_hd); 234ea2384d3Sbellard bs->drv->bdrv_close(bs); 235ea2384d3Sbellard qemu_free(bs->opaque); 236ea2384d3Sbellard #ifdef _WIN32 237ea2384d3Sbellard if (bs->is_temporary) { 238ea2384d3Sbellard unlink(bs->filename); 239ea2384d3Sbellard } 24067b915a5Sbellard #endif 241ea2384d3Sbellard bs->opaque = NULL; 242ea2384d3Sbellard bs->drv = NULL; 243b338082bSbellard bs->inserted = 0; 244b338082bSbellard 245b338082bSbellard /* call the change callback */ 246b338082bSbellard if (bs->change_cb) 247b338082bSbellard bs->change_cb(bs->change_opaque); 248b338082bSbellard } 249b338082bSbellard } 250b338082bSbellard 251b338082bSbellard void bdrv_delete(BlockDriverState *bs) 252b338082bSbellard { 253ea2384d3Sbellard /* XXX: remove the driver list */ 254b338082bSbellard bdrv_close(bs); 255b338082bSbellard qemu_free(bs); 256fc01f7e7Sbellard } 257fc01f7e7Sbellard 25833e3963eSbellard /* commit COW file into the raw image */ 25933e3963eSbellard int bdrv_commit(BlockDriverState *bs) 26033e3963eSbellard { 26133e3963eSbellard int64_t i; 262ea2384d3Sbellard int n, j; 263ea2384d3Sbellard unsigned char sector[512]; 26433e3963eSbellard 265b338082bSbellard if (!bs->inserted) 266ea2384d3Sbellard return -ENOENT; 26733e3963eSbellard 26833e3963eSbellard if (bs->read_only) { 269ea2384d3Sbellard return -EACCES; 27033e3963eSbellard } 27133e3963eSbellard 272ea2384d3Sbellard if (!bs->backing_hd) { 273ea2384d3Sbellard return -ENOTSUP; 274ea2384d3Sbellard } 275ea2384d3Sbellard 276ea2384d3Sbellard for (i = 0; i < bs->total_sectors;) { 277ea2384d3Sbellard if (bs->drv->bdrv_is_allocated(bs, i, 65536, &n)) { 278ea2384d3Sbellard for(j = 0; j < n; j++) { 27933e3963eSbellard if (bdrv_read(bs, i, sector, 1) != 0) { 280ea2384d3Sbellard return -EIO; 28133e3963eSbellard } 28233e3963eSbellard 283ea2384d3Sbellard if (bdrv_write(bs->backing_hd, i, sector, 1) != 0) { 284ea2384d3Sbellard return -EIO; 28533e3963eSbellard } 286ea2384d3Sbellard i++; 287ea2384d3Sbellard } 288ea2384d3Sbellard } else { 289ea2384d3Sbellard i += n; 29033e3963eSbellard } 29133e3963eSbellard } 29233e3963eSbellard return 0; 29333e3963eSbellard } 29433e3963eSbellard 295fc01f7e7Sbellard /* return -1 if error */ 296fc01f7e7Sbellard int bdrv_read(BlockDriverState *bs, int64_t sector_num, 297fc01f7e7Sbellard uint8_t *buf, int nb_sectors) 298fc01f7e7Sbellard { 299ea2384d3Sbellard int ret, n; 300ea2384d3Sbellard BlockDriver *drv = bs->drv; 301fc01f7e7Sbellard 302b338082bSbellard if (!bs->inserted) 303b338082bSbellard return -1; 304b338082bSbellard 30533e3963eSbellard while (nb_sectors > 0) { 306ea2384d3Sbellard if (sector_num == 0 && bs->boot_sector_enabled) { 307cf98951bSbellard memcpy(buf, bs->boot_sector_data, 512); 308cf98951bSbellard n = 1; 309ea2384d3Sbellard } else if (bs->backing_hd) { 310ea2384d3Sbellard if (drv->bdrv_is_allocated(bs, sector_num, nb_sectors, &n)) { 311ea2384d3Sbellard ret = drv->bdrv_read(bs, sector_num, buf, n); 312ea2384d3Sbellard if (ret < 0) 313ea2384d3Sbellard return -1; 31433e3963eSbellard } else { 315ea2384d3Sbellard /* read from the base image */ 316ea2384d3Sbellard ret = bdrv_read(bs->backing_hd, sector_num, buf, n); 317ea2384d3Sbellard if (ret < 0) 318fc01f7e7Sbellard return -1; 31933e3963eSbellard } 320ea2384d3Sbellard } else { 321ea2384d3Sbellard ret = drv->bdrv_read(bs, sector_num, buf, nb_sectors); 322ea2384d3Sbellard if (ret < 0) 323ea2384d3Sbellard return -1; 324ea2384d3Sbellard /* no need to loop */ 325ea2384d3Sbellard break; 32633e3963eSbellard } 32733e3963eSbellard nb_sectors -= n; 32833e3963eSbellard sector_num += n; 32933e3963eSbellard buf += n * 512; 33033e3963eSbellard } 331fc01f7e7Sbellard return 0; 332fc01f7e7Sbellard } 333fc01f7e7Sbellard 334fc01f7e7Sbellard /* return -1 if error */ 335fc01f7e7Sbellard int bdrv_write(BlockDriverState *bs, int64_t sector_num, 336fc01f7e7Sbellard const uint8_t *buf, int nb_sectors) 337fc01f7e7Sbellard { 338b338082bSbellard if (!bs->inserted) 339b338082bSbellard return -1; 3400849bf08Sbellard if (bs->read_only) 3410849bf08Sbellard return -1; 342ea2384d3Sbellard return bs->drv->bdrv_write(bs, sector_num, buf, nb_sectors); 343fc01f7e7Sbellard } 344fc01f7e7Sbellard 345fc01f7e7Sbellard void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr) 346fc01f7e7Sbellard { 347fc01f7e7Sbellard *nb_sectors_ptr = bs->total_sectors; 348fc01f7e7Sbellard } 349cf98951bSbellard 350cf98951bSbellard /* force a given boot sector. */ 351cf98951bSbellard void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size) 352cf98951bSbellard { 353cf98951bSbellard bs->boot_sector_enabled = 1; 354cf98951bSbellard if (size > 512) 355cf98951bSbellard size = 512; 356cf98951bSbellard memcpy(bs->boot_sector_data, data, size); 357cf98951bSbellard memset(bs->boot_sector_data + size, 0, 512 - size); 358cf98951bSbellard } 359b338082bSbellard 360b338082bSbellard void bdrv_set_geometry_hint(BlockDriverState *bs, 361b338082bSbellard int cyls, int heads, int secs) 362b338082bSbellard { 363b338082bSbellard bs->cyls = cyls; 364b338082bSbellard bs->heads = heads; 365b338082bSbellard bs->secs = secs; 366b338082bSbellard } 367b338082bSbellard 368b338082bSbellard void bdrv_set_type_hint(BlockDriverState *bs, int type) 369b338082bSbellard { 370b338082bSbellard bs->type = type; 371b338082bSbellard bs->removable = ((type == BDRV_TYPE_CDROM || 372b338082bSbellard type == BDRV_TYPE_FLOPPY)); 373b338082bSbellard } 374b338082bSbellard 37546d4767dSbellard void bdrv_set_translation_hint(BlockDriverState *bs, int translation) 37646d4767dSbellard { 37746d4767dSbellard bs->translation = translation; 37846d4767dSbellard } 37946d4767dSbellard 380b338082bSbellard void bdrv_get_geometry_hint(BlockDriverState *bs, 381b338082bSbellard int *pcyls, int *pheads, int *psecs) 382b338082bSbellard { 383b338082bSbellard *pcyls = bs->cyls; 384b338082bSbellard *pheads = bs->heads; 385b338082bSbellard *psecs = bs->secs; 386b338082bSbellard } 387b338082bSbellard 388b338082bSbellard int bdrv_get_type_hint(BlockDriverState *bs) 389b338082bSbellard { 390b338082bSbellard return bs->type; 391b338082bSbellard } 392b338082bSbellard 39346d4767dSbellard int bdrv_get_translation_hint(BlockDriverState *bs) 39446d4767dSbellard { 39546d4767dSbellard return bs->translation; 39646d4767dSbellard } 39746d4767dSbellard 398b338082bSbellard int bdrv_is_removable(BlockDriverState *bs) 399b338082bSbellard { 400b338082bSbellard return bs->removable; 401b338082bSbellard } 402b338082bSbellard 403b338082bSbellard int bdrv_is_read_only(BlockDriverState *bs) 404b338082bSbellard { 405b338082bSbellard return bs->read_only; 406b338082bSbellard } 407b338082bSbellard 408b338082bSbellard int bdrv_is_inserted(BlockDriverState *bs) 409b338082bSbellard { 410b338082bSbellard return bs->inserted; 411b338082bSbellard } 412b338082bSbellard 413b338082bSbellard int bdrv_is_locked(BlockDriverState *bs) 414b338082bSbellard { 415b338082bSbellard return bs->locked; 416b338082bSbellard } 417b338082bSbellard 418b338082bSbellard void bdrv_set_locked(BlockDriverState *bs, int locked) 419b338082bSbellard { 420b338082bSbellard bs->locked = locked; 421b338082bSbellard } 422b338082bSbellard 423b338082bSbellard void bdrv_set_change_cb(BlockDriverState *bs, 424b338082bSbellard void (*change_cb)(void *opaque), void *opaque) 425b338082bSbellard { 426b338082bSbellard bs->change_cb = change_cb; 427b338082bSbellard bs->change_opaque = opaque; 428b338082bSbellard } 429b338082bSbellard 430ea2384d3Sbellard int bdrv_is_encrypted(BlockDriverState *bs) 431ea2384d3Sbellard { 432ea2384d3Sbellard if (bs->backing_hd && bs->backing_hd->encrypted) 433ea2384d3Sbellard return 1; 434ea2384d3Sbellard return bs->encrypted; 435ea2384d3Sbellard } 436ea2384d3Sbellard 437ea2384d3Sbellard int bdrv_set_key(BlockDriverState *bs, const char *key) 438ea2384d3Sbellard { 439ea2384d3Sbellard int ret; 440ea2384d3Sbellard if (bs->backing_hd && bs->backing_hd->encrypted) { 441ea2384d3Sbellard ret = bdrv_set_key(bs->backing_hd, key); 442ea2384d3Sbellard if (ret < 0) 443ea2384d3Sbellard return ret; 444ea2384d3Sbellard if (!bs->encrypted) 445ea2384d3Sbellard return 0; 446ea2384d3Sbellard } 447ea2384d3Sbellard if (!bs->encrypted || !bs->drv || !bs->drv->bdrv_set_key) 448ea2384d3Sbellard return -1; 449ea2384d3Sbellard return bs->drv->bdrv_set_key(bs, key); 450ea2384d3Sbellard } 451ea2384d3Sbellard 452ea2384d3Sbellard void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size) 453ea2384d3Sbellard { 454ea2384d3Sbellard if (!bs->inserted || !bs->drv) { 455ea2384d3Sbellard buf[0] = '\0'; 456ea2384d3Sbellard } else { 457ea2384d3Sbellard pstrcpy(buf, buf_size, bs->drv->format_name); 458ea2384d3Sbellard } 459ea2384d3Sbellard } 460ea2384d3Sbellard 461ea2384d3Sbellard void bdrv_iterate_format(void (*it)(void *opaque, const char *name), 462ea2384d3Sbellard void *opaque) 463ea2384d3Sbellard { 464ea2384d3Sbellard BlockDriver *drv; 465ea2384d3Sbellard 466ea2384d3Sbellard for (drv = first_drv; drv != NULL; drv = drv->next) { 467ea2384d3Sbellard it(opaque, drv->format_name); 468ea2384d3Sbellard } 469ea2384d3Sbellard } 470ea2384d3Sbellard 471b338082bSbellard BlockDriverState *bdrv_find(const char *name) 472b338082bSbellard { 473b338082bSbellard BlockDriverState *bs; 474b338082bSbellard 475b338082bSbellard for (bs = bdrv_first; bs != NULL; bs = bs->next) { 476b338082bSbellard if (!strcmp(name, bs->device_name)) 477b338082bSbellard return bs; 478b338082bSbellard } 479b338082bSbellard return NULL; 480b338082bSbellard } 481b338082bSbellard 48281d0912dSbellard void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque) 48381d0912dSbellard { 48481d0912dSbellard BlockDriverState *bs; 48581d0912dSbellard 48681d0912dSbellard for (bs = bdrv_first; bs != NULL; bs = bs->next) { 48781d0912dSbellard it(opaque, bs->device_name); 48881d0912dSbellard } 48981d0912dSbellard } 49081d0912dSbellard 491ea2384d3Sbellard const char *bdrv_get_device_name(BlockDriverState *bs) 492ea2384d3Sbellard { 493ea2384d3Sbellard return bs->device_name; 494ea2384d3Sbellard } 495ea2384d3Sbellard 496b338082bSbellard void bdrv_info(void) 497b338082bSbellard { 498b338082bSbellard BlockDriverState *bs; 499b338082bSbellard 500b338082bSbellard for (bs = bdrv_first; bs != NULL; bs = bs->next) { 501b338082bSbellard term_printf("%s:", bs->device_name); 502b338082bSbellard term_printf(" type="); 503b338082bSbellard switch(bs->type) { 504b338082bSbellard case BDRV_TYPE_HD: 505b338082bSbellard term_printf("hd"); 506b338082bSbellard break; 507b338082bSbellard case BDRV_TYPE_CDROM: 508b338082bSbellard term_printf("cdrom"); 509b338082bSbellard break; 510b338082bSbellard case BDRV_TYPE_FLOPPY: 511b338082bSbellard term_printf("floppy"); 512b338082bSbellard break; 513b338082bSbellard } 514b338082bSbellard term_printf(" removable=%d", bs->removable); 515b338082bSbellard if (bs->removable) { 516b338082bSbellard term_printf(" locked=%d", bs->locked); 517b338082bSbellard } 518b338082bSbellard if (bs->inserted) { 519b338082bSbellard term_printf(" file=%s", bs->filename); 520ea2384d3Sbellard if (bs->backing_file[0] != '\0') 521ea2384d3Sbellard term_printf(" backing_file=%s", bs->backing_file); 522b338082bSbellard term_printf(" ro=%d", bs->read_only); 523ea2384d3Sbellard term_printf(" drv=%s", bs->drv->format_name); 524ea2384d3Sbellard if (bs->encrypted) 525ea2384d3Sbellard term_printf(" encrypted"); 526b338082bSbellard } else { 527b338082bSbellard term_printf(" [not inserted]"); 528b338082bSbellard } 529b338082bSbellard term_printf("\n"); 530b338082bSbellard } 531b338082bSbellard } 532ea2384d3Sbellard 533ea2384d3Sbellard 534ea2384d3Sbellard /**************************************************************/ 535ea2384d3Sbellard /* RAW block driver */ 536ea2384d3Sbellard 537ea2384d3Sbellard typedef struct BDRVRawState { 538ea2384d3Sbellard int fd; 539ea2384d3Sbellard } BDRVRawState; 540ea2384d3Sbellard 541ea2384d3Sbellard static int raw_probe(const uint8_t *buf, int buf_size, const char *filename) 542ea2384d3Sbellard { 543ea2384d3Sbellard return 1; /* maybe */ 544ea2384d3Sbellard } 545ea2384d3Sbellard 546ea2384d3Sbellard static int raw_open(BlockDriverState *bs, const char *filename) 547ea2384d3Sbellard { 548ea2384d3Sbellard BDRVRawState *s = bs->opaque; 549ea2384d3Sbellard int fd; 550ea2384d3Sbellard int64_t size; 551ea2384d3Sbellard 552ea2384d3Sbellard fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); 553ea2384d3Sbellard if (fd < 0) { 554ea2384d3Sbellard fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); 555ea2384d3Sbellard if (fd < 0) 556ea2384d3Sbellard return -1; 557ea2384d3Sbellard bs->read_only = 1; 558ea2384d3Sbellard } 559*7674e7bfSbellard #ifdef _BSD 560*7674e7bfSbellard { 561*7674e7bfSbellard struct stat sb; 562*7674e7bfSbellard if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) { 563*7674e7bfSbellard #ifdef DIOCGMEDIASIZE 564*7674e7bfSbellard if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size)) 565*7674e7bfSbellard #endif 566*7674e7bfSbellard size = lseek(fd, 0LL, SEEK_END); 567*7674e7bfSbellard } else 568*7674e7bfSbellard #endif 569*7674e7bfSbellard { 570d5249393Sbellard size = lseek(fd, 0, SEEK_END); 571*7674e7bfSbellard } 572c747cd1fSbellard #ifdef _WIN32 573c747cd1fSbellard /* On Windows hosts it can happen that we're unable to get file size 574c747cd1fSbellard for CD-ROM raw device (it's inherent limitation of the CDFS driver). */ 575c747cd1fSbellard if (size == -1) 576c747cd1fSbellard size = LONG_LONG_MAX; 577c747cd1fSbellard #endif 578ea2384d3Sbellard bs->total_sectors = size / 512; 579ea2384d3Sbellard s->fd = fd; 580ea2384d3Sbellard return 0; 581ea2384d3Sbellard } 582ea2384d3Sbellard 583ea2384d3Sbellard static int raw_read(BlockDriverState *bs, int64_t sector_num, 584ea2384d3Sbellard uint8_t *buf, int nb_sectors) 585ea2384d3Sbellard { 586ea2384d3Sbellard BDRVRawState *s = bs->opaque; 587ea2384d3Sbellard int ret; 588ea2384d3Sbellard 589d5249393Sbellard lseek(s->fd, sector_num * 512, SEEK_SET); 590ea2384d3Sbellard ret = read(s->fd, buf, nb_sectors * 512); 591ea2384d3Sbellard if (ret != nb_sectors * 512) 592ea2384d3Sbellard return -1; 593ea2384d3Sbellard return 0; 594ea2384d3Sbellard } 595ea2384d3Sbellard 596ea2384d3Sbellard static int raw_write(BlockDriverState *bs, int64_t sector_num, 597ea2384d3Sbellard const uint8_t *buf, int nb_sectors) 598ea2384d3Sbellard { 599ea2384d3Sbellard BDRVRawState *s = bs->opaque; 600ea2384d3Sbellard int ret; 601ea2384d3Sbellard 602d5249393Sbellard lseek(s->fd, sector_num * 512, SEEK_SET); 603ea2384d3Sbellard ret = write(s->fd, buf, nb_sectors * 512); 604ea2384d3Sbellard if (ret != nb_sectors * 512) 605ea2384d3Sbellard return -1; 606ea2384d3Sbellard return 0; 607ea2384d3Sbellard } 608ea2384d3Sbellard 609e2731addSbellard static void raw_close(BlockDriverState *bs) 610ea2384d3Sbellard { 611ea2384d3Sbellard BDRVRawState *s = bs->opaque; 612ea2384d3Sbellard close(s->fd); 613ea2384d3Sbellard } 614ea2384d3Sbellard 615ea2384d3Sbellard static int raw_create(const char *filename, int64_t total_size, 616ea2384d3Sbellard const char *backing_file, int flags) 617ea2384d3Sbellard { 618ea2384d3Sbellard int fd; 619ea2384d3Sbellard 620ea2384d3Sbellard if (flags || backing_file) 621ea2384d3Sbellard return -ENOTSUP; 622ea2384d3Sbellard 623ea2384d3Sbellard fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 624ea2384d3Sbellard 0644); 625ea2384d3Sbellard if (fd < 0) 626ea2384d3Sbellard return -EIO; 627d5249393Sbellard ftruncate(fd, total_size * 512); 628ea2384d3Sbellard close(fd); 629ea2384d3Sbellard return 0; 630ea2384d3Sbellard } 631ea2384d3Sbellard 632ea2384d3Sbellard BlockDriver bdrv_raw = { 633ea2384d3Sbellard "raw", 634ea2384d3Sbellard sizeof(BDRVRawState), 635ea2384d3Sbellard raw_probe, 636ea2384d3Sbellard raw_open, 637ea2384d3Sbellard raw_read, 638ea2384d3Sbellard raw_write, 639ea2384d3Sbellard raw_close, 640ea2384d3Sbellard raw_create, 641ea2384d3Sbellard }; 642ea2384d3Sbellard 643ea2384d3Sbellard void bdrv_init(void) 644ea2384d3Sbellard { 645ea2384d3Sbellard bdrv_register(&bdrv_raw); 646ea2384d3Sbellard #ifndef _WIN32 647ea2384d3Sbellard bdrv_register(&bdrv_cow); 648ea2384d3Sbellard #endif 649ea2384d3Sbellard bdrv_register(&bdrv_qcow); 650ea2384d3Sbellard bdrv_register(&bdrv_vmdk); 6513c56521bSbellard bdrv_register(&bdrv_cloop); 652585d0ed9Sbellard bdrv_register(&bdrv_dmg); 653a8753c34Sbellard bdrv_register(&bdrv_bochs); 654ea2384d3Sbellard } 655