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 153d5249393Sbellard static void get_tmp_filename(char *filename, int size) 154d5249393Sbellard { 155d5249393Sbellard /* XXX: find a better function */ 156d5249393Sbellard tmpnam(filename); 157d5249393Sbellard } 158d5249393Sbellard #else 159ea2384d3Sbellard static void get_tmp_filename(char *filename, int size) 160ea2384d3Sbellard { 161ea2384d3Sbellard int fd; 162d5249393Sbellard /* XXX: race condition possible */ 163ea2384d3Sbellard pstrcpy(filename, size, "/tmp/vl.XXXXXX"); 164ea2384d3Sbellard fd = mkstemp(filename); 165ea2384d3Sbellard close(fd); 166ea2384d3Sbellard } 167d5249393Sbellard #endif 168ea2384d3Sbellard 1697674e7bfSbellard /* XXX: force raw format if block or character device ? It would 1707674e7bfSbellard simplify the BSD case */ 171ea2384d3Sbellard static BlockDriver *find_image_format(const char *filename) 172ea2384d3Sbellard { 173ea2384d3Sbellard int fd, ret, score, score_max; 174ea2384d3Sbellard BlockDriver *drv1, *drv; 1757674e7bfSbellard uint8_t *buf; 1767674e7bfSbellard size_t bufsize = 1024; 177ea2384d3Sbellard 178ea2384d3Sbellard fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); 179712e7874Sbellard if (fd < 0) { 180712e7874Sbellard buf = NULL; 181712e7874Sbellard ret = 0; 182712e7874Sbellard } else { 1837674e7bfSbellard #ifdef DIOCGSECTORSIZE 1847674e7bfSbellard { 1857674e7bfSbellard unsigned int sectorsize = 512; 1867674e7bfSbellard if (!ioctl(fd, DIOCGSECTORSIZE, §orsize) && 1877674e7bfSbellard sectorsize > bufsize) 1887674e7bfSbellard bufsize = sectorsize; 1897674e7bfSbellard } 1907674e7bfSbellard #endif 1913b0d4f61Sbellard #ifdef CONFIG_COCOA 1923b0d4f61Sbellard u_int32_t blockSize = 512; 1933b0d4f61Sbellard if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize > bufsize) { 1943b0d4f61Sbellard bufsize = blockSize; 1953b0d4f61Sbellard } 1963b0d4f61Sbellard #endif 197712e7874Sbellard buf = qemu_malloc(bufsize); 1987674e7bfSbellard if (!buf) 1997674e7bfSbellard return NULL; 2007674e7bfSbellard ret = read(fd, buf, bufsize); 201ea2384d3Sbellard if (ret < 0) { 202ea2384d3Sbellard close(fd); 203712e7874Sbellard qemu_free(buf); 204ea2384d3Sbellard return NULL; 205ea2384d3Sbellard } 206ea2384d3Sbellard close(fd); 207712e7874Sbellard } 208ea2384d3Sbellard 209ea2384d3Sbellard drv = NULL; 210ea2384d3Sbellard score_max = 0; 211ea2384d3Sbellard for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) { 212ea2384d3Sbellard score = drv1->bdrv_probe(buf, ret, filename); 213ea2384d3Sbellard if (score > score_max) { 214ea2384d3Sbellard score_max = score; 215ea2384d3Sbellard drv = drv1; 216ea2384d3Sbellard } 217ea2384d3Sbellard } 218712e7874Sbellard qemu_free(buf); 219ea2384d3Sbellard return drv; 220ea2384d3Sbellard } 221ea2384d3Sbellard 222b338082bSbellard int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) 223b338082bSbellard { 2243b0d4f61Sbellard #ifdef CONFIG_COCOA 2253b0d4f61Sbellard if ( strncmp( filename, "/dev/cdrom", 10 ) == 0 ) { 2263b0d4f61Sbellard kern_return_t kernResult; 2273b0d4f61Sbellard io_iterator_t mediaIterator; 2283b0d4f61Sbellard char bsdPath[ MAXPATHLEN ]; 2293b0d4f61Sbellard int fd; 2303b0d4f61Sbellard 2313b0d4f61Sbellard kernResult = FindEjectableCDMedia( &mediaIterator ); 2323b0d4f61Sbellard kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) ); 2333b0d4f61Sbellard 2343b0d4f61Sbellard if ( bsdPath[ 0 ] != '\0' ) { 2353b0d4f61Sbellard strcat(bsdPath,"s0"); 2363b0d4f61Sbellard /* some CDs don't have a partition 0 */ 2373b0d4f61Sbellard fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE); 2383b0d4f61Sbellard if (fd < 0) { 2393b0d4f61Sbellard bsdPath[strlen(bsdPath)-1] = '1'; 2403b0d4f61Sbellard } else { 2413b0d4f61Sbellard close(fd); 2423b0d4f61Sbellard } 2433b0d4f61Sbellard filename = bsdPath; 2443b0d4f61Sbellard } 2453b0d4f61Sbellard 2463b0d4f61Sbellard if ( mediaIterator ) 2473b0d4f61Sbellard IOObjectRelease( mediaIterator ); 2483b0d4f61Sbellard } 2493b0d4f61Sbellard #endif 250ea2384d3Sbellard return bdrv_open2(bs, filename, snapshot, NULL); 251ea2384d3Sbellard } 252ea2384d3Sbellard 253ea2384d3Sbellard int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot, 254ea2384d3Sbellard BlockDriver *drv) 255ea2384d3Sbellard { 256ea2384d3Sbellard int ret; 257ea2384d3Sbellard char tmp_filename[1024]; 258fc01f7e7Sbellard 2590849bf08Sbellard bs->read_only = 0; 260ea2384d3Sbellard bs->is_temporary = 0; 261ea2384d3Sbellard bs->encrypted = 0; 26233e3963eSbellard 26333e3963eSbellard if (snapshot) { 264ea2384d3Sbellard BlockDriverState *bs1; 265ea2384d3Sbellard int64_t total_size; 26633e3963eSbellard 267ea2384d3Sbellard /* if snapshot, we create a temporary backing file and open it 268ea2384d3Sbellard instead of opening 'filename' directly */ 269ea2384d3Sbellard 270ea2384d3Sbellard /* if there is a backing file, use it */ 271ea2384d3Sbellard bs1 = bdrv_new(""); 272ea2384d3Sbellard if (!bs1) { 273ea2384d3Sbellard return -1; 274ea2384d3Sbellard } 275ea2384d3Sbellard if (bdrv_open(bs1, filename, 0) < 0) { 276ea2384d3Sbellard bdrv_delete(bs1); 277ea2384d3Sbellard return -1; 278ea2384d3Sbellard } 279ea2384d3Sbellard total_size = bs1->total_sectors; 280ea2384d3Sbellard bdrv_delete(bs1); 281ea2384d3Sbellard 282ea2384d3Sbellard get_tmp_filename(tmp_filename, sizeof(tmp_filename)); 283ea2384d3Sbellard /* XXX: use cow for linux as it is more efficient ? */ 284ea2384d3Sbellard if (bdrv_create(&bdrv_qcow, tmp_filename, 285ea2384d3Sbellard total_size, filename, 0) < 0) { 286ea2384d3Sbellard return -1; 287ea2384d3Sbellard } 288ea2384d3Sbellard filename = tmp_filename; 289ea2384d3Sbellard bs->is_temporary = 1; 290ea2384d3Sbellard } 291ea2384d3Sbellard 292ea2384d3Sbellard pstrcpy(bs->filename, sizeof(bs->filename), filename); 293ea2384d3Sbellard if (!drv) { 294ea2384d3Sbellard drv = find_image_format(filename); 295ea2384d3Sbellard if (!drv) 296ea2384d3Sbellard return -1; 297ea2384d3Sbellard } 298ea2384d3Sbellard bs->drv = drv; 299ea2384d3Sbellard bs->opaque = qemu_mallocz(drv->instance_size); 300ea2384d3Sbellard if (bs->opaque == NULL && drv->instance_size > 0) 301ea2384d3Sbellard return -1; 302ea2384d3Sbellard 303ea2384d3Sbellard ret = drv->bdrv_open(bs, filename); 304ea2384d3Sbellard if (ret < 0) { 305ea2384d3Sbellard qemu_free(bs->opaque); 306ea2384d3Sbellard return -1; 307ea2384d3Sbellard } 308ea2384d3Sbellard #ifndef _WIN32 309ea2384d3Sbellard if (bs->is_temporary) { 310ea2384d3Sbellard unlink(filename); 31133e3963eSbellard } 31267b915a5Sbellard #endif 313ea2384d3Sbellard if (bs->backing_file[0] != '\0' && drv->bdrv_is_allocated) { 314ea2384d3Sbellard /* if there is a backing file, use it */ 315ea2384d3Sbellard bs->backing_hd = bdrv_new(""); 316ea2384d3Sbellard if (!bs->backing_hd) { 317ea2384d3Sbellard fail: 318ea2384d3Sbellard bdrv_close(bs); 319ea2384d3Sbellard return -1; 320ea2384d3Sbellard } 321ea2384d3Sbellard if (bdrv_open(bs->backing_hd, bs->backing_file, 0) < 0) 322ea2384d3Sbellard goto fail; 323ea2384d3Sbellard } 32433e3963eSbellard 325b338082bSbellard bs->inserted = 1; 326b338082bSbellard 327b338082bSbellard /* call the change callback */ 328b338082bSbellard if (bs->change_cb) 329b338082bSbellard bs->change_cb(bs->change_opaque); 330b338082bSbellard 331b338082bSbellard return 0; 332fc01f7e7Sbellard } 333fc01f7e7Sbellard 334fc01f7e7Sbellard void bdrv_close(BlockDriverState *bs) 335fc01f7e7Sbellard { 336b338082bSbellard if (bs->inserted) { 337ea2384d3Sbellard if (bs->backing_hd) 338ea2384d3Sbellard bdrv_delete(bs->backing_hd); 339ea2384d3Sbellard bs->drv->bdrv_close(bs); 340ea2384d3Sbellard qemu_free(bs->opaque); 341ea2384d3Sbellard #ifdef _WIN32 342ea2384d3Sbellard if (bs->is_temporary) { 343ea2384d3Sbellard unlink(bs->filename); 344ea2384d3Sbellard } 34567b915a5Sbellard #endif 346ea2384d3Sbellard bs->opaque = NULL; 347ea2384d3Sbellard bs->drv = NULL; 348b338082bSbellard bs->inserted = 0; 349b338082bSbellard 350b338082bSbellard /* call the change callback */ 351b338082bSbellard if (bs->change_cb) 352b338082bSbellard bs->change_cb(bs->change_opaque); 353b338082bSbellard } 354b338082bSbellard } 355b338082bSbellard 356b338082bSbellard void bdrv_delete(BlockDriverState *bs) 357b338082bSbellard { 358ea2384d3Sbellard /* XXX: remove the driver list */ 359b338082bSbellard bdrv_close(bs); 360b338082bSbellard qemu_free(bs); 361fc01f7e7Sbellard } 362fc01f7e7Sbellard 36333e3963eSbellard /* commit COW file into the raw image */ 36433e3963eSbellard int bdrv_commit(BlockDriverState *bs) 36533e3963eSbellard { 36633e3963eSbellard int64_t i; 367ea2384d3Sbellard int n, j; 368ea2384d3Sbellard unsigned char sector[512]; 36933e3963eSbellard 370b338082bSbellard if (!bs->inserted) 371ea2384d3Sbellard return -ENOENT; 37233e3963eSbellard 37333e3963eSbellard if (bs->read_only) { 374ea2384d3Sbellard return -EACCES; 37533e3963eSbellard } 37633e3963eSbellard 377ea2384d3Sbellard if (!bs->backing_hd) { 378ea2384d3Sbellard return -ENOTSUP; 379ea2384d3Sbellard } 380ea2384d3Sbellard 381ea2384d3Sbellard for (i = 0; i < bs->total_sectors;) { 382ea2384d3Sbellard if (bs->drv->bdrv_is_allocated(bs, i, 65536, &n)) { 383ea2384d3Sbellard for(j = 0; j < n; j++) { 38433e3963eSbellard if (bdrv_read(bs, i, sector, 1) != 0) { 385ea2384d3Sbellard return -EIO; 38633e3963eSbellard } 38733e3963eSbellard 388ea2384d3Sbellard if (bdrv_write(bs->backing_hd, i, sector, 1) != 0) { 389ea2384d3Sbellard return -EIO; 39033e3963eSbellard } 391ea2384d3Sbellard i++; 392ea2384d3Sbellard } 393ea2384d3Sbellard } else { 394ea2384d3Sbellard i += n; 39533e3963eSbellard } 39633e3963eSbellard } 39733e3963eSbellard return 0; 39833e3963eSbellard } 39933e3963eSbellard 400fc01f7e7Sbellard /* return -1 if error */ 401fc01f7e7Sbellard int bdrv_read(BlockDriverState *bs, int64_t sector_num, 402fc01f7e7Sbellard uint8_t *buf, int nb_sectors) 403fc01f7e7Sbellard { 404ea2384d3Sbellard int ret, n; 405ea2384d3Sbellard BlockDriver *drv = bs->drv; 406fc01f7e7Sbellard 407b338082bSbellard if (!bs->inserted) 408b338082bSbellard return -1; 409b338082bSbellard 41033e3963eSbellard while (nb_sectors > 0) { 411ea2384d3Sbellard if (sector_num == 0 && bs->boot_sector_enabled) { 412cf98951bSbellard memcpy(buf, bs->boot_sector_data, 512); 413cf98951bSbellard n = 1; 414ea2384d3Sbellard } else if (bs->backing_hd) { 415ea2384d3Sbellard if (drv->bdrv_is_allocated(bs, sector_num, nb_sectors, &n)) { 416ea2384d3Sbellard ret = drv->bdrv_read(bs, sector_num, buf, n); 417ea2384d3Sbellard if (ret < 0) 418ea2384d3Sbellard return -1; 41933e3963eSbellard } else { 420ea2384d3Sbellard /* read from the base image */ 421ea2384d3Sbellard ret = bdrv_read(bs->backing_hd, sector_num, buf, n); 422ea2384d3Sbellard if (ret < 0) 423fc01f7e7Sbellard return -1; 42433e3963eSbellard } 425ea2384d3Sbellard } else { 426ea2384d3Sbellard ret = drv->bdrv_read(bs, sector_num, buf, nb_sectors); 427ea2384d3Sbellard if (ret < 0) 428ea2384d3Sbellard return -1; 429ea2384d3Sbellard /* no need to loop */ 430ea2384d3Sbellard break; 43133e3963eSbellard } 43233e3963eSbellard nb_sectors -= n; 43333e3963eSbellard sector_num += n; 43433e3963eSbellard buf += n * 512; 43533e3963eSbellard } 436fc01f7e7Sbellard return 0; 437fc01f7e7Sbellard } 438fc01f7e7Sbellard 439fc01f7e7Sbellard /* return -1 if error */ 440fc01f7e7Sbellard int bdrv_write(BlockDriverState *bs, int64_t sector_num, 441fc01f7e7Sbellard const uint8_t *buf, int nb_sectors) 442fc01f7e7Sbellard { 443b338082bSbellard if (!bs->inserted) 444b338082bSbellard return -1; 4450849bf08Sbellard if (bs->read_only) 4460849bf08Sbellard return -1; 447*79639d42Sbellard if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { 448*79639d42Sbellard memcpy(bs->boot_sector_data, buf, 512); 449*79639d42Sbellard } 450ea2384d3Sbellard return bs->drv->bdrv_write(bs, sector_num, buf, nb_sectors); 451fc01f7e7Sbellard } 452fc01f7e7Sbellard 453fc01f7e7Sbellard void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr) 454fc01f7e7Sbellard { 455fc01f7e7Sbellard *nb_sectors_ptr = bs->total_sectors; 456fc01f7e7Sbellard } 457cf98951bSbellard 458cf98951bSbellard /* force a given boot sector. */ 459cf98951bSbellard void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size) 460cf98951bSbellard { 461cf98951bSbellard bs->boot_sector_enabled = 1; 462cf98951bSbellard if (size > 512) 463cf98951bSbellard size = 512; 464cf98951bSbellard memcpy(bs->boot_sector_data, data, size); 465cf98951bSbellard memset(bs->boot_sector_data + size, 0, 512 - size); 466cf98951bSbellard } 467b338082bSbellard 468b338082bSbellard void bdrv_set_geometry_hint(BlockDriverState *bs, 469b338082bSbellard int cyls, int heads, int secs) 470b338082bSbellard { 471b338082bSbellard bs->cyls = cyls; 472b338082bSbellard bs->heads = heads; 473b338082bSbellard bs->secs = secs; 474b338082bSbellard } 475b338082bSbellard 476b338082bSbellard void bdrv_set_type_hint(BlockDriverState *bs, int type) 477b338082bSbellard { 478b338082bSbellard bs->type = type; 479b338082bSbellard bs->removable = ((type == BDRV_TYPE_CDROM || 480b338082bSbellard type == BDRV_TYPE_FLOPPY)); 481b338082bSbellard } 482b338082bSbellard 48346d4767dSbellard void bdrv_set_translation_hint(BlockDriverState *bs, int translation) 48446d4767dSbellard { 48546d4767dSbellard bs->translation = translation; 48646d4767dSbellard } 48746d4767dSbellard 488b338082bSbellard void bdrv_get_geometry_hint(BlockDriverState *bs, 489b338082bSbellard int *pcyls, int *pheads, int *psecs) 490b338082bSbellard { 491b338082bSbellard *pcyls = bs->cyls; 492b338082bSbellard *pheads = bs->heads; 493b338082bSbellard *psecs = bs->secs; 494b338082bSbellard } 495b338082bSbellard 496b338082bSbellard int bdrv_get_type_hint(BlockDriverState *bs) 497b338082bSbellard { 498b338082bSbellard return bs->type; 499b338082bSbellard } 500b338082bSbellard 50146d4767dSbellard int bdrv_get_translation_hint(BlockDriverState *bs) 50246d4767dSbellard { 50346d4767dSbellard return bs->translation; 50446d4767dSbellard } 50546d4767dSbellard 506b338082bSbellard int bdrv_is_removable(BlockDriverState *bs) 507b338082bSbellard { 508b338082bSbellard return bs->removable; 509b338082bSbellard } 510b338082bSbellard 511b338082bSbellard int bdrv_is_read_only(BlockDriverState *bs) 512b338082bSbellard { 513b338082bSbellard return bs->read_only; 514b338082bSbellard } 515b338082bSbellard 516b338082bSbellard int bdrv_is_inserted(BlockDriverState *bs) 517b338082bSbellard { 518b338082bSbellard return bs->inserted; 519b338082bSbellard } 520b338082bSbellard 521b338082bSbellard int bdrv_is_locked(BlockDriverState *bs) 522b338082bSbellard { 523b338082bSbellard return bs->locked; 524b338082bSbellard } 525b338082bSbellard 526b338082bSbellard void bdrv_set_locked(BlockDriverState *bs, int locked) 527b338082bSbellard { 528b338082bSbellard bs->locked = locked; 529b338082bSbellard } 530b338082bSbellard 531b338082bSbellard void bdrv_set_change_cb(BlockDriverState *bs, 532b338082bSbellard void (*change_cb)(void *opaque), void *opaque) 533b338082bSbellard { 534b338082bSbellard bs->change_cb = change_cb; 535b338082bSbellard bs->change_opaque = opaque; 536b338082bSbellard } 537b338082bSbellard 538ea2384d3Sbellard int bdrv_is_encrypted(BlockDriverState *bs) 539ea2384d3Sbellard { 540ea2384d3Sbellard if (bs->backing_hd && bs->backing_hd->encrypted) 541ea2384d3Sbellard return 1; 542ea2384d3Sbellard return bs->encrypted; 543ea2384d3Sbellard } 544ea2384d3Sbellard 545ea2384d3Sbellard int bdrv_set_key(BlockDriverState *bs, const char *key) 546ea2384d3Sbellard { 547ea2384d3Sbellard int ret; 548ea2384d3Sbellard if (bs->backing_hd && bs->backing_hd->encrypted) { 549ea2384d3Sbellard ret = bdrv_set_key(bs->backing_hd, key); 550ea2384d3Sbellard if (ret < 0) 551ea2384d3Sbellard return ret; 552ea2384d3Sbellard if (!bs->encrypted) 553ea2384d3Sbellard return 0; 554ea2384d3Sbellard } 555ea2384d3Sbellard if (!bs->encrypted || !bs->drv || !bs->drv->bdrv_set_key) 556ea2384d3Sbellard return -1; 557ea2384d3Sbellard return bs->drv->bdrv_set_key(bs, key); 558ea2384d3Sbellard } 559ea2384d3Sbellard 560ea2384d3Sbellard void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size) 561ea2384d3Sbellard { 562ea2384d3Sbellard if (!bs->inserted || !bs->drv) { 563ea2384d3Sbellard buf[0] = '\0'; 564ea2384d3Sbellard } else { 565ea2384d3Sbellard pstrcpy(buf, buf_size, bs->drv->format_name); 566ea2384d3Sbellard } 567ea2384d3Sbellard } 568ea2384d3Sbellard 569ea2384d3Sbellard void bdrv_iterate_format(void (*it)(void *opaque, const char *name), 570ea2384d3Sbellard void *opaque) 571ea2384d3Sbellard { 572ea2384d3Sbellard BlockDriver *drv; 573ea2384d3Sbellard 574ea2384d3Sbellard for (drv = first_drv; drv != NULL; drv = drv->next) { 575ea2384d3Sbellard it(opaque, drv->format_name); 576ea2384d3Sbellard } 577ea2384d3Sbellard } 578ea2384d3Sbellard 579b338082bSbellard BlockDriverState *bdrv_find(const char *name) 580b338082bSbellard { 581b338082bSbellard BlockDriverState *bs; 582b338082bSbellard 583b338082bSbellard for (bs = bdrv_first; bs != NULL; bs = bs->next) { 584b338082bSbellard if (!strcmp(name, bs->device_name)) 585b338082bSbellard return bs; 586b338082bSbellard } 587b338082bSbellard return NULL; 588b338082bSbellard } 589b338082bSbellard 59081d0912dSbellard void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque) 59181d0912dSbellard { 59281d0912dSbellard BlockDriverState *bs; 59381d0912dSbellard 59481d0912dSbellard for (bs = bdrv_first; bs != NULL; bs = bs->next) { 59581d0912dSbellard it(opaque, bs->device_name); 59681d0912dSbellard } 59781d0912dSbellard } 59881d0912dSbellard 599ea2384d3Sbellard const char *bdrv_get_device_name(BlockDriverState *bs) 600ea2384d3Sbellard { 601ea2384d3Sbellard return bs->device_name; 602ea2384d3Sbellard } 603ea2384d3Sbellard 604b338082bSbellard void bdrv_info(void) 605b338082bSbellard { 606b338082bSbellard BlockDriverState *bs; 607b338082bSbellard 608b338082bSbellard for (bs = bdrv_first; bs != NULL; bs = bs->next) { 609b338082bSbellard term_printf("%s:", bs->device_name); 610b338082bSbellard term_printf(" type="); 611b338082bSbellard switch(bs->type) { 612b338082bSbellard case BDRV_TYPE_HD: 613b338082bSbellard term_printf("hd"); 614b338082bSbellard break; 615b338082bSbellard case BDRV_TYPE_CDROM: 616b338082bSbellard term_printf("cdrom"); 617b338082bSbellard break; 618b338082bSbellard case BDRV_TYPE_FLOPPY: 619b338082bSbellard term_printf("floppy"); 620b338082bSbellard break; 621b338082bSbellard } 622b338082bSbellard term_printf(" removable=%d", bs->removable); 623b338082bSbellard if (bs->removable) { 624b338082bSbellard term_printf(" locked=%d", bs->locked); 625b338082bSbellard } 626b338082bSbellard if (bs->inserted) { 627b338082bSbellard term_printf(" file=%s", bs->filename); 628ea2384d3Sbellard if (bs->backing_file[0] != '\0') 629ea2384d3Sbellard term_printf(" backing_file=%s", bs->backing_file); 630b338082bSbellard term_printf(" ro=%d", bs->read_only); 631ea2384d3Sbellard term_printf(" drv=%s", bs->drv->format_name); 632ea2384d3Sbellard if (bs->encrypted) 633ea2384d3Sbellard term_printf(" encrypted"); 634b338082bSbellard } else { 635b338082bSbellard term_printf(" [not inserted]"); 636b338082bSbellard } 637b338082bSbellard term_printf("\n"); 638b338082bSbellard } 639b338082bSbellard } 640ea2384d3Sbellard 641ea2384d3Sbellard 642ea2384d3Sbellard /**************************************************************/ 643ea2384d3Sbellard /* RAW block driver */ 644ea2384d3Sbellard 645ea2384d3Sbellard typedef struct BDRVRawState { 646ea2384d3Sbellard int fd; 647ea2384d3Sbellard } BDRVRawState; 648ea2384d3Sbellard 649ea2384d3Sbellard static int raw_probe(const uint8_t *buf, int buf_size, const char *filename) 650ea2384d3Sbellard { 651ea2384d3Sbellard return 1; /* maybe */ 652ea2384d3Sbellard } 653ea2384d3Sbellard 654ea2384d3Sbellard static int raw_open(BlockDriverState *bs, const char *filename) 655ea2384d3Sbellard { 656ea2384d3Sbellard BDRVRawState *s = bs->opaque; 657ea2384d3Sbellard int fd; 658ea2384d3Sbellard int64_t size; 659e5484d33Sbellard #ifdef _BSD 660e5484d33Sbellard struct stat sb; 661e5484d33Sbellard #endif 662ea2384d3Sbellard 663ea2384d3Sbellard fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); 664ea2384d3Sbellard if (fd < 0) { 665ea2384d3Sbellard fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); 666ea2384d3Sbellard if (fd < 0) 667ea2384d3Sbellard return -1; 668ea2384d3Sbellard bs->read_only = 1; 669ea2384d3Sbellard } 6707674e7bfSbellard #ifdef _BSD 6717674e7bfSbellard if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) { 6727674e7bfSbellard #ifdef DIOCGMEDIASIZE 6737674e7bfSbellard if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size)) 6747674e7bfSbellard #endif 6753b0d4f61Sbellard #ifdef CONFIG_COCOA 6763b0d4f61Sbellard size = LONG_LONG_MAX; 6773b0d4f61Sbellard #else 6787674e7bfSbellard size = lseek(fd, 0LL, SEEK_END); 6793b0d4f61Sbellard #endif 6807674e7bfSbellard } else 6817674e7bfSbellard #endif 6827674e7bfSbellard { 683d5249393Sbellard size = lseek(fd, 0, SEEK_END); 6847674e7bfSbellard } 685c747cd1fSbellard #ifdef _WIN32 686c747cd1fSbellard /* On Windows hosts it can happen that we're unable to get file size 687c747cd1fSbellard for CD-ROM raw device (it's inherent limitation of the CDFS driver). */ 688c747cd1fSbellard if (size == -1) 689c747cd1fSbellard size = LONG_LONG_MAX; 690c747cd1fSbellard #endif 691ea2384d3Sbellard bs->total_sectors = size / 512; 692ea2384d3Sbellard s->fd = fd; 693ea2384d3Sbellard return 0; 694ea2384d3Sbellard } 695ea2384d3Sbellard 696ea2384d3Sbellard static int raw_read(BlockDriverState *bs, int64_t sector_num, 697ea2384d3Sbellard uint8_t *buf, int nb_sectors) 698ea2384d3Sbellard { 699ea2384d3Sbellard BDRVRawState *s = bs->opaque; 700ea2384d3Sbellard int ret; 701ea2384d3Sbellard 702d5249393Sbellard lseek(s->fd, sector_num * 512, SEEK_SET); 703ea2384d3Sbellard ret = read(s->fd, buf, nb_sectors * 512); 704ea2384d3Sbellard if (ret != nb_sectors * 512) 705ea2384d3Sbellard return -1; 706ea2384d3Sbellard return 0; 707ea2384d3Sbellard } 708ea2384d3Sbellard 709ea2384d3Sbellard static int raw_write(BlockDriverState *bs, int64_t sector_num, 710ea2384d3Sbellard const uint8_t *buf, int nb_sectors) 711ea2384d3Sbellard { 712ea2384d3Sbellard BDRVRawState *s = bs->opaque; 713ea2384d3Sbellard int ret; 714ea2384d3Sbellard 715d5249393Sbellard lseek(s->fd, sector_num * 512, SEEK_SET); 716ea2384d3Sbellard ret = write(s->fd, buf, nb_sectors * 512); 717ea2384d3Sbellard if (ret != nb_sectors * 512) 718ea2384d3Sbellard return -1; 719ea2384d3Sbellard return 0; 720ea2384d3Sbellard } 721ea2384d3Sbellard 722e2731addSbellard static void raw_close(BlockDriverState *bs) 723ea2384d3Sbellard { 724ea2384d3Sbellard BDRVRawState *s = bs->opaque; 725ea2384d3Sbellard close(s->fd); 726ea2384d3Sbellard } 727ea2384d3Sbellard 728ea2384d3Sbellard static int raw_create(const char *filename, int64_t total_size, 729ea2384d3Sbellard const char *backing_file, int flags) 730ea2384d3Sbellard { 731ea2384d3Sbellard int fd; 732ea2384d3Sbellard 733ea2384d3Sbellard if (flags || backing_file) 734ea2384d3Sbellard return -ENOTSUP; 735ea2384d3Sbellard 736ea2384d3Sbellard fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 737ea2384d3Sbellard 0644); 738ea2384d3Sbellard if (fd < 0) 739ea2384d3Sbellard return -EIO; 740d5249393Sbellard ftruncate(fd, total_size * 512); 741ea2384d3Sbellard close(fd); 742ea2384d3Sbellard return 0; 743ea2384d3Sbellard } 744ea2384d3Sbellard 745ea2384d3Sbellard BlockDriver bdrv_raw = { 746ea2384d3Sbellard "raw", 747ea2384d3Sbellard sizeof(BDRVRawState), 748ea2384d3Sbellard raw_probe, 749ea2384d3Sbellard raw_open, 750ea2384d3Sbellard raw_read, 751ea2384d3Sbellard raw_write, 752ea2384d3Sbellard raw_close, 753ea2384d3Sbellard raw_create, 754ea2384d3Sbellard }; 755ea2384d3Sbellard 756ea2384d3Sbellard void bdrv_init(void) 757ea2384d3Sbellard { 758ea2384d3Sbellard bdrv_register(&bdrv_raw); 759ea2384d3Sbellard #ifndef _WIN32 760ea2384d3Sbellard bdrv_register(&bdrv_cow); 761ea2384d3Sbellard #endif 762ea2384d3Sbellard bdrv_register(&bdrv_qcow); 763ea2384d3Sbellard bdrv_register(&bdrv_vmdk); 7643c56521bSbellard bdrv_register(&bdrv_cloop); 765585d0ed9Sbellard bdrv_register(&bdrv_dmg); 766a8753c34Sbellard bdrv_register(&bdrv_bochs); 7676a0f9e82Sbellard bdrv_register(&bdrv_vpc); 768712e7874Sbellard bdrv_register(&bdrv_vvfat); 769ea2384d3Sbellard } 770