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 27b338082bSbellard static BlockDriverState *bdrv_first; 28ea2384d3Sbellard static BlockDriver *first_drv; 29ea2384d3Sbellard 30ea2384d3Sbellard void bdrv_register(BlockDriver *bdrv) 31ea2384d3Sbellard { 32ea2384d3Sbellard bdrv->next = first_drv; 33ea2384d3Sbellard first_drv = bdrv; 34ea2384d3Sbellard } 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); 45ea2384d3Sbellard 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; 51ea2384d3Sbellard } 52b338082bSbellard return bs; 53b338082bSbellard } 54b338082bSbellard 55ea2384d3Sbellard BlockDriver *bdrv_find_format(const char *format_name) 56ea2384d3Sbellard { 57ea2384d3Sbellard BlockDriver *drv1; 58ea2384d3Sbellard for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) { 59ea2384d3Sbellard if (!strcmp(drv1->format_name, format_name)) 60ea2384d3Sbellard return drv1; 61ea2384d3Sbellard } 62ea2384d3Sbellard return NULL; 63ea2384d3Sbellard } 64ea2384d3Sbellard 65ea2384d3Sbellard int bdrv_create(BlockDriver *drv, 66ea2384d3Sbellard const char *filename, int64_t size_in_sectors, 67ea2384d3Sbellard const char *backing_file, int flags) 68ea2384d3Sbellard { 69ea2384d3Sbellard if (!drv->bdrv_create) 70ea2384d3Sbellard return -ENOTSUP; 71ea2384d3Sbellard return drv->bdrv_create(filename, size_in_sectors, backing_file, flags); 72ea2384d3Sbellard } 73ea2384d3Sbellard 74d5249393Sbellard #ifdef _WIN32 75d5249393Sbellard static void get_tmp_filename(char *filename, int size) 76d5249393Sbellard { 77d5249393Sbellard /* XXX: find a better function */ 78d5249393Sbellard tmpnam(filename); 79d5249393Sbellard } 80d5249393Sbellard #else 81ea2384d3Sbellard static void get_tmp_filename(char *filename, int size) 82ea2384d3Sbellard { 83ea2384d3Sbellard int fd; 84d5249393Sbellard /* XXX: race condition possible */ 85ea2384d3Sbellard pstrcpy(filename, size, "/tmp/vl.XXXXXX"); 86ea2384d3Sbellard fd = mkstemp(filename); 87ea2384d3Sbellard close(fd); 88ea2384d3Sbellard } 89d5249393Sbellard #endif 90ea2384d3Sbellard 91ea2384d3Sbellard static BlockDriver *find_image_format(const char *filename) 92ea2384d3Sbellard { 93ea2384d3Sbellard int fd, ret, score, score_max; 94ea2384d3Sbellard BlockDriver *drv1, *drv; 95ea2384d3Sbellard uint8_t buf[1024]; 96ea2384d3Sbellard 97ea2384d3Sbellard fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); 98ea2384d3Sbellard if (fd < 0) 99ea2384d3Sbellard return NULL; 100ea2384d3Sbellard ret = read(fd, buf, sizeof(buf)); 101ea2384d3Sbellard if (ret < 0) { 102ea2384d3Sbellard close(fd); 103ea2384d3Sbellard return NULL; 104ea2384d3Sbellard } 105ea2384d3Sbellard close(fd); 106ea2384d3Sbellard 107ea2384d3Sbellard drv = NULL; 108ea2384d3Sbellard score_max = 0; 109ea2384d3Sbellard for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) { 110ea2384d3Sbellard score = drv1->bdrv_probe(buf, ret, filename); 111ea2384d3Sbellard if (score > score_max) { 112ea2384d3Sbellard score_max = score; 113ea2384d3Sbellard drv = drv1; 114ea2384d3Sbellard } 115ea2384d3Sbellard } 116ea2384d3Sbellard return drv; 117ea2384d3Sbellard } 118ea2384d3Sbellard 119b338082bSbellard int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) 120b338082bSbellard { 121ea2384d3Sbellard return bdrv_open2(bs, filename, snapshot, NULL); 122ea2384d3Sbellard } 123ea2384d3Sbellard 124ea2384d3Sbellard int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot, 125ea2384d3Sbellard BlockDriver *drv) 126ea2384d3Sbellard { 127ea2384d3Sbellard int ret; 128ea2384d3Sbellard char tmp_filename[1024]; 129fc01f7e7Sbellard 1300849bf08Sbellard bs->read_only = 0; 131ea2384d3Sbellard bs->is_temporary = 0; 132ea2384d3Sbellard bs->encrypted = 0; 13333e3963eSbellard 13433e3963eSbellard if (snapshot) { 135ea2384d3Sbellard BlockDriverState *bs1; 136ea2384d3Sbellard int64_t total_size; 13733e3963eSbellard 138ea2384d3Sbellard /* if snapshot, we create a temporary backing file and open it 139ea2384d3Sbellard instead of opening 'filename' directly */ 140ea2384d3Sbellard 141ea2384d3Sbellard /* if there is a backing file, use it */ 142ea2384d3Sbellard bs1 = bdrv_new(""); 143ea2384d3Sbellard if (!bs1) { 144ea2384d3Sbellard return -1; 145ea2384d3Sbellard } 146ea2384d3Sbellard if (bdrv_open(bs1, filename, 0) < 0) { 147ea2384d3Sbellard bdrv_delete(bs1); 148ea2384d3Sbellard return -1; 149ea2384d3Sbellard } 150ea2384d3Sbellard total_size = bs1->total_sectors; 151ea2384d3Sbellard bdrv_delete(bs1); 152ea2384d3Sbellard 153ea2384d3Sbellard get_tmp_filename(tmp_filename, sizeof(tmp_filename)); 154ea2384d3Sbellard /* XXX: use cow for linux as it is more efficient ? */ 155ea2384d3Sbellard if (bdrv_create(&bdrv_qcow, tmp_filename, 156ea2384d3Sbellard total_size, filename, 0) < 0) { 157ea2384d3Sbellard return -1; 158ea2384d3Sbellard } 159ea2384d3Sbellard filename = tmp_filename; 160ea2384d3Sbellard bs->is_temporary = 1; 161ea2384d3Sbellard } 162ea2384d3Sbellard 163ea2384d3Sbellard pstrcpy(bs->filename, sizeof(bs->filename), filename); 164ea2384d3Sbellard if (!drv) { 165ea2384d3Sbellard drv = find_image_format(filename); 166ea2384d3Sbellard if (!drv) 167ea2384d3Sbellard return -1; 168ea2384d3Sbellard } 169ea2384d3Sbellard bs->drv = drv; 170ea2384d3Sbellard bs->opaque = qemu_mallocz(drv->instance_size); 171ea2384d3Sbellard if (bs->opaque == NULL && drv->instance_size > 0) 172ea2384d3Sbellard return -1; 173ea2384d3Sbellard 174ea2384d3Sbellard ret = drv->bdrv_open(bs, filename); 175ea2384d3Sbellard if (ret < 0) { 176ea2384d3Sbellard qemu_free(bs->opaque); 177ea2384d3Sbellard return -1; 178ea2384d3Sbellard } 179ea2384d3Sbellard #ifndef _WIN32 180ea2384d3Sbellard if (bs->is_temporary) { 181ea2384d3Sbellard unlink(filename); 18233e3963eSbellard } 18367b915a5Sbellard #endif 184ea2384d3Sbellard if (bs->backing_file[0] != '\0' && drv->bdrv_is_allocated) { 185ea2384d3Sbellard /* if there is a backing file, use it */ 186ea2384d3Sbellard bs->backing_hd = bdrv_new(""); 187ea2384d3Sbellard if (!bs->backing_hd) { 188ea2384d3Sbellard fail: 189ea2384d3Sbellard bdrv_close(bs); 190ea2384d3Sbellard return -1; 191ea2384d3Sbellard } 192ea2384d3Sbellard if (bdrv_open(bs->backing_hd, bs->backing_file, 0) < 0) 193ea2384d3Sbellard goto fail; 194ea2384d3Sbellard } 19533e3963eSbellard 196b338082bSbellard bs->inserted = 1; 197b338082bSbellard 198b338082bSbellard /* call the change callback */ 199b338082bSbellard if (bs->change_cb) 200b338082bSbellard bs->change_cb(bs->change_opaque); 201b338082bSbellard 202b338082bSbellard return 0; 203fc01f7e7Sbellard } 204fc01f7e7Sbellard 205fc01f7e7Sbellard void bdrv_close(BlockDriverState *bs) 206fc01f7e7Sbellard { 207b338082bSbellard if (bs->inserted) { 208ea2384d3Sbellard if (bs->backing_hd) 209ea2384d3Sbellard bdrv_delete(bs->backing_hd); 210ea2384d3Sbellard bs->drv->bdrv_close(bs); 211ea2384d3Sbellard qemu_free(bs->opaque); 212ea2384d3Sbellard #ifdef _WIN32 213ea2384d3Sbellard if (bs->is_temporary) { 214ea2384d3Sbellard unlink(bs->filename); 215ea2384d3Sbellard } 21667b915a5Sbellard #endif 217ea2384d3Sbellard bs->opaque = NULL; 218ea2384d3Sbellard bs->drv = NULL; 219b338082bSbellard bs->inserted = 0; 220b338082bSbellard 221b338082bSbellard /* call the change callback */ 222b338082bSbellard if (bs->change_cb) 223b338082bSbellard bs->change_cb(bs->change_opaque); 224b338082bSbellard } 225b338082bSbellard } 226b338082bSbellard 227b338082bSbellard void bdrv_delete(BlockDriverState *bs) 228b338082bSbellard { 229ea2384d3Sbellard /* XXX: remove the driver list */ 230b338082bSbellard bdrv_close(bs); 231b338082bSbellard qemu_free(bs); 232fc01f7e7Sbellard } 233fc01f7e7Sbellard 23433e3963eSbellard /* commit COW file into the raw image */ 23533e3963eSbellard int bdrv_commit(BlockDriverState *bs) 23633e3963eSbellard { 23733e3963eSbellard int64_t i; 238ea2384d3Sbellard int n, j; 239ea2384d3Sbellard unsigned char sector[512]; 24033e3963eSbellard 241b338082bSbellard if (!bs->inserted) 242ea2384d3Sbellard return -ENOENT; 24333e3963eSbellard 24433e3963eSbellard if (bs->read_only) { 245ea2384d3Sbellard return -EACCES; 24633e3963eSbellard } 24733e3963eSbellard 248ea2384d3Sbellard if (!bs->backing_hd) { 249ea2384d3Sbellard return -ENOTSUP; 250ea2384d3Sbellard } 251ea2384d3Sbellard 252ea2384d3Sbellard for (i = 0; i < bs->total_sectors;) { 253ea2384d3Sbellard if (bs->drv->bdrv_is_allocated(bs, i, 65536, &n)) { 254ea2384d3Sbellard for(j = 0; j < n; j++) { 25533e3963eSbellard if (bdrv_read(bs, i, sector, 1) != 0) { 256ea2384d3Sbellard return -EIO; 25733e3963eSbellard } 25833e3963eSbellard 259ea2384d3Sbellard if (bdrv_write(bs->backing_hd, i, sector, 1) != 0) { 260ea2384d3Sbellard return -EIO; 26133e3963eSbellard } 262ea2384d3Sbellard i++; 263ea2384d3Sbellard } 264ea2384d3Sbellard } else { 265ea2384d3Sbellard i += n; 26633e3963eSbellard } 26733e3963eSbellard } 26833e3963eSbellard return 0; 26933e3963eSbellard } 27033e3963eSbellard 271fc01f7e7Sbellard /* return -1 if error */ 272fc01f7e7Sbellard int bdrv_read(BlockDriverState *bs, int64_t sector_num, 273fc01f7e7Sbellard uint8_t *buf, int nb_sectors) 274fc01f7e7Sbellard { 275ea2384d3Sbellard int ret, n; 276ea2384d3Sbellard BlockDriver *drv = bs->drv; 277fc01f7e7Sbellard 278b338082bSbellard if (!bs->inserted) 279b338082bSbellard return -1; 280b338082bSbellard 28133e3963eSbellard while (nb_sectors > 0) { 282ea2384d3Sbellard if (sector_num == 0 && bs->boot_sector_enabled) { 283cf98951bSbellard memcpy(buf, bs->boot_sector_data, 512); 284cf98951bSbellard n = 1; 285ea2384d3Sbellard } else if (bs->backing_hd) { 286ea2384d3Sbellard if (drv->bdrv_is_allocated(bs, sector_num, nb_sectors, &n)) { 287ea2384d3Sbellard ret = drv->bdrv_read(bs, sector_num, buf, n); 288ea2384d3Sbellard if (ret < 0) 289ea2384d3Sbellard return -1; 29033e3963eSbellard } else { 291ea2384d3Sbellard /* read from the base image */ 292ea2384d3Sbellard ret = bdrv_read(bs->backing_hd, sector_num, buf, n); 293ea2384d3Sbellard if (ret < 0) 294fc01f7e7Sbellard return -1; 29533e3963eSbellard } 296ea2384d3Sbellard } else { 297ea2384d3Sbellard ret = drv->bdrv_read(bs, sector_num, buf, nb_sectors); 298ea2384d3Sbellard if (ret < 0) 299ea2384d3Sbellard return -1; 300ea2384d3Sbellard /* no need to loop */ 301ea2384d3Sbellard break; 30233e3963eSbellard } 30333e3963eSbellard nb_sectors -= n; 30433e3963eSbellard sector_num += n; 30533e3963eSbellard buf += n * 512; 30633e3963eSbellard } 307fc01f7e7Sbellard return 0; 308fc01f7e7Sbellard } 309fc01f7e7Sbellard 310fc01f7e7Sbellard /* return -1 if error */ 311fc01f7e7Sbellard int bdrv_write(BlockDriverState *bs, int64_t sector_num, 312fc01f7e7Sbellard const uint8_t *buf, int nb_sectors) 313fc01f7e7Sbellard { 314b338082bSbellard if (!bs->inserted) 315b338082bSbellard return -1; 3160849bf08Sbellard if (bs->read_only) 3170849bf08Sbellard return -1; 318ea2384d3Sbellard return bs->drv->bdrv_write(bs, sector_num, buf, nb_sectors); 319fc01f7e7Sbellard } 320fc01f7e7Sbellard 321fc01f7e7Sbellard void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr) 322fc01f7e7Sbellard { 323fc01f7e7Sbellard *nb_sectors_ptr = bs->total_sectors; 324fc01f7e7Sbellard } 325cf98951bSbellard 326cf98951bSbellard /* force a given boot sector. */ 327cf98951bSbellard void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size) 328cf98951bSbellard { 329cf98951bSbellard bs->boot_sector_enabled = 1; 330cf98951bSbellard if (size > 512) 331cf98951bSbellard size = 512; 332cf98951bSbellard memcpy(bs->boot_sector_data, data, size); 333cf98951bSbellard memset(bs->boot_sector_data + size, 0, 512 - size); 334cf98951bSbellard } 335b338082bSbellard 336b338082bSbellard void bdrv_set_geometry_hint(BlockDriverState *bs, 337b338082bSbellard int cyls, int heads, int secs) 338b338082bSbellard { 339b338082bSbellard bs->cyls = cyls; 340b338082bSbellard bs->heads = heads; 341b338082bSbellard bs->secs = secs; 342b338082bSbellard } 343b338082bSbellard 344b338082bSbellard void bdrv_set_type_hint(BlockDriverState *bs, int type) 345b338082bSbellard { 346b338082bSbellard bs->type = type; 347b338082bSbellard bs->removable = ((type == BDRV_TYPE_CDROM || 348b338082bSbellard type == BDRV_TYPE_FLOPPY)); 349b338082bSbellard } 350b338082bSbellard 351*46d4767dSbellard void bdrv_set_translation_hint(BlockDriverState *bs, int translation) 352*46d4767dSbellard { 353*46d4767dSbellard bs->translation = translation; 354*46d4767dSbellard } 355*46d4767dSbellard 356b338082bSbellard void bdrv_get_geometry_hint(BlockDriverState *bs, 357b338082bSbellard int *pcyls, int *pheads, int *psecs) 358b338082bSbellard { 359b338082bSbellard *pcyls = bs->cyls; 360b338082bSbellard *pheads = bs->heads; 361b338082bSbellard *psecs = bs->secs; 362b338082bSbellard } 363b338082bSbellard 364b338082bSbellard int bdrv_get_type_hint(BlockDriverState *bs) 365b338082bSbellard { 366b338082bSbellard return bs->type; 367b338082bSbellard } 368b338082bSbellard 369*46d4767dSbellard int bdrv_get_translation_hint(BlockDriverState *bs) 370*46d4767dSbellard { 371*46d4767dSbellard return bs->translation; 372*46d4767dSbellard } 373*46d4767dSbellard 374b338082bSbellard int bdrv_is_removable(BlockDriverState *bs) 375b338082bSbellard { 376b338082bSbellard return bs->removable; 377b338082bSbellard } 378b338082bSbellard 379b338082bSbellard int bdrv_is_read_only(BlockDriverState *bs) 380b338082bSbellard { 381b338082bSbellard return bs->read_only; 382b338082bSbellard } 383b338082bSbellard 384b338082bSbellard int bdrv_is_inserted(BlockDriverState *bs) 385b338082bSbellard { 386b338082bSbellard return bs->inserted; 387b338082bSbellard } 388b338082bSbellard 389b338082bSbellard int bdrv_is_locked(BlockDriverState *bs) 390b338082bSbellard { 391b338082bSbellard return bs->locked; 392b338082bSbellard } 393b338082bSbellard 394b338082bSbellard void bdrv_set_locked(BlockDriverState *bs, int locked) 395b338082bSbellard { 396b338082bSbellard bs->locked = locked; 397b338082bSbellard } 398b338082bSbellard 399b338082bSbellard void bdrv_set_change_cb(BlockDriverState *bs, 400b338082bSbellard void (*change_cb)(void *opaque), void *opaque) 401b338082bSbellard { 402b338082bSbellard bs->change_cb = change_cb; 403b338082bSbellard bs->change_opaque = opaque; 404b338082bSbellard } 405b338082bSbellard 406ea2384d3Sbellard int bdrv_is_encrypted(BlockDriverState *bs) 407ea2384d3Sbellard { 408ea2384d3Sbellard if (bs->backing_hd && bs->backing_hd->encrypted) 409ea2384d3Sbellard return 1; 410ea2384d3Sbellard return bs->encrypted; 411ea2384d3Sbellard } 412ea2384d3Sbellard 413ea2384d3Sbellard int bdrv_set_key(BlockDriverState *bs, const char *key) 414ea2384d3Sbellard { 415ea2384d3Sbellard int ret; 416ea2384d3Sbellard if (bs->backing_hd && bs->backing_hd->encrypted) { 417ea2384d3Sbellard ret = bdrv_set_key(bs->backing_hd, key); 418ea2384d3Sbellard if (ret < 0) 419ea2384d3Sbellard return ret; 420ea2384d3Sbellard if (!bs->encrypted) 421ea2384d3Sbellard return 0; 422ea2384d3Sbellard } 423ea2384d3Sbellard if (!bs->encrypted || !bs->drv || !bs->drv->bdrv_set_key) 424ea2384d3Sbellard return -1; 425ea2384d3Sbellard return bs->drv->bdrv_set_key(bs, key); 426ea2384d3Sbellard } 427ea2384d3Sbellard 428ea2384d3Sbellard void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size) 429ea2384d3Sbellard { 430ea2384d3Sbellard if (!bs->inserted || !bs->drv) { 431ea2384d3Sbellard buf[0] = '\0'; 432ea2384d3Sbellard } else { 433ea2384d3Sbellard pstrcpy(buf, buf_size, bs->drv->format_name); 434ea2384d3Sbellard } 435ea2384d3Sbellard } 436ea2384d3Sbellard 437ea2384d3Sbellard void bdrv_iterate_format(void (*it)(void *opaque, const char *name), 438ea2384d3Sbellard void *opaque) 439ea2384d3Sbellard { 440ea2384d3Sbellard BlockDriver *drv; 441ea2384d3Sbellard 442ea2384d3Sbellard for (drv = first_drv; drv != NULL; drv = drv->next) { 443ea2384d3Sbellard it(opaque, drv->format_name); 444ea2384d3Sbellard } 445ea2384d3Sbellard } 446ea2384d3Sbellard 447b338082bSbellard BlockDriverState *bdrv_find(const char *name) 448b338082bSbellard { 449b338082bSbellard BlockDriverState *bs; 450b338082bSbellard 451b338082bSbellard for (bs = bdrv_first; bs != NULL; bs = bs->next) { 452b338082bSbellard if (!strcmp(name, bs->device_name)) 453b338082bSbellard return bs; 454b338082bSbellard } 455b338082bSbellard return NULL; 456b338082bSbellard } 457b338082bSbellard 45881d0912dSbellard void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque) 45981d0912dSbellard { 46081d0912dSbellard BlockDriverState *bs; 46181d0912dSbellard 46281d0912dSbellard for (bs = bdrv_first; bs != NULL; bs = bs->next) { 46381d0912dSbellard it(opaque, bs->device_name); 46481d0912dSbellard } 46581d0912dSbellard } 46681d0912dSbellard 467ea2384d3Sbellard const char *bdrv_get_device_name(BlockDriverState *bs) 468ea2384d3Sbellard { 469ea2384d3Sbellard return bs->device_name; 470ea2384d3Sbellard } 471ea2384d3Sbellard 472b338082bSbellard void bdrv_info(void) 473b338082bSbellard { 474b338082bSbellard BlockDriverState *bs; 475b338082bSbellard 476b338082bSbellard for (bs = bdrv_first; bs != NULL; bs = bs->next) { 477b338082bSbellard term_printf("%s:", bs->device_name); 478b338082bSbellard term_printf(" type="); 479b338082bSbellard switch(bs->type) { 480b338082bSbellard case BDRV_TYPE_HD: 481b338082bSbellard term_printf("hd"); 482b338082bSbellard break; 483b338082bSbellard case BDRV_TYPE_CDROM: 484b338082bSbellard term_printf("cdrom"); 485b338082bSbellard break; 486b338082bSbellard case BDRV_TYPE_FLOPPY: 487b338082bSbellard term_printf("floppy"); 488b338082bSbellard break; 489b338082bSbellard } 490b338082bSbellard term_printf(" removable=%d", bs->removable); 491b338082bSbellard if (bs->removable) { 492b338082bSbellard term_printf(" locked=%d", bs->locked); 493b338082bSbellard } 494b338082bSbellard if (bs->inserted) { 495b338082bSbellard term_printf(" file=%s", bs->filename); 496ea2384d3Sbellard if (bs->backing_file[0] != '\0') 497ea2384d3Sbellard term_printf(" backing_file=%s", bs->backing_file); 498b338082bSbellard term_printf(" ro=%d", bs->read_only); 499ea2384d3Sbellard term_printf(" drv=%s", bs->drv->format_name); 500ea2384d3Sbellard if (bs->encrypted) 501ea2384d3Sbellard term_printf(" encrypted"); 502b338082bSbellard } else { 503b338082bSbellard term_printf(" [not inserted]"); 504b338082bSbellard } 505b338082bSbellard term_printf("\n"); 506b338082bSbellard } 507b338082bSbellard } 508ea2384d3Sbellard 509ea2384d3Sbellard 510ea2384d3Sbellard /**************************************************************/ 511ea2384d3Sbellard /* RAW block driver */ 512ea2384d3Sbellard 513ea2384d3Sbellard typedef struct BDRVRawState { 514ea2384d3Sbellard int fd; 515ea2384d3Sbellard } BDRVRawState; 516ea2384d3Sbellard 517ea2384d3Sbellard static int raw_probe(const uint8_t *buf, int buf_size, const char *filename) 518ea2384d3Sbellard { 519ea2384d3Sbellard return 1; /* maybe */ 520ea2384d3Sbellard } 521ea2384d3Sbellard 522ea2384d3Sbellard static int raw_open(BlockDriverState *bs, const char *filename) 523ea2384d3Sbellard { 524ea2384d3Sbellard BDRVRawState *s = bs->opaque; 525ea2384d3Sbellard int fd; 526ea2384d3Sbellard int64_t size; 527ea2384d3Sbellard 528ea2384d3Sbellard fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); 529ea2384d3Sbellard if (fd < 0) { 530ea2384d3Sbellard fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); 531ea2384d3Sbellard if (fd < 0) 532ea2384d3Sbellard return -1; 533ea2384d3Sbellard bs->read_only = 1; 534ea2384d3Sbellard } 535d5249393Sbellard size = lseek(fd, 0, SEEK_END); 536ea2384d3Sbellard bs->total_sectors = size / 512; 537ea2384d3Sbellard s->fd = fd; 538ea2384d3Sbellard return 0; 539ea2384d3Sbellard } 540ea2384d3Sbellard 541ea2384d3Sbellard static int raw_read(BlockDriverState *bs, int64_t sector_num, 542ea2384d3Sbellard uint8_t *buf, int nb_sectors) 543ea2384d3Sbellard { 544ea2384d3Sbellard BDRVRawState *s = bs->opaque; 545ea2384d3Sbellard int ret; 546ea2384d3Sbellard 547d5249393Sbellard lseek(s->fd, sector_num * 512, SEEK_SET); 548ea2384d3Sbellard ret = read(s->fd, buf, nb_sectors * 512); 549ea2384d3Sbellard if (ret != nb_sectors * 512) 550ea2384d3Sbellard return -1; 551ea2384d3Sbellard return 0; 552ea2384d3Sbellard } 553ea2384d3Sbellard 554ea2384d3Sbellard static int raw_write(BlockDriverState *bs, int64_t sector_num, 555ea2384d3Sbellard const uint8_t *buf, int nb_sectors) 556ea2384d3Sbellard { 557ea2384d3Sbellard BDRVRawState *s = bs->opaque; 558ea2384d3Sbellard int ret; 559ea2384d3Sbellard 560d5249393Sbellard lseek(s->fd, sector_num * 512, SEEK_SET); 561ea2384d3Sbellard ret = write(s->fd, buf, nb_sectors * 512); 562ea2384d3Sbellard if (ret != nb_sectors * 512) 563ea2384d3Sbellard return -1; 564ea2384d3Sbellard return 0; 565ea2384d3Sbellard } 566ea2384d3Sbellard 567e2731addSbellard static void raw_close(BlockDriverState *bs) 568ea2384d3Sbellard { 569ea2384d3Sbellard BDRVRawState *s = bs->opaque; 570ea2384d3Sbellard close(s->fd); 571ea2384d3Sbellard } 572ea2384d3Sbellard 573ea2384d3Sbellard static int raw_create(const char *filename, int64_t total_size, 574ea2384d3Sbellard const char *backing_file, int flags) 575ea2384d3Sbellard { 576ea2384d3Sbellard int fd; 577ea2384d3Sbellard 578ea2384d3Sbellard if (flags || backing_file) 579ea2384d3Sbellard return -ENOTSUP; 580ea2384d3Sbellard 581ea2384d3Sbellard fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 582ea2384d3Sbellard 0644); 583ea2384d3Sbellard if (fd < 0) 584ea2384d3Sbellard return -EIO; 585d5249393Sbellard ftruncate(fd, total_size * 512); 586ea2384d3Sbellard close(fd); 587ea2384d3Sbellard return 0; 588ea2384d3Sbellard } 589ea2384d3Sbellard 590ea2384d3Sbellard BlockDriver bdrv_raw = { 591ea2384d3Sbellard "raw", 592ea2384d3Sbellard sizeof(BDRVRawState), 593ea2384d3Sbellard raw_probe, 594ea2384d3Sbellard raw_open, 595ea2384d3Sbellard raw_read, 596ea2384d3Sbellard raw_write, 597ea2384d3Sbellard raw_close, 598ea2384d3Sbellard raw_create, 599ea2384d3Sbellard }; 600ea2384d3Sbellard 601ea2384d3Sbellard void bdrv_init(void) 602ea2384d3Sbellard { 603ea2384d3Sbellard bdrv_register(&bdrv_raw); 604ea2384d3Sbellard #ifndef _WIN32 605ea2384d3Sbellard bdrv_register(&bdrv_cow); 606ea2384d3Sbellard #endif 607ea2384d3Sbellard bdrv_register(&bdrv_qcow); 608ea2384d3Sbellard bdrv_register(&bdrv_vmdk); 6093c56521bSbellard bdrv_register(&bdrv_cloop); 610ea2384d3Sbellard } 611