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 277674e7bfSbellard #ifdef _BSD 287674e7bfSbellard #include <sys/types.h> 297674e7bfSbellard #include <sys/stat.h> 307674e7bfSbellard #include <sys/ioctl.h> 317674e7bfSbellard #include <sys/queue.h> 327674e7bfSbellard #include <sys/disk.h> 337674e7bfSbellard #endif 347674e7bfSbellard 353b0d4f61Sbellard #ifdef CONFIG_COCOA 363b0d4f61Sbellard #include <paths.h> 373b0d4f61Sbellard #include <sys/param.h> 383b0d4f61Sbellard #include <IOKit/IOKitLib.h> 393b0d4f61Sbellard #include <IOKit/IOBSD.h> 403b0d4f61Sbellard #include <IOKit/storage/IOMediaBSDClient.h> 413b0d4f61Sbellard #include <IOKit/storage/IOMedia.h> 423b0d4f61Sbellard #include <IOKit/storage/IOCDMedia.h> 433b0d4f61Sbellard //#include <IOKit/storage/IOCDTypes.h> 443b0d4f61Sbellard #include <CoreFoundation/CoreFoundation.h> 453b0d4f61Sbellard #endif 463b0d4f61Sbellard 47*ec530c81Sbellard #ifdef __sun__ 48*ec530c81Sbellard #include <sys/dkio.h> 49*ec530c81Sbellard #endif 50*ec530c81Sbellard 51b338082bSbellard static BlockDriverState *bdrv_first; 52ea2384d3Sbellard static BlockDriver *first_drv; 53ea2384d3Sbellard 543b0d4f61Sbellard #ifdef CONFIG_COCOA 553b0d4f61Sbellard static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator ); 563b0d4f61Sbellard static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize ); 573b0d4f61Sbellard 583b0d4f61Sbellard kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator ) 593b0d4f61Sbellard { 603b0d4f61Sbellard kern_return_t kernResult; 613b0d4f61Sbellard mach_port_t masterPort; 623b0d4f61Sbellard CFMutableDictionaryRef classesToMatch; 633b0d4f61Sbellard 643b0d4f61Sbellard kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort ); 653b0d4f61Sbellard if ( KERN_SUCCESS != kernResult ) { 663b0d4f61Sbellard printf( "IOMasterPort returned %d\n", kernResult ); 673b0d4f61Sbellard } 683b0d4f61Sbellard 693b0d4f61Sbellard classesToMatch = IOServiceMatching( kIOCDMediaClass ); 703b0d4f61Sbellard if ( classesToMatch == NULL ) { 713b0d4f61Sbellard printf( "IOServiceMatching returned a NULL dictionary.\n" ); 723b0d4f61Sbellard } else { 733b0d4f61Sbellard CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue ); 743b0d4f61Sbellard } 753b0d4f61Sbellard kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, mediaIterator ); 763b0d4f61Sbellard if ( KERN_SUCCESS != kernResult ) 773b0d4f61Sbellard { 783b0d4f61Sbellard printf( "IOServiceGetMatchingServices returned %d\n", kernResult ); 793b0d4f61Sbellard } 803b0d4f61Sbellard 813b0d4f61Sbellard return kernResult; 823b0d4f61Sbellard } 833b0d4f61Sbellard 843b0d4f61Sbellard kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize ) 853b0d4f61Sbellard { 863b0d4f61Sbellard io_object_t nextMedia; 873b0d4f61Sbellard kern_return_t kernResult = KERN_FAILURE; 883b0d4f61Sbellard *bsdPath = '\0'; 893b0d4f61Sbellard nextMedia = IOIteratorNext( mediaIterator ); 903b0d4f61Sbellard if ( nextMedia ) 913b0d4f61Sbellard { 923b0d4f61Sbellard CFTypeRef bsdPathAsCFString; 933b0d4f61Sbellard bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia, CFSTR( kIOBSDNameKey ), kCFAllocatorDefault, 0 ); 943b0d4f61Sbellard if ( bsdPathAsCFString ) { 953b0d4f61Sbellard size_t devPathLength; 963b0d4f61Sbellard strcpy( bsdPath, _PATH_DEV ); 973b0d4f61Sbellard strcat( bsdPath, "r" ); 983b0d4f61Sbellard devPathLength = strlen( bsdPath ); 993b0d4f61Sbellard if ( CFStringGetCString( bsdPathAsCFString, bsdPath + devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) { 1003b0d4f61Sbellard kernResult = KERN_SUCCESS; 1013b0d4f61Sbellard } 1023b0d4f61Sbellard CFRelease( bsdPathAsCFString ); 1033b0d4f61Sbellard } 1043b0d4f61Sbellard IOObjectRelease( nextMedia ); 1053b0d4f61Sbellard } 1063b0d4f61Sbellard 1073b0d4f61Sbellard return kernResult; 1083b0d4f61Sbellard } 1093b0d4f61Sbellard 1103b0d4f61Sbellard #endif 1113b0d4f61Sbellard 112ea2384d3Sbellard void bdrv_register(BlockDriver *bdrv) 113ea2384d3Sbellard { 114ea2384d3Sbellard bdrv->next = first_drv; 115ea2384d3Sbellard first_drv = bdrv; 116ea2384d3Sbellard } 117b338082bSbellard 118b338082bSbellard /* create a new block device (by default it is empty) */ 119b338082bSbellard BlockDriverState *bdrv_new(const char *device_name) 120fc01f7e7Sbellard { 121b338082bSbellard BlockDriverState **pbs, *bs; 122b338082bSbellard 123b338082bSbellard bs = qemu_mallocz(sizeof(BlockDriverState)); 124b338082bSbellard if(!bs) 125b338082bSbellard return NULL; 126b338082bSbellard pstrcpy(bs->device_name, sizeof(bs->device_name), device_name); 127ea2384d3Sbellard if (device_name[0] != '\0') { 128b338082bSbellard /* insert at the end */ 129b338082bSbellard pbs = &bdrv_first; 130b338082bSbellard while (*pbs != NULL) 131b338082bSbellard pbs = &(*pbs)->next; 132b338082bSbellard *pbs = bs; 133ea2384d3Sbellard } 134b338082bSbellard return bs; 135b338082bSbellard } 136b338082bSbellard 137ea2384d3Sbellard BlockDriver *bdrv_find_format(const char *format_name) 138ea2384d3Sbellard { 139ea2384d3Sbellard BlockDriver *drv1; 140ea2384d3Sbellard for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) { 141ea2384d3Sbellard if (!strcmp(drv1->format_name, format_name)) 142ea2384d3Sbellard return drv1; 143ea2384d3Sbellard } 144ea2384d3Sbellard return NULL; 145ea2384d3Sbellard } 146ea2384d3Sbellard 147ea2384d3Sbellard int bdrv_create(BlockDriver *drv, 148ea2384d3Sbellard const char *filename, int64_t size_in_sectors, 149ea2384d3Sbellard const char *backing_file, int flags) 150ea2384d3Sbellard { 151ea2384d3Sbellard if (!drv->bdrv_create) 152ea2384d3Sbellard return -ENOTSUP; 153ea2384d3Sbellard return drv->bdrv_create(filename, size_in_sectors, backing_file, flags); 154ea2384d3Sbellard } 155ea2384d3Sbellard 156d5249393Sbellard #ifdef _WIN32 15795389c86Sbellard void get_tmp_filename(char *filename, int size) 158d5249393Sbellard { 15995389c86Sbellard char* p = strrchr(filename, '/'); 16095389c86Sbellard 16195389c86Sbellard if (p == NULL) 16295389c86Sbellard return; 16395389c86Sbellard 164d5249393Sbellard /* XXX: find a better function */ 16595389c86Sbellard tmpnam(p); 16695389c86Sbellard *p = '/'; 167d5249393Sbellard } 168d5249393Sbellard #else 16995389c86Sbellard void get_tmp_filename(char *filename, int size) 170ea2384d3Sbellard { 171ea2384d3Sbellard int fd; 172d5249393Sbellard /* XXX: race condition possible */ 173ea2384d3Sbellard pstrcpy(filename, size, "/tmp/vl.XXXXXX"); 174ea2384d3Sbellard fd = mkstemp(filename); 175ea2384d3Sbellard close(fd); 176ea2384d3Sbellard } 177d5249393Sbellard #endif 178ea2384d3Sbellard 1797674e7bfSbellard /* XXX: force raw format if block or character device ? It would 1807674e7bfSbellard simplify the BSD case */ 181ea2384d3Sbellard static BlockDriver *find_image_format(const char *filename) 182ea2384d3Sbellard { 183ea2384d3Sbellard int fd, ret, score, score_max; 184ea2384d3Sbellard BlockDriver *drv1, *drv; 1857674e7bfSbellard uint8_t *buf; 1867674e7bfSbellard size_t bufsize = 1024; 187ea2384d3Sbellard 188ea2384d3Sbellard fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); 189712e7874Sbellard if (fd < 0) { 190712e7874Sbellard buf = NULL; 191712e7874Sbellard ret = 0; 192712e7874Sbellard } else { 1937674e7bfSbellard #ifdef DIOCGSECTORSIZE 1947674e7bfSbellard { 1957674e7bfSbellard unsigned int sectorsize = 512; 1967674e7bfSbellard if (!ioctl(fd, DIOCGSECTORSIZE, §orsize) && 1977674e7bfSbellard sectorsize > bufsize) 1987674e7bfSbellard bufsize = sectorsize; 1997674e7bfSbellard } 2007674e7bfSbellard #endif 2013b0d4f61Sbellard #ifdef CONFIG_COCOA 2023b0d4f61Sbellard u_int32_t blockSize = 512; 2033b0d4f61Sbellard if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize > bufsize) { 2043b0d4f61Sbellard bufsize = blockSize; 2053b0d4f61Sbellard } 2063b0d4f61Sbellard #endif 207712e7874Sbellard buf = qemu_malloc(bufsize); 2087674e7bfSbellard if (!buf) 2097674e7bfSbellard return NULL; 2107674e7bfSbellard ret = read(fd, buf, bufsize); 211ea2384d3Sbellard if (ret < 0) { 212ea2384d3Sbellard close(fd); 213712e7874Sbellard qemu_free(buf); 214ea2384d3Sbellard return NULL; 215ea2384d3Sbellard } 216ea2384d3Sbellard close(fd); 217712e7874Sbellard } 218ea2384d3Sbellard 219ea2384d3Sbellard drv = NULL; 220ea2384d3Sbellard score_max = 0; 221ea2384d3Sbellard for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) { 222ea2384d3Sbellard score = drv1->bdrv_probe(buf, ret, filename); 223ea2384d3Sbellard if (score > score_max) { 224ea2384d3Sbellard score_max = score; 225ea2384d3Sbellard drv = drv1; 226ea2384d3Sbellard } 227ea2384d3Sbellard } 228712e7874Sbellard qemu_free(buf); 229ea2384d3Sbellard return drv; 230ea2384d3Sbellard } 231ea2384d3Sbellard 232b338082bSbellard int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) 233b338082bSbellard { 2343b0d4f61Sbellard #ifdef CONFIG_COCOA 2353b0d4f61Sbellard if ( strncmp( filename, "/dev/cdrom", 10 ) == 0 ) { 2363b0d4f61Sbellard kern_return_t kernResult; 2373b0d4f61Sbellard io_iterator_t mediaIterator; 2383b0d4f61Sbellard char bsdPath[ MAXPATHLEN ]; 2393b0d4f61Sbellard int fd; 2403b0d4f61Sbellard 2413b0d4f61Sbellard kernResult = FindEjectableCDMedia( &mediaIterator ); 2423b0d4f61Sbellard kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) ); 2433b0d4f61Sbellard 2443b0d4f61Sbellard if ( bsdPath[ 0 ] != '\0' ) { 2453b0d4f61Sbellard strcat(bsdPath,"s0"); 2463b0d4f61Sbellard /* some CDs don't have a partition 0 */ 2473b0d4f61Sbellard fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE); 2483b0d4f61Sbellard if (fd < 0) { 2493b0d4f61Sbellard bsdPath[strlen(bsdPath)-1] = '1'; 2503b0d4f61Sbellard } else { 2513b0d4f61Sbellard close(fd); 2523b0d4f61Sbellard } 2533b0d4f61Sbellard filename = bsdPath; 2543b0d4f61Sbellard } 2553b0d4f61Sbellard 2563b0d4f61Sbellard if ( mediaIterator ) 2573b0d4f61Sbellard IOObjectRelease( mediaIterator ); 2583b0d4f61Sbellard } 2593b0d4f61Sbellard #endif 260ea2384d3Sbellard return bdrv_open2(bs, filename, snapshot, NULL); 261ea2384d3Sbellard } 262ea2384d3Sbellard 263ea2384d3Sbellard int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot, 264ea2384d3Sbellard BlockDriver *drv) 265ea2384d3Sbellard { 266ea2384d3Sbellard int ret; 267ea2384d3Sbellard char tmp_filename[1024]; 268fc01f7e7Sbellard 2690849bf08Sbellard bs->read_only = 0; 270ea2384d3Sbellard bs->is_temporary = 0; 271ea2384d3Sbellard bs->encrypted = 0; 27233e3963eSbellard 27333e3963eSbellard if (snapshot) { 274ea2384d3Sbellard BlockDriverState *bs1; 275ea2384d3Sbellard int64_t total_size; 27633e3963eSbellard 277ea2384d3Sbellard /* if snapshot, we create a temporary backing file and open it 278ea2384d3Sbellard instead of opening 'filename' directly */ 279ea2384d3Sbellard 280ea2384d3Sbellard /* if there is a backing file, use it */ 281ea2384d3Sbellard bs1 = bdrv_new(""); 282ea2384d3Sbellard if (!bs1) { 283ea2384d3Sbellard return -1; 284ea2384d3Sbellard } 285ea2384d3Sbellard if (bdrv_open(bs1, filename, 0) < 0) { 286ea2384d3Sbellard bdrv_delete(bs1); 287ea2384d3Sbellard return -1; 288ea2384d3Sbellard } 289ea2384d3Sbellard total_size = bs1->total_sectors; 290ea2384d3Sbellard bdrv_delete(bs1); 291ea2384d3Sbellard 292ea2384d3Sbellard get_tmp_filename(tmp_filename, sizeof(tmp_filename)); 293ea2384d3Sbellard /* XXX: use cow for linux as it is more efficient ? */ 294ea2384d3Sbellard if (bdrv_create(&bdrv_qcow, tmp_filename, 295ea2384d3Sbellard total_size, filename, 0) < 0) { 296ea2384d3Sbellard return -1; 297ea2384d3Sbellard } 298ea2384d3Sbellard filename = tmp_filename; 299ea2384d3Sbellard bs->is_temporary = 1; 300ea2384d3Sbellard } 301ea2384d3Sbellard 302ea2384d3Sbellard pstrcpy(bs->filename, sizeof(bs->filename), filename); 303ea2384d3Sbellard if (!drv) { 304ea2384d3Sbellard drv = find_image_format(filename); 305ea2384d3Sbellard if (!drv) 306ea2384d3Sbellard return -1; 307ea2384d3Sbellard } 308ea2384d3Sbellard bs->drv = drv; 309ea2384d3Sbellard bs->opaque = qemu_mallocz(drv->instance_size); 310ea2384d3Sbellard if (bs->opaque == NULL && drv->instance_size > 0) 311ea2384d3Sbellard return -1; 312ea2384d3Sbellard 313ea2384d3Sbellard ret = drv->bdrv_open(bs, filename); 314ea2384d3Sbellard if (ret < 0) { 315ea2384d3Sbellard qemu_free(bs->opaque); 316ea2384d3Sbellard return -1; 317ea2384d3Sbellard } 318ea2384d3Sbellard #ifndef _WIN32 319ea2384d3Sbellard if (bs->is_temporary) { 320ea2384d3Sbellard unlink(filename); 32133e3963eSbellard } 32267b915a5Sbellard #endif 323ea2384d3Sbellard if (bs->backing_file[0] != '\0' && drv->bdrv_is_allocated) { 324ea2384d3Sbellard /* if there is a backing file, use it */ 325ea2384d3Sbellard bs->backing_hd = bdrv_new(""); 326ea2384d3Sbellard if (!bs->backing_hd) { 327ea2384d3Sbellard fail: 328ea2384d3Sbellard bdrv_close(bs); 329ea2384d3Sbellard return -1; 330ea2384d3Sbellard } 331ea2384d3Sbellard if (bdrv_open(bs->backing_hd, bs->backing_file, 0) < 0) 332ea2384d3Sbellard goto fail; 333ea2384d3Sbellard } 33433e3963eSbellard 335b338082bSbellard bs->inserted = 1; 336b338082bSbellard 337b338082bSbellard /* call the change callback */ 338b338082bSbellard if (bs->change_cb) 339b338082bSbellard bs->change_cb(bs->change_opaque); 340b338082bSbellard 341b338082bSbellard return 0; 342fc01f7e7Sbellard } 343fc01f7e7Sbellard 344fc01f7e7Sbellard void bdrv_close(BlockDriverState *bs) 345fc01f7e7Sbellard { 346b338082bSbellard if (bs->inserted) { 347ea2384d3Sbellard if (bs->backing_hd) 348ea2384d3Sbellard bdrv_delete(bs->backing_hd); 349ea2384d3Sbellard bs->drv->bdrv_close(bs); 350ea2384d3Sbellard qemu_free(bs->opaque); 351ea2384d3Sbellard #ifdef _WIN32 352ea2384d3Sbellard if (bs->is_temporary) { 353ea2384d3Sbellard unlink(bs->filename); 354ea2384d3Sbellard } 35567b915a5Sbellard #endif 356ea2384d3Sbellard bs->opaque = NULL; 357ea2384d3Sbellard bs->drv = NULL; 358b338082bSbellard bs->inserted = 0; 359b338082bSbellard 360b338082bSbellard /* call the change callback */ 361b338082bSbellard if (bs->change_cb) 362b338082bSbellard bs->change_cb(bs->change_opaque); 363b338082bSbellard } 364b338082bSbellard } 365b338082bSbellard 366b338082bSbellard void bdrv_delete(BlockDriverState *bs) 367b338082bSbellard { 368ea2384d3Sbellard /* XXX: remove the driver list */ 369b338082bSbellard bdrv_close(bs); 370b338082bSbellard qemu_free(bs); 371fc01f7e7Sbellard } 372fc01f7e7Sbellard 37333e3963eSbellard /* commit COW file into the raw image */ 37433e3963eSbellard int bdrv_commit(BlockDriverState *bs) 37533e3963eSbellard { 37633e3963eSbellard int64_t i; 377ea2384d3Sbellard int n, j; 378ea2384d3Sbellard unsigned char sector[512]; 37933e3963eSbellard 380b338082bSbellard if (!bs->inserted) 381ea2384d3Sbellard return -ENOENT; 38233e3963eSbellard 38333e3963eSbellard if (bs->read_only) { 384ea2384d3Sbellard return -EACCES; 38533e3963eSbellard } 38633e3963eSbellard 387ea2384d3Sbellard if (!bs->backing_hd) { 388ea2384d3Sbellard return -ENOTSUP; 389ea2384d3Sbellard } 390ea2384d3Sbellard 391ea2384d3Sbellard for (i = 0; i < bs->total_sectors;) { 392ea2384d3Sbellard if (bs->drv->bdrv_is_allocated(bs, i, 65536, &n)) { 393ea2384d3Sbellard for(j = 0; j < n; j++) { 39433e3963eSbellard if (bdrv_read(bs, i, sector, 1) != 0) { 395ea2384d3Sbellard return -EIO; 39633e3963eSbellard } 39733e3963eSbellard 398ea2384d3Sbellard if (bdrv_write(bs->backing_hd, i, sector, 1) != 0) { 399ea2384d3Sbellard return -EIO; 40033e3963eSbellard } 401ea2384d3Sbellard i++; 402ea2384d3Sbellard } 403ea2384d3Sbellard } else { 404ea2384d3Sbellard i += n; 40533e3963eSbellard } 40633e3963eSbellard } 40795389c86Sbellard 40895389c86Sbellard if (bs->drv->bdrv_make_empty) 40995389c86Sbellard return bs->drv->bdrv_make_empty(bs); 41095389c86Sbellard 41133e3963eSbellard return 0; 41233e3963eSbellard } 41333e3963eSbellard 414fc01f7e7Sbellard /* return -1 if error */ 415fc01f7e7Sbellard int bdrv_read(BlockDriverState *bs, int64_t sector_num, 416fc01f7e7Sbellard uint8_t *buf, int nb_sectors) 417fc01f7e7Sbellard { 418ea2384d3Sbellard int ret, n; 419ea2384d3Sbellard BlockDriver *drv = bs->drv; 420fc01f7e7Sbellard 421b338082bSbellard if (!bs->inserted) 422b338082bSbellard return -1; 423b338082bSbellard 42433e3963eSbellard while (nb_sectors > 0) { 425ea2384d3Sbellard if (sector_num == 0 && bs->boot_sector_enabled) { 426cf98951bSbellard memcpy(buf, bs->boot_sector_data, 512); 427cf98951bSbellard n = 1; 428ea2384d3Sbellard } else if (bs->backing_hd) { 429ea2384d3Sbellard if (drv->bdrv_is_allocated(bs, sector_num, nb_sectors, &n)) { 430ea2384d3Sbellard ret = drv->bdrv_read(bs, sector_num, buf, n); 431ea2384d3Sbellard if (ret < 0) 432ea2384d3Sbellard return -1; 43333e3963eSbellard } else { 434ea2384d3Sbellard /* read from the base image */ 435ea2384d3Sbellard ret = bdrv_read(bs->backing_hd, sector_num, buf, n); 436ea2384d3Sbellard if (ret < 0) 437fc01f7e7Sbellard return -1; 43833e3963eSbellard } 439ea2384d3Sbellard } else { 440ea2384d3Sbellard ret = drv->bdrv_read(bs, sector_num, buf, nb_sectors); 441ea2384d3Sbellard if (ret < 0) 442ea2384d3Sbellard return -1; 443ea2384d3Sbellard /* no need to loop */ 444ea2384d3Sbellard break; 44533e3963eSbellard } 44633e3963eSbellard nb_sectors -= n; 44733e3963eSbellard sector_num += n; 44833e3963eSbellard buf += n * 512; 44933e3963eSbellard } 450fc01f7e7Sbellard return 0; 451fc01f7e7Sbellard } 452fc01f7e7Sbellard 453fc01f7e7Sbellard /* return -1 if error */ 454fc01f7e7Sbellard int bdrv_write(BlockDriverState *bs, int64_t sector_num, 455fc01f7e7Sbellard const uint8_t *buf, int nb_sectors) 456fc01f7e7Sbellard { 457b338082bSbellard if (!bs->inserted) 458b338082bSbellard return -1; 4590849bf08Sbellard if (bs->read_only) 4600849bf08Sbellard return -1; 46179639d42Sbellard if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { 46279639d42Sbellard memcpy(bs->boot_sector_data, buf, 512); 46379639d42Sbellard } 464ea2384d3Sbellard return bs->drv->bdrv_write(bs, sector_num, buf, nb_sectors); 465fc01f7e7Sbellard } 466fc01f7e7Sbellard 467fc01f7e7Sbellard void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr) 468fc01f7e7Sbellard { 469fc01f7e7Sbellard *nb_sectors_ptr = bs->total_sectors; 470fc01f7e7Sbellard } 471cf98951bSbellard 472cf98951bSbellard /* force a given boot sector. */ 473cf98951bSbellard void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size) 474cf98951bSbellard { 475cf98951bSbellard bs->boot_sector_enabled = 1; 476cf98951bSbellard if (size > 512) 477cf98951bSbellard size = 512; 478cf98951bSbellard memcpy(bs->boot_sector_data, data, size); 479cf98951bSbellard memset(bs->boot_sector_data + size, 0, 512 - size); 480cf98951bSbellard } 481b338082bSbellard 482b338082bSbellard void bdrv_set_geometry_hint(BlockDriverState *bs, 483b338082bSbellard int cyls, int heads, int secs) 484b338082bSbellard { 485b338082bSbellard bs->cyls = cyls; 486b338082bSbellard bs->heads = heads; 487b338082bSbellard bs->secs = secs; 488b338082bSbellard } 489b338082bSbellard 490b338082bSbellard void bdrv_set_type_hint(BlockDriverState *bs, int type) 491b338082bSbellard { 492b338082bSbellard bs->type = type; 493b338082bSbellard bs->removable = ((type == BDRV_TYPE_CDROM || 494b338082bSbellard type == BDRV_TYPE_FLOPPY)); 495b338082bSbellard } 496b338082bSbellard 49746d4767dSbellard void bdrv_set_translation_hint(BlockDriverState *bs, int translation) 49846d4767dSbellard { 49946d4767dSbellard bs->translation = translation; 50046d4767dSbellard } 50146d4767dSbellard 502b338082bSbellard void bdrv_get_geometry_hint(BlockDriverState *bs, 503b338082bSbellard int *pcyls, int *pheads, int *psecs) 504b338082bSbellard { 505b338082bSbellard *pcyls = bs->cyls; 506b338082bSbellard *pheads = bs->heads; 507b338082bSbellard *psecs = bs->secs; 508b338082bSbellard } 509b338082bSbellard 510b338082bSbellard int bdrv_get_type_hint(BlockDriverState *bs) 511b338082bSbellard { 512b338082bSbellard return bs->type; 513b338082bSbellard } 514b338082bSbellard 51546d4767dSbellard int bdrv_get_translation_hint(BlockDriverState *bs) 51646d4767dSbellard { 51746d4767dSbellard return bs->translation; 51846d4767dSbellard } 51946d4767dSbellard 520b338082bSbellard int bdrv_is_removable(BlockDriverState *bs) 521b338082bSbellard { 522b338082bSbellard return bs->removable; 523b338082bSbellard } 524b338082bSbellard 525b338082bSbellard int bdrv_is_read_only(BlockDriverState *bs) 526b338082bSbellard { 527b338082bSbellard return bs->read_only; 528b338082bSbellard } 529b338082bSbellard 530b338082bSbellard int bdrv_is_inserted(BlockDriverState *bs) 531b338082bSbellard { 532b338082bSbellard return bs->inserted; 533b338082bSbellard } 534b338082bSbellard 535b338082bSbellard int bdrv_is_locked(BlockDriverState *bs) 536b338082bSbellard { 537b338082bSbellard return bs->locked; 538b338082bSbellard } 539b338082bSbellard 540b338082bSbellard void bdrv_set_locked(BlockDriverState *bs, int locked) 541b338082bSbellard { 542b338082bSbellard bs->locked = locked; 543b338082bSbellard } 544b338082bSbellard 545b338082bSbellard void bdrv_set_change_cb(BlockDriverState *bs, 546b338082bSbellard void (*change_cb)(void *opaque), void *opaque) 547b338082bSbellard { 548b338082bSbellard bs->change_cb = change_cb; 549b338082bSbellard bs->change_opaque = opaque; 550b338082bSbellard } 551b338082bSbellard 552ea2384d3Sbellard int bdrv_is_encrypted(BlockDriverState *bs) 553ea2384d3Sbellard { 554ea2384d3Sbellard if (bs->backing_hd && bs->backing_hd->encrypted) 555ea2384d3Sbellard return 1; 556ea2384d3Sbellard return bs->encrypted; 557ea2384d3Sbellard } 558ea2384d3Sbellard 559ea2384d3Sbellard int bdrv_set_key(BlockDriverState *bs, const char *key) 560ea2384d3Sbellard { 561ea2384d3Sbellard int ret; 562ea2384d3Sbellard if (bs->backing_hd && bs->backing_hd->encrypted) { 563ea2384d3Sbellard ret = bdrv_set_key(bs->backing_hd, key); 564ea2384d3Sbellard if (ret < 0) 565ea2384d3Sbellard return ret; 566ea2384d3Sbellard if (!bs->encrypted) 567ea2384d3Sbellard return 0; 568ea2384d3Sbellard } 569ea2384d3Sbellard if (!bs->encrypted || !bs->drv || !bs->drv->bdrv_set_key) 570ea2384d3Sbellard return -1; 571ea2384d3Sbellard return bs->drv->bdrv_set_key(bs, key); 572ea2384d3Sbellard } 573ea2384d3Sbellard 574ea2384d3Sbellard void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size) 575ea2384d3Sbellard { 576ea2384d3Sbellard if (!bs->inserted || !bs->drv) { 577ea2384d3Sbellard buf[0] = '\0'; 578ea2384d3Sbellard } else { 579ea2384d3Sbellard pstrcpy(buf, buf_size, bs->drv->format_name); 580ea2384d3Sbellard } 581ea2384d3Sbellard } 582ea2384d3Sbellard 583ea2384d3Sbellard void bdrv_iterate_format(void (*it)(void *opaque, const char *name), 584ea2384d3Sbellard void *opaque) 585ea2384d3Sbellard { 586ea2384d3Sbellard BlockDriver *drv; 587ea2384d3Sbellard 588ea2384d3Sbellard for (drv = first_drv; drv != NULL; drv = drv->next) { 589ea2384d3Sbellard it(opaque, drv->format_name); 590ea2384d3Sbellard } 591ea2384d3Sbellard } 592ea2384d3Sbellard 593b338082bSbellard BlockDriverState *bdrv_find(const char *name) 594b338082bSbellard { 595b338082bSbellard BlockDriverState *bs; 596b338082bSbellard 597b338082bSbellard for (bs = bdrv_first; bs != NULL; bs = bs->next) { 598b338082bSbellard if (!strcmp(name, bs->device_name)) 599b338082bSbellard return bs; 600b338082bSbellard } 601b338082bSbellard return NULL; 602b338082bSbellard } 603b338082bSbellard 60481d0912dSbellard void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque) 60581d0912dSbellard { 60681d0912dSbellard BlockDriverState *bs; 60781d0912dSbellard 60881d0912dSbellard for (bs = bdrv_first; bs != NULL; bs = bs->next) { 60981d0912dSbellard it(opaque, bs->device_name); 61081d0912dSbellard } 61181d0912dSbellard } 61281d0912dSbellard 613ea2384d3Sbellard const char *bdrv_get_device_name(BlockDriverState *bs) 614ea2384d3Sbellard { 615ea2384d3Sbellard return bs->device_name; 616ea2384d3Sbellard } 617ea2384d3Sbellard 618b338082bSbellard void bdrv_info(void) 619b338082bSbellard { 620b338082bSbellard BlockDriverState *bs; 621b338082bSbellard 622b338082bSbellard for (bs = bdrv_first; bs != NULL; bs = bs->next) { 623b338082bSbellard term_printf("%s:", bs->device_name); 624b338082bSbellard term_printf(" type="); 625b338082bSbellard switch(bs->type) { 626b338082bSbellard case BDRV_TYPE_HD: 627b338082bSbellard term_printf("hd"); 628b338082bSbellard break; 629b338082bSbellard case BDRV_TYPE_CDROM: 630b338082bSbellard term_printf("cdrom"); 631b338082bSbellard break; 632b338082bSbellard case BDRV_TYPE_FLOPPY: 633b338082bSbellard term_printf("floppy"); 634b338082bSbellard break; 635b338082bSbellard } 636b338082bSbellard term_printf(" removable=%d", bs->removable); 637b338082bSbellard if (bs->removable) { 638b338082bSbellard term_printf(" locked=%d", bs->locked); 639b338082bSbellard } 640b338082bSbellard if (bs->inserted) { 641b338082bSbellard term_printf(" file=%s", bs->filename); 642ea2384d3Sbellard if (bs->backing_file[0] != '\0') 643ea2384d3Sbellard term_printf(" backing_file=%s", bs->backing_file); 644b338082bSbellard term_printf(" ro=%d", bs->read_only); 645ea2384d3Sbellard term_printf(" drv=%s", bs->drv->format_name); 646ea2384d3Sbellard if (bs->encrypted) 647ea2384d3Sbellard term_printf(" encrypted"); 648b338082bSbellard } else { 649b338082bSbellard term_printf(" [not inserted]"); 650b338082bSbellard } 651b338082bSbellard term_printf("\n"); 652b338082bSbellard } 653b338082bSbellard } 654ea2384d3Sbellard 655ea2384d3Sbellard /**************************************************************/ 656ea2384d3Sbellard /* RAW block driver */ 657ea2384d3Sbellard 658ea2384d3Sbellard typedef struct BDRVRawState { 659ea2384d3Sbellard int fd; 660ea2384d3Sbellard } BDRVRawState; 661ea2384d3Sbellard 662ea2384d3Sbellard static int raw_probe(const uint8_t *buf, int buf_size, const char *filename) 663ea2384d3Sbellard { 664ea2384d3Sbellard return 1; /* maybe */ 665ea2384d3Sbellard } 666ea2384d3Sbellard 667ea2384d3Sbellard static int raw_open(BlockDriverState *bs, const char *filename) 668ea2384d3Sbellard { 669ea2384d3Sbellard BDRVRawState *s = bs->opaque; 670ea2384d3Sbellard int fd; 671ea2384d3Sbellard int64_t size; 672e5484d33Sbellard #ifdef _BSD 673e5484d33Sbellard struct stat sb; 674e5484d33Sbellard #endif 675*ec530c81Sbellard #ifdef __sun__ 676*ec530c81Sbellard struct dk_minfo minfo; 677*ec530c81Sbellard int rv; 678*ec530c81Sbellard #endif 679ea2384d3Sbellard 680ea2384d3Sbellard fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); 681ea2384d3Sbellard if (fd < 0) { 682ea2384d3Sbellard fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); 683ea2384d3Sbellard if (fd < 0) 684ea2384d3Sbellard return -1; 685ea2384d3Sbellard bs->read_only = 1; 686ea2384d3Sbellard } 6877674e7bfSbellard #ifdef _BSD 6887674e7bfSbellard if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) { 6897674e7bfSbellard #ifdef DIOCGMEDIASIZE 6907674e7bfSbellard if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size)) 6917674e7bfSbellard #endif 6923b0d4f61Sbellard #ifdef CONFIG_COCOA 6933b0d4f61Sbellard size = LONG_LONG_MAX; 6943b0d4f61Sbellard #else 6957674e7bfSbellard size = lseek(fd, 0LL, SEEK_END); 6963b0d4f61Sbellard #endif 6977674e7bfSbellard } else 6987674e7bfSbellard #endif 699*ec530c81Sbellard #ifdef __sun__ 700*ec530c81Sbellard /* 701*ec530c81Sbellard * use the DKIOCGMEDIAINFO ioctl to read the size. 702*ec530c81Sbellard */ 703*ec530c81Sbellard rv = ioctl ( fd, DKIOCGMEDIAINFO, &minfo ); 704*ec530c81Sbellard if ( rv != -1 ) { 705*ec530c81Sbellard size = minfo.dki_lbsize * minfo.dki_capacity; 706*ec530c81Sbellard } else /* there are reports that lseek on some devices 707*ec530c81Sbellard fails, but irc discussion said that contingency 708*ec530c81Sbellard on contingency was overkill */ 709*ec530c81Sbellard #endif 7107674e7bfSbellard { 711d5249393Sbellard size = lseek(fd, 0, SEEK_END); 7127674e7bfSbellard } 713c747cd1fSbellard #ifdef _WIN32 714c747cd1fSbellard /* On Windows hosts it can happen that we're unable to get file size 715c747cd1fSbellard for CD-ROM raw device (it's inherent limitation of the CDFS driver). */ 716c747cd1fSbellard if (size == -1) 717c747cd1fSbellard size = LONG_LONG_MAX; 718c747cd1fSbellard #endif 719ea2384d3Sbellard bs->total_sectors = size / 512; 720ea2384d3Sbellard s->fd = fd; 721ea2384d3Sbellard return 0; 722ea2384d3Sbellard } 723ea2384d3Sbellard 724ea2384d3Sbellard static int raw_read(BlockDriverState *bs, int64_t sector_num, 725ea2384d3Sbellard uint8_t *buf, int nb_sectors) 726ea2384d3Sbellard { 727ea2384d3Sbellard BDRVRawState *s = bs->opaque; 728ea2384d3Sbellard int ret; 729ea2384d3Sbellard 730d5249393Sbellard lseek(s->fd, sector_num * 512, SEEK_SET); 731ea2384d3Sbellard ret = read(s->fd, buf, nb_sectors * 512); 732ea2384d3Sbellard if (ret != nb_sectors * 512) 733ea2384d3Sbellard return -1; 734ea2384d3Sbellard return 0; 735ea2384d3Sbellard } 736ea2384d3Sbellard 737ea2384d3Sbellard static int raw_write(BlockDriverState *bs, int64_t sector_num, 738ea2384d3Sbellard const uint8_t *buf, int nb_sectors) 739ea2384d3Sbellard { 740ea2384d3Sbellard BDRVRawState *s = bs->opaque; 741ea2384d3Sbellard int ret; 742ea2384d3Sbellard 743d5249393Sbellard lseek(s->fd, sector_num * 512, SEEK_SET); 744ea2384d3Sbellard ret = write(s->fd, buf, nb_sectors * 512); 745ea2384d3Sbellard if (ret != nb_sectors * 512) 746ea2384d3Sbellard return -1; 747ea2384d3Sbellard return 0; 748ea2384d3Sbellard } 749ea2384d3Sbellard 750e2731addSbellard static void raw_close(BlockDriverState *bs) 751ea2384d3Sbellard { 752ea2384d3Sbellard BDRVRawState *s = bs->opaque; 753ea2384d3Sbellard close(s->fd); 754ea2384d3Sbellard } 755ea2384d3Sbellard 756ea2384d3Sbellard static int raw_create(const char *filename, int64_t total_size, 757ea2384d3Sbellard const char *backing_file, int flags) 758ea2384d3Sbellard { 759ea2384d3Sbellard int fd; 760ea2384d3Sbellard 761ea2384d3Sbellard if (flags || backing_file) 762ea2384d3Sbellard return -ENOTSUP; 763ea2384d3Sbellard 764ea2384d3Sbellard fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 765ea2384d3Sbellard 0644); 766ea2384d3Sbellard if (fd < 0) 767ea2384d3Sbellard return -EIO; 768d5249393Sbellard ftruncate(fd, total_size * 512); 769ea2384d3Sbellard close(fd); 770ea2384d3Sbellard return 0; 771ea2384d3Sbellard } 772ea2384d3Sbellard 773ea2384d3Sbellard BlockDriver bdrv_raw = { 774ea2384d3Sbellard "raw", 775ea2384d3Sbellard sizeof(BDRVRawState), 776ea2384d3Sbellard raw_probe, 777ea2384d3Sbellard raw_open, 778ea2384d3Sbellard raw_read, 779ea2384d3Sbellard raw_write, 780ea2384d3Sbellard raw_close, 781ea2384d3Sbellard raw_create, 782ea2384d3Sbellard }; 783ea2384d3Sbellard 784ea2384d3Sbellard void bdrv_init(void) 785ea2384d3Sbellard { 786ea2384d3Sbellard bdrv_register(&bdrv_raw); 787ea2384d3Sbellard #ifndef _WIN32 788ea2384d3Sbellard bdrv_register(&bdrv_cow); 789ea2384d3Sbellard #endif 790ea2384d3Sbellard bdrv_register(&bdrv_qcow); 791ea2384d3Sbellard bdrv_register(&bdrv_vmdk); 7923c56521bSbellard bdrv_register(&bdrv_cloop); 793585d0ed9Sbellard bdrv_register(&bdrv_dmg); 794a8753c34Sbellard bdrv_register(&bdrv_bochs); 7956a0f9e82Sbellard bdrv_register(&bdrv_vpc); 796712e7874Sbellard bdrv_register(&bdrv_vvfat); 797ea2384d3Sbellard } 798