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 47b338082bSbellard static BlockDriverState *bdrv_first; 48ea2384d3Sbellard static BlockDriver *first_drv; 49ea2384d3Sbellard 503b0d4f61Sbellard #ifdef CONFIG_COCOA 513b0d4f61Sbellard static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator ); 523b0d4f61Sbellard static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize ); 533b0d4f61Sbellard 543b0d4f61Sbellard kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator ) 553b0d4f61Sbellard { 563b0d4f61Sbellard kern_return_t kernResult; 573b0d4f61Sbellard mach_port_t masterPort; 583b0d4f61Sbellard CFMutableDictionaryRef classesToMatch; 593b0d4f61Sbellard 603b0d4f61Sbellard kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort ); 613b0d4f61Sbellard if ( KERN_SUCCESS != kernResult ) { 623b0d4f61Sbellard printf( "IOMasterPort returned %d\n", kernResult ); 633b0d4f61Sbellard } 643b0d4f61Sbellard 653b0d4f61Sbellard classesToMatch = IOServiceMatching( kIOCDMediaClass ); 663b0d4f61Sbellard if ( classesToMatch == NULL ) { 673b0d4f61Sbellard printf( "IOServiceMatching returned a NULL dictionary.\n" ); 683b0d4f61Sbellard } else { 693b0d4f61Sbellard CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue ); 703b0d4f61Sbellard } 713b0d4f61Sbellard kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, mediaIterator ); 723b0d4f61Sbellard if ( KERN_SUCCESS != kernResult ) 733b0d4f61Sbellard { 743b0d4f61Sbellard printf( "IOServiceGetMatchingServices returned %d\n", kernResult ); 753b0d4f61Sbellard } 763b0d4f61Sbellard 773b0d4f61Sbellard return kernResult; 783b0d4f61Sbellard } 793b0d4f61Sbellard 803b0d4f61Sbellard kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize ) 813b0d4f61Sbellard { 823b0d4f61Sbellard io_object_t nextMedia; 833b0d4f61Sbellard kern_return_t kernResult = KERN_FAILURE; 843b0d4f61Sbellard *bsdPath = '\0'; 853b0d4f61Sbellard nextMedia = IOIteratorNext( mediaIterator ); 863b0d4f61Sbellard if ( nextMedia ) 873b0d4f61Sbellard { 883b0d4f61Sbellard CFTypeRef bsdPathAsCFString; 893b0d4f61Sbellard bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia, CFSTR( kIOBSDNameKey ), kCFAllocatorDefault, 0 ); 903b0d4f61Sbellard if ( bsdPathAsCFString ) { 913b0d4f61Sbellard size_t devPathLength; 923b0d4f61Sbellard strcpy( bsdPath, _PATH_DEV ); 933b0d4f61Sbellard strcat( bsdPath, "r" ); 943b0d4f61Sbellard devPathLength = strlen( bsdPath ); 953b0d4f61Sbellard if ( CFStringGetCString( bsdPathAsCFString, bsdPath + devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) { 963b0d4f61Sbellard kernResult = KERN_SUCCESS; 973b0d4f61Sbellard } 983b0d4f61Sbellard CFRelease( bsdPathAsCFString ); 993b0d4f61Sbellard } 1003b0d4f61Sbellard IOObjectRelease( nextMedia ); 1013b0d4f61Sbellard } 1023b0d4f61Sbellard 1033b0d4f61Sbellard return kernResult; 1043b0d4f61Sbellard } 1053b0d4f61Sbellard 1063b0d4f61Sbellard #endif 1073b0d4f61Sbellard 108ea2384d3Sbellard void bdrv_register(BlockDriver *bdrv) 109ea2384d3Sbellard { 110ea2384d3Sbellard bdrv->next = first_drv; 111ea2384d3Sbellard first_drv = bdrv; 112ea2384d3Sbellard } 113b338082bSbellard 114b338082bSbellard /* create a new block device (by default it is empty) */ 115b338082bSbellard BlockDriverState *bdrv_new(const char *device_name) 116fc01f7e7Sbellard { 117b338082bSbellard BlockDriverState **pbs, *bs; 118b338082bSbellard 119b338082bSbellard bs = qemu_mallocz(sizeof(BlockDriverState)); 120b338082bSbellard if(!bs) 121b338082bSbellard return NULL; 122b338082bSbellard pstrcpy(bs->device_name, sizeof(bs->device_name), device_name); 123ea2384d3Sbellard if (device_name[0] != '\0') { 124b338082bSbellard /* insert at the end */ 125b338082bSbellard pbs = &bdrv_first; 126b338082bSbellard while (*pbs != NULL) 127b338082bSbellard pbs = &(*pbs)->next; 128b338082bSbellard *pbs = bs; 129ea2384d3Sbellard } 130b338082bSbellard return bs; 131b338082bSbellard } 132b338082bSbellard 133ea2384d3Sbellard BlockDriver *bdrv_find_format(const char *format_name) 134ea2384d3Sbellard { 135ea2384d3Sbellard BlockDriver *drv1; 136ea2384d3Sbellard for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) { 137ea2384d3Sbellard if (!strcmp(drv1->format_name, format_name)) 138ea2384d3Sbellard return drv1; 139ea2384d3Sbellard } 140ea2384d3Sbellard return NULL; 141ea2384d3Sbellard } 142ea2384d3Sbellard 143ea2384d3Sbellard int bdrv_create(BlockDriver *drv, 144ea2384d3Sbellard const char *filename, int64_t size_in_sectors, 145ea2384d3Sbellard const char *backing_file, int flags) 146ea2384d3Sbellard { 147ea2384d3Sbellard if (!drv->bdrv_create) 148ea2384d3Sbellard return -ENOTSUP; 149ea2384d3Sbellard return drv->bdrv_create(filename, size_in_sectors, backing_file, flags); 150ea2384d3Sbellard } 151ea2384d3Sbellard 152d5249393Sbellard #ifdef _WIN32 153*95389c86Sbellard void get_tmp_filename(char *filename, int size) 154d5249393Sbellard { 155*95389c86Sbellard char* p = strrchr(filename, '/'); 156*95389c86Sbellard 157*95389c86Sbellard if (p == NULL) 158*95389c86Sbellard return; 159*95389c86Sbellard 160d5249393Sbellard /* XXX: find a better function */ 161*95389c86Sbellard tmpnam(p); 162*95389c86Sbellard *p = '/'; 163d5249393Sbellard } 164d5249393Sbellard #else 165*95389c86Sbellard void get_tmp_filename(char *filename, int size) 166ea2384d3Sbellard { 167ea2384d3Sbellard int fd; 168d5249393Sbellard /* XXX: race condition possible */ 169ea2384d3Sbellard pstrcpy(filename, size, "/tmp/vl.XXXXXX"); 170ea2384d3Sbellard fd = mkstemp(filename); 171ea2384d3Sbellard close(fd); 172ea2384d3Sbellard } 173d5249393Sbellard #endif 174ea2384d3Sbellard 1757674e7bfSbellard /* XXX: force raw format if block or character device ? It would 1767674e7bfSbellard simplify the BSD case */ 177ea2384d3Sbellard static BlockDriver *find_image_format(const char *filename) 178ea2384d3Sbellard { 179ea2384d3Sbellard int fd, ret, score, score_max; 180ea2384d3Sbellard BlockDriver *drv1, *drv; 1817674e7bfSbellard uint8_t *buf; 1827674e7bfSbellard size_t bufsize = 1024; 183ea2384d3Sbellard 184ea2384d3Sbellard fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); 185712e7874Sbellard if (fd < 0) { 186712e7874Sbellard buf = NULL; 187712e7874Sbellard ret = 0; 188712e7874Sbellard } else { 1897674e7bfSbellard #ifdef DIOCGSECTORSIZE 1907674e7bfSbellard { 1917674e7bfSbellard unsigned int sectorsize = 512; 1927674e7bfSbellard if (!ioctl(fd, DIOCGSECTORSIZE, §orsize) && 1937674e7bfSbellard sectorsize > bufsize) 1947674e7bfSbellard bufsize = sectorsize; 1957674e7bfSbellard } 1967674e7bfSbellard #endif 1973b0d4f61Sbellard #ifdef CONFIG_COCOA 1983b0d4f61Sbellard u_int32_t blockSize = 512; 1993b0d4f61Sbellard if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize > bufsize) { 2003b0d4f61Sbellard bufsize = blockSize; 2013b0d4f61Sbellard } 2023b0d4f61Sbellard #endif 203712e7874Sbellard buf = qemu_malloc(bufsize); 2047674e7bfSbellard if (!buf) 2057674e7bfSbellard return NULL; 2067674e7bfSbellard ret = read(fd, buf, bufsize); 207ea2384d3Sbellard if (ret < 0) { 208ea2384d3Sbellard close(fd); 209712e7874Sbellard qemu_free(buf); 210ea2384d3Sbellard return NULL; 211ea2384d3Sbellard } 212ea2384d3Sbellard close(fd); 213712e7874Sbellard } 214ea2384d3Sbellard 215ea2384d3Sbellard drv = NULL; 216ea2384d3Sbellard score_max = 0; 217ea2384d3Sbellard for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) { 218ea2384d3Sbellard score = drv1->bdrv_probe(buf, ret, filename); 219ea2384d3Sbellard if (score > score_max) { 220ea2384d3Sbellard score_max = score; 221ea2384d3Sbellard drv = drv1; 222ea2384d3Sbellard } 223ea2384d3Sbellard } 224712e7874Sbellard qemu_free(buf); 225ea2384d3Sbellard return drv; 226ea2384d3Sbellard } 227ea2384d3Sbellard 228b338082bSbellard int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) 229b338082bSbellard { 2303b0d4f61Sbellard #ifdef CONFIG_COCOA 2313b0d4f61Sbellard if ( strncmp( filename, "/dev/cdrom", 10 ) == 0 ) { 2323b0d4f61Sbellard kern_return_t kernResult; 2333b0d4f61Sbellard io_iterator_t mediaIterator; 2343b0d4f61Sbellard char bsdPath[ MAXPATHLEN ]; 2353b0d4f61Sbellard int fd; 2363b0d4f61Sbellard 2373b0d4f61Sbellard kernResult = FindEjectableCDMedia( &mediaIterator ); 2383b0d4f61Sbellard kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) ); 2393b0d4f61Sbellard 2403b0d4f61Sbellard if ( bsdPath[ 0 ] != '\0' ) { 2413b0d4f61Sbellard strcat(bsdPath,"s0"); 2423b0d4f61Sbellard /* some CDs don't have a partition 0 */ 2433b0d4f61Sbellard fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE); 2443b0d4f61Sbellard if (fd < 0) { 2453b0d4f61Sbellard bsdPath[strlen(bsdPath)-1] = '1'; 2463b0d4f61Sbellard } else { 2473b0d4f61Sbellard close(fd); 2483b0d4f61Sbellard } 2493b0d4f61Sbellard filename = bsdPath; 2503b0d4f61Sbellard } 2513b0d4f61Sbellard 2523b0d4f61Sbellard if ( mediaIterator ) 2533b0d4f61Sbellard IOObjectRelease( mediaIterator ); 2543b0d4f61Sbellard } 2553b0d4f61Sbellard #endif 256ea2384d3Sbellard return bdrv_open2(bs, filename, snapshot, NULL); 257ea2384d3Sbellard } 258ea2384d3Sbellard 259ea2384d3Sbellard int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot, 260ea2384d3Sbellard BlockDriver *drv) 261ea2384d3Sbellard { 262ea2384d3Sbellard int ret; 263ea2384d3Sbellard char tmp_filename[1024]; 264fc01f7e7Sbellard 2650849bf08Sbellard bs->read_only = 0; 266ea2384d3Sbellard bs->is_temporary = 0; 267ea2384d3Sbellard bs->encrypted = 0; 26833e3963eSbellard 26933e3963eSbellard if (snapshot) { 270ea2384d3Sbellard BlockDriverState *bs1; 271ea2384d3Sbellard int64_t total_size; 27233e3963eSbellard 273ea2384d3Sbellard /* if snapshot, we create a temporary backing file and open it 274ea2384d3Sbellard instead of opening 'filename' directly */ 275ea2384d3Sbellard 276ea2384d3Sbellard /* if there is a backing file, use it */ 277ea2384d3Sbellard bs1 = bdrv_new(""); 278ea2384d3Sbellard if (!bs1) { 279ea2384d3Sbellard return -1; 280ea2384d3Sbellard } 281ea2384d3Sbellard if (bdrv_open(bs1, filename, 0) < 0) { 282ea2384d3Sbellard bdrv_delete(bs1); 283ea2384d3Sbellard return -1; 284ea2384d3Sbellard } 285ea2384d3Sbellard total_size = bs1->total_sectors; 286ea2384d3Sbellard bdrv_delete(bs1); 287ea2384d3Sbellard 288ea2384d3Sbellard get_tmp_filename(tmp_filename, sizeof(tmp_filename)); 289ea2384d3Sbellard /* XXX: use cow for linux as it is more efficient ? */ 290ea2384d3Sbellard if (bdrv_create(&bdrv_qcow, tmp_filename, 291ea2384d3Sbellard total_size, filename, 0) < 0) { 292ea2384d3Sbellard return -1; 293ea2384d3Sbellard } 294ea2384d3Sbellard filename = tmp_filename; 295ea2384d3Sbellard bs->is_temporary = 1; 296ea2384d3Sbellard } 297ea2384d3Sbellard 298ea2384d3Sbellard pstrcpy(bs->filename, sizeof(bs->filename), filename); 299ea2384d3Sbellard if (!drv) { 300ea2384d3Sbellard drv = find_image_format(filename); 301ea2384d3Sbellard if (!drv) 302ea2384d3Sbellard return -1; 303ea2384d3Sbellard } 304ea2384d3Sbellard bs->drv = drv; 305ea2384d3Sbellard bs->opaque = qemu_mallocz(drv->instance_size); 306ea2384d3Sbellard if (bs->opaque == NULL && drv->instance_size > 0) 307ea2384d3Sbellard return -1; 308ea2384d3Sbellard 309ea2384d3Sbellard ret = drv->bdrv_open(bs, filename); 310ea2384d3Sbellard if (ret < 0) { 311ea2384d3Sbellard qemu_free(bs->opaque); 312ea2384d3Sbellard return -1; 313ea2384d3Sbellard } 314ea2384d3Sbellard #ifndef _WIN32 315ea2384d3Sbellard if (bs->is_temporary) { 316ea2384d3Sbellard unlink(filename); 31733e3963eSbellard } 31867b915a5Sbellard #endif 319ea2384d3Sbellard if (bs->backing_file[0] != '\0' && drv->bdrv_is_allocated) { 320ea2384d3Sbellard /* if there is a backing file, use it */ 321ea2384d3Sbellard bs->backing_hd = bdrv_new(""); 322ea2384d3Sbellard if (!bs->backing_hd) { 323ea2384d3Sbellard fail: 324ea2384d3Sbellard bdrv_close(bs); 325ea2384d3Sbellard return -1; 326ea2384d3Sbellard } 327ea2384d3Sbellard if (bdrv_open(bs->backing_hd, bs->backing_file, 0) < 0) 328ea2384d3Sbellard goto fail; 329ea2384d3Sbellard } 33033e3963eSbellard 331b338082bSbellard bs->inserted = 1; 332b338082bSbellard 333b338082bSbellard /* call the change callback */ 334b338082bSbellard if (bs->change_cb) 335b338082bSbellard bs->change_cb(bs->change_opaque); 336b338082bSbellard 337b338082bSbellard return 0; 338fc01f7e7Sbellard } 339fc01f7e7Sbellard 340fc01f7e7Sbellard void bdrv_close(BlockDriverState *bs) 341fc01f7e7Sbellard { 342b338082bSbellard if (bs->inserted) { 343ea2384d3Sbellard if (bs->backing_hd) 344ea2384d3Sbellard bdrv_delete(bs->backing_hd); 345ea2384d3Sbellard bs->drv->bdrv_close(bs); 346ea2384d3Sbellard qemu_free(bs->opaque); 347ea2384d3Sbellard #ifdef _WIN32 348ea2384d3Sbellard if (bs->is_temporary) { 349ea2384d3Sbellard unlink(bs->filename); 350ea2384d3Sbellard } 35167b915a5Sbellard #endif 352ea2384d3Sbellard bs->opaque = NULL; 353ea2384d3Sbellard bs->drv = NULL; 354b338082bSbellard bs->inserted = 0; 355b338082bSbellard 356b338082bSbellard /* call the change callback */ 357b338082bSbellard if (bs->change_cb) 358b338082bSbellard bs->change_cb(bs->change_opaque); 359b338082bSbellard } 360b338082bSbellard } 361b338082bSbellard 362b338082bSbellard void bdrv_delete(BlockDriverState *bs) 363b338082bSbellard { 364ea2384d3Sbellard /* XXX: remove the driver list */ 365b338082bSbellard bdrv_close(bs); 366b338082bSbellard qemu_free(bs); 367fc01f7e7Sbellard } 368fc01f7e7Sbellard 36933e3963eSbellard /* commit COW file into the raw image */ 37033e3963eSbellard int bdrv_commit(BlockDriverState *bs) 37133e3963eSbellard { 37233e3963eSbellard int64_t i; 373ea2384d3Sbellard int n, j; 374ea2384d3Sbellard unsigned char sector[512]; 37533e3963eSbellard 376b338082bSbellard if (!bs->inserted) 377ea2384d3Sbellard return -ENOENT; 37833e3963eSbellard 37933e3963eSbellard if (bs->read_only) { 380ea2384d3Sbellard return -EACCES; 38133e3963eSbellard } 38233e3963eSbellard 383ea2384d3Sbellard if (!bs->backing_hd) { 384ea2384d3Sbellard return -ENOTSUP; 385ea2384d3Sbellard } 386ea2384d3Sbellard 387ea2384d3Sbellard for (i = 0; i < bs->total_sectors;) { 388ea2384d3Sbellard if (bs->drv->bdrv_is_allocated(bs, i, 65536, &n)) { 389ea2384d3Sbellard for(j = 0; j < n; j++) { 39033e3963eSbellard if (bdrv_read(bs, i, sector, 1) != 0) { 391ea2384d3Sbellard return -EIO; 39233e3963eSbellard } 39333e3963eSbellard 394ea2384d3Sbellard if (bdrv_write(bs->backing_hd, i, sector, 1) != 0) { 395ea2384d3Sbellard return -EIO; 39633e3963eSbellard } 397ea2384d3Sbellard i++; 398ea2384d3Sbellard } 399ea2384d3Sbellard } else { 400ea2384d3Sbellard i += n; 40133e3963eSbellard } 40233e3963eSbellard } 403*95389c86Sbellard 404*95389c86Sbellard if (bs->drv->bdrv_make_empty) 405*95389c86Sbellard return bs->drv->bdrv_make_empty(bs); 406*95389c86Sbellard 40733e3963eSbellard return 0; 40833e3963eSbellard } 40933e3963eSbellard 410fc01f7e7Sbellard /* return -1 if error */ 411fc01f7e7Sbellard int bdrv_read(BlockDriverState *bs, int64_t sector_num, 412fc01f7e7Sbellard uint8_t *buf, int nb_sectors) 413fc01f7e7Sbellard { 414ea2384d3Sbellard int ret, n; 415ea2384d3Sbellard BlockDriver *drv = bs->drv; 416fc01f7e7Sbellard 417b338082bSbellard if (!bs->inserted) 418b338082bSbellard return -1; 419b338082bSbellard 42033e3963eSbellard while (nb_sectors > 0) { 421ea2384d3Sbellard if (sector_num == 0 && bs->boot_sector_enabled) { 422cf98951bSbellard memcpy(buf, bs->boot_sector_data, 512); 423cf98951bSbellard n = 1; 424ea2384d3Sbellard } else if (bs->backing_hd) { 425ea2384d3Sbellard if (drv->bdrv_is_allocated(bs, sector_num, nb_sectors, &n)) { 426ea2384d3Sbellard ret = drv->bdrv_read(bs, sector_num, buf, n); 427ea2384d3Sbellard if (ret < 0) 428ea2384d3Sbellard return -1; 42933e3963eSbellard } else { 430ea2384d3Sbellard /* read from the base image */ 431ea2384d3Sbellard ret = bdrv_read(bs->backing_hd, sector_num, buf, n); 432ea2384d3Sbellard if (ret < 0) 433fc01f7e7Sbellard return -1; 43433e3963eSbellard } 435ea2384d3Sbellard } else { 436ea2384d3Sbellard ret = drv->bdrv_read(bs, sector_num, buf, nb_sectors); 437ea2384d3Sbellard if (ret < 0) 438ea2384d3Sbellard return -1; 439ea2384d3Sbellard /* no need to loop */ 440ea2384d3Sbellard break; 44133e3963eSbellard } 44233e3963eSbellard nb_sectors -= n; 44333e3963eSbellard sector_num += n; 44433e3963eSbellard buf += n * 512; 44533e3963eSbellard } 446fc01f7e7Sbellard return 0; 447fc01f7e7Sbellard } 448fc01f7e7Sbellard 449fc01f7e7Sbellard /* return -1 if error */ 450fc01f7e7Sbellard int bdrv_write(BlockDriverState *bs, int64_t sector_num, 451fc01f7e7Sbellard const uint8_t *buf, int nb_sectors) 452fc01f7e7Sbellard { 453b338082bSbellard if (!bs->inserted) 454b338082bSbellard return -1; 4550849bf08Sbellard if (bs->read_only) 4560849bf08Sbellard return -1; 45779639d42Sbellard if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { 45879639d42Sbellard memcpy(bs->boot_sector_data, buf, 512); 45979639d42Sbellard } 460ea2384d3Sbellard return bs->drv->bdrv_write(bs, sector_num, buf, nb_sectors); 461fc01f7e7Sbellard } 462fc01f7e7Sbellard 463fc01f7e7Sbellard void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr) 464fc01f7e7Sbellard { 465fc01f7e7Sbellard *nb_sectors_ptr = bs->total_sectors; 466fc01f7e7Sbellard } 467cf98951bSbellard 468cf98951bSbellard /* force a given boot sector. */ 469cf98951bSbellard void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size) 470cf98951bSbellard { 471cf98951bSbellard bs->boot_sector_enabled = 1; 472cf98951bSbellard if (size > 512) 473cf98951bSbellard size = 512; 474cf98951bSbellard memcpy(bs->boot_sector_data, data, size); 475cf98951bSbellard memset(bs->boot_sector_data + size, 0, 512 - size); 476cf98951bSbellard } 477b338082bSbellard 478b338082bSbellard void bdrv_set_geometry_hint(BlockDriverState *bs, 479b338082bSbellard int cyls, int heads, int secs) 480b338082bSbellard { 481b338082bSbellard bs->cyls = cyls; 482b338082bSbellard bs->heads = heads; 483b338082bSbellard bs->secs = secs; 484b338082bSbellard } 485b338082bSbellard 486b338082bSbellard void bdrv_set_type_hint(BlockDriverState *bs, int type) 487b338082bSbellard { 488b338082bSbellard bs->type = type; 489b338082bSbellard bs->removable = ((type == BDRV_TYPE_CDROM || 490b338082bSbellard type == BDRV_TYPE_FLOPPY)); 491b338082bSbellard } 492b338082bSbellard 49346d4767dSbellard void bdrv_set_translation_hint(BlockDriverState *bs, int translation) 49446d4767dSbellard { 49546d4767dSbellard bs->translation = translation; 49646d4767dSbellard } 49746d4767dSbellard 498b338082bSbellard void bdrv_get_geometry_hint(BlockDriverState *bs, 499b338082bSbellard int *pcyls, int *pheads, int *psecs) 500b338082bSbellard { 501b338082bSbellard *pcyls = bs->cyls; 502b338082bSbellard *pheads = bs->heads; 503b338082bSbellard *psecs = bs->secs; 504b338082bSbellard } 505b338082bSbellard 506b338082bSbellard int bdrv_get_type_hint(BlockDriverState *bs) 507b338082bSbellard { 508b338082bSbellard return bs->type; 509b338082bSbellard } 510b338082bSbellard 51146d4767dSbellard int bdrv_get_translation_hint(BlockDriverState *bs) 51246d4767dSbellard { 51346d4767dSbellard return bs->translation; 51446d4767dSbellard } 51546d4767dSbellard 516b338082bSbellard int bdrv_is_removable(BlockDriverState *bs) 517b338082bSbellard { 518b338082bSbellard return bs->removable; 519b338082bSbellard } 520b338082bSbellard 521b338082bSbellard int bdrv_is_read_only(BlockDriverState *bs) 522b338082bSbellard { 523b338082bSbellard return bs->read_only; 524b338082bSbellard } 525b338082bSbellard 526b338082bSbellard int bdrv_is_inserted(BlockDriverState *bs) 527b338082bSbellard { 528b338082bSbellard return bs->inserted; 529b338082bSbellard } 530b338082bSbellard 531b338082bSbellard int bdrv_is_locked(BlockDriverState *bs) 532b338082bSbellard { 533b338082bSbellard return bs->locked; 534b338082bSbellard } 535b338082bSbellard 536b338082bSbellard void bdrv_set_locked(BlockDriverState *bs, int locked) 537b338082bSbellard { 538b338082bSbellard bs->locked = locked; 539b338082bSbellard } 540b338082bSbellard 541b338082bSbellard void bdrv_set_change_cb(BlockDriverState *bs, 542b338082bSbellard void (*change_cb)(void *opaque), void *opaque) 543b338082bSbellard { 544b338082bSbellard bs->change_cb = change_cb; 545b338082bSbellard bs->change_opaque = opaque; 546b338082bSbellard } 547b338082bSbellard 548ea2384d3Sbellard int bdrv_is_encrypted(BlockDriverState *bs) 549ea2384d3Sbellard { 550ea2384d3Sbellard if (bs->backing_hd && bs->backing_hd->encrypted) 551ea2384d3Sbellard return 1; 552ea2384d3Sbellard return bs->encrypted; 553ea2384d3Sbellard } 554ea2384d3Sbellard 555ea2384d3Sbellard int bdrv_set_key(BlockDriverState *bs, const char *key) 556ea2384d3Sbellard { 557ea2384d3Sbellard int ret; 558ea2384d3Sbellard if (bs->backing_hd && bs->backing_hd->encrypted) { 559ea2384d3Sbellard ret = bdrv_set_key(bs->backing_hd, key); 560ea2384d3Sbellard if (ret < 0) 561ea2384d3Sbellard return ret; 562ea2384d3Sbellard if (!bs->encrypted) 563ea2384d3Sbellard return 0; 564ea2384d3Sbellard } 565ea2384d3Sbellard if (!bs->encrypted || !bs->drv || !bs->drv->bdrv_set_key) 566ea2384d3Sbellard return -1; 567ea2384d3Sbellard return bs->drv->bdrv_set_key(bs, key); 568ea2384d3Sbellard } 569ea2384d3Sbellard 570ea2384d3Sbellard void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size) 571ea2384d3Sbellard { 572ea2384d3Sbellard if (!bs->inserted || !bs->drv) { 573ea2384d3Sbellard buf[0] = '\0'; 574ea2384d3Sbellard } else { 575ea2384d3Sbellard pstrcpy(buf, buf_size, bs->drv->format_name); 576ea2384d3Sbellard } 577ea2384d3Sbellard } 578ea2384d3Sbellard 579ea2384d3Sbellard void bdrv_iterate_format(void (*it)(void *opaque, const char *name), 580ea2384d3Sbellard void *opaque) 581ea2384d3Sbellard { 582ea2384d3Sbellard BlockDriver *drv; 583ea2384d3Sbellard 584ea2384d3Sbellard for (drv = first_drv; drv != NULL; drv = drv->next) { 585ea2384d3Sbellard it(opaque, drv->format_name); 586ea2384d3Sbellard } 587ea2384d3Sbellard } 588ea2384d3Sbellard 589b338082bSbellard BlockDriverState *bdrv_find(const char *name) 590b338082bSbellard { 591b338082bSbellard BlockDriverState *bs; 592b338082bSbellard 593b338082bSbellard for (bs = bdrv_first; bs != NULL; bs = bs->next) { 594b338082bSbellard if (!strcmp(name, bs->device_name)) 595b338082bSbellard return bs; 596b338082bSbellard } 597b338082bSbellard return NULL; 598b338082bSbellard } 599b338082bSbellard 60081d0912dSbellard void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque) 60181d0912dSbellard { 60281d0912dSbellard BlockDriverState *bs; 60381d0912dSbellard 60481d0912dSbellard for (bs = bdrv_first; bs != NULL; bs = bs->next) { 60581d0912dSbellard it(opaque, bs->device_name); 60681d0912dSbellard } 60781d0912dSbellard } 60881d0912dSbellard 609ea2384d3Sbellard const char *bdrv_get_device_name(BlockDriverState *bs) 610ea2384d3Sbellard { 611ea2384d3Sbellard return bs->device_name; 612ea2384d3Sbellard } 613ea2384d3Sbellard 614b338082bSbellard void bdrv_info(void) 615b338082bSbellard { 616b338082bSbellard BlockDriverState *bs; 617b338082bSbellard 618b338082bSbellard for (bs = bdrv_first; bs != NULL; bs = bs->next) { 619b338082bSbellard term_printf("%s:", bs->device_name); 620b338082bSbellard term_printf(" type="); 621b338082bSbellard switch(bs->type) { 622b338082bSbellard case BDRV_TYPE_HD: 623b338082bSbellard term_printf("hd"); 624b338082bSbellard break; 625b338082bSbellard case BDRV_TYPE_CDROM: 626b338082bSbellard term_printf("cdrom"); 627b338082bSbellard break; 628b338082bSbellard case BDRV_TYPE_FLOPPY: 629b338082bSbellard term_printf("floppy"); 630b338082bSbellard break; 631b338082bSbellard } 632b338082bSbellard term_printf(" removable=%d", bs->removable); 633b338082bSbellard if (bs->removable) { 634b338082bSbellard term_printf(" locked=%d", bs->locked); 635b338082bSbellard } 636b338082bSbellard if (bs->inserted) { 637b338082bSbellard term_printf(" file=%s", bs->filename); 638ea2384d3Sbellard if (bs->backing_file[0] != '\0') 639ea2384d3Sbellard term_printf(" backing_file=%s", bs->backing_file); 640b338082bSbellard term_printf(" ro=%d", bs->read_only); 641ea2384d3Sbellard term_printf(" drv=%s", bs->drv->format_name); 642ea2384d3Sbellard if (bs->encrypted) 643ea2384d3Sbellard term_printf(" encrypted"); 644b338082bSbellard } else { 645b338082bSbellard term_printf(" [not inserted]"); 646b338082bSbellard } 647b338082bSbellard term_printf("\n"); 648b338082bSbellard } 649b338082bSbellard } 650ea2384d3Sbellard 651ea2384d3Sbellard 652ea2384d3Sbellard /**************************************************************/ 653ea2384d3Sbellard /* RAW block driver */ 654ea2384d3Sbellard 655ea2384d3Sbellard typedef struct BDRVRawState { 656ea2384d3Sbellard int fd; 657ea2384d3Sbellard } BDRVRawState; 658ea2384d3Sbellard 659ea2384d3Sbellard static int raw_probe(const uint8_t *buf, int buf_size, const char *filename) 660ea2384d3Sbellard { 661ea2384d3Sbellard return 1; /* maybe */ 662ea2384d3Sbellard } 663ea2384d3Sbellard 664ea2384d3Sbellard static int raw_open(BlockDriverState *bs, const char *filename) 665ea2384d3Sbellard { 666ea2384d3Sbellard BDRVRawState *s = bs->opaque; 667ea2384d3Sbellard int fd; 668ea2384d3Sbellard int64_t size; 669e5484d33Sbellard #ifdef _BSD 670e5484d33Sbellard struct stat sb; 671e5484d33Sbellard #endif 672ea2384d3Sbellard 673ea2384d3Sbellard fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); 674ea2384d3Sbellard if (fd < 0) { 675ea2384d3Sbellard fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); 676ea2384d3Sbellard if (fd < 0) 677ea2384d3Sbellard return -1; 678ea2384d3Sbellard bs->read_only = 1; 679ea2384d3Sbellard } 6807674e7bfSbellard #ifdef _BSD 6817674e7bfSbellard if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) { 6827674e7bfSbellard #ifdef DIOCGMEDIASIZE 6837674e7bfSbellard if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size)) 6847674e7bfSbellard #endif 6853b0d4f61Sbellard #ifdef CONFIG_COCOA 6863b0d4f61Sbellard size = LONG_LONG_MAX; 6873b0d4f61Sbellard #else 6887674e7bfSbellard size = lseek(fd, 0LL, SEEK_END); 6893b0d4f61Sbellard #endif 6907674e7bfSbellard } else 6917674e7bfSbellard #endif 6927674e7bfSbellard { 693d5249393Sbellard size = lseek(fd, 0, SEEK_END); 6947674e7bfSbellard } 695c747cd1fSbellard #ifdef _WIN32 696c747cd1fSbellard /* On Windows hosts it can happen that we're unable to get file size 697c747cd1fSbellard for CD-ROM raw device (it's inherent limitation of the CDFS driver). */ 698c747cd1fSbellard if (size == -1) 699c747cd1fSbellard size = LONG_LONG_MAX; 700c747cd1fSbellard #endif 701ea2384d3Sbellard bs->total_sectors = size / 512; 702ea2384d3Sbellard s->fd = fd; 703ea2384d3Sbellard return 0; 704ea2384d3Sbellard } 705ea2384d3Sbellard 706ea2384d3Sbellard static int raw_read(BlockDriverState *bs, int64_t sector_num, 707ea2384d3Sbellard uint8_t *buf, int nb_sectors) 708ea2384d3Sbellard { 709ea2384d3Sbellard BDRVRawState *s = bs->opaque; 710ea2384d3Sbellard int ret; 711ea2384d3Sbellard 712d5249393Sbellard lseek(s->fd, sector_num * 512, SEEK_SET); 713ea2384d3Sbellard ret = read(s->fd, buf, nb_sectors * 512); 714ea2384d3Sbellard if (ret != nb_sectors * 512) 715ea2384d3Sbellard return -1; 716ea2384d3Sbellard return 0; 717ea2384d3Sbellard } 718ea2384d3Sbellard 719ea2384d3Sbellard static int raw_write(BlockDriverState *bs, int64_t sector_num, 720ea2384d3Sbellard const uint8_t *buf, int nb_sectors) 721ea2384d3Sbellard { 722ea2384d3Sbellard BDRVRawState *s = bs->opaque; 723ea2384d3Sbellard int ret; 724ea2384d3Sbellard 725d5249393Sbellard lseek(s->fd, sector_num * 512, SEEK_SET); 726ea2384d3Sbellard ret = write(s->fd, buf, nb_sectors * 512); 727ea2384d3Sbellard if (ret != nb_sectors * 512) 728ea2384d3Sbellard return -1; 729ea2384d3Sbellard return 0; 730ea2384d3Sbellard } 731ea2384d3Sbellard 732e2731addSbellard static void raw_close(BlockDriverState *bs) 733ea2384d3Sbellard { 734ea2384d3Sbellard BDRVRawState *s = bs->opaque; 735ea2384d3Sbellard close(s->fd); 736ea2384d3Sbellard } 737ea2384d3Sbellard 738ea2384d3Sbellard static int raw_create(const char *filename, int64_t total_size, 739ea2384d3Sbellard const char *backing_file, int flags) 740ea2384d3Sbellard { 741ea2384d3Sbellard int fd; 742ea2384d3Sbellard 743ea2384d3Sbellard if (flags || backing_file) 744ea2384d3Sbellard return -ENOTSUP; 745ea2384d3Sbellard 746ea2384d3Sbellard fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 747ea2384d3Sbellard 0644); 748ea2384d3Sbellard if (fd < 0) 749ea2384d3Sbellard return -EIO; 750d5249393Sbellard ftruncate(fd, total_size * 512); 751ea2384d3Sbellard close(fd); 752ea2384d3Sbellard return 0; 753ea2384d3Sbellard } 754ea2384d3Sbellard 755ea2384d3Sbellard BlockDriver bdrv_raw = { 756ea2384d3Sbellard "raw", 757ea2384d3Sbellard sizeof(BDRVRawState), 758ea2384d3Sbellard raw_probe, 759ea2384d3Sbellard raw_open, 760ea2384d3Sbellard raw_read, 761ea2384d3Sbellard raw_write, 762ea2384d3Sbellard raw_close, 763ea2384d3Sbellard raw_create, 764ea2384d3Sbellard }; 765ea2384d3Sbellard 766ea2384d3Sbellard void bdrv_init(void) 767ea2384d3Sbellard { 768ea2384d3Sbellard bdrv_register(&bdrv_raw); 769ea2384d3Sbellard #ifndef _WIN32 770ea2384d3Sbellard bdrv_register(&bdrv_cow); 771ea2384d3Sbellard #endif 772ea2384d3Sbellard bdrv_register(&bdrv_qcow); 773ea2384d3Sbellard bdrv_register(&bdrv_vmdk); 7743c56521bSbellard bdrv_register(&bdrv_cloop); 775585d0ed9Sbellard bdrv_register(&bdrv_dmg); 776a8753c34Sbellard bdrv_register(&bdrv_bochs); 7776a0f9e82Sbellard bdrv_register(&bdrv_vpc); 778712e7874Sbellard bdrv_register(&bdrv_vvfat); 779ea2384d3Sbellard } 780