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 35*3b0d4f61Sbellard #ifdef CONFIG_COCOA 36*3b0d4f61Sbellard #include <paths.h> 37*3b0d4f61Sbellard #include <sys/param.h> 38*3b0d4f61Sbellard #include <IOKit/IOKitLib.h> 39*3b0d4f61Sbellard #include <IOKit/IOBSD.h> 40*3b0d4f61Sbellard #include <IOKit/storage/IOMediaBSDClient.h> 41*3b0d4f61Sbellard #include <IOKit/storage/IOMedia.h> 42*3b0d4f61Sbellard #include <IOKit/storage/IOCDMedia.h> 43*3b0d4f61Sbellard //#include <IOKit/storage/IOCDTypes.h> 44*3b0d4f61Sbellard #include <CoreFoundation/CoreFoundation.h> 45*3b0d4f61Sbellard #endif 46*3b0d4f61Sbellard 47b338082bSbellard static BlockDriverState *bdrv_first; 48ea2384d3Sbellard static BlockDriver *first_drv; 49ea2384d3Sbellard 50*3b0d4f61Sbellard #ifdef CONFIG_COCOA 51*3b0d4f61Sbellard static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator ); 52*3b0d4f61Sbellard static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize ); 53*3b0d4f61Sbellard 54*3b0d4f61Sbellard kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator ) 55*3b0d4f61Sbellard { 56*3b0d4f61Sbellard kern_return_t kernResult; 57*3b0d4f61Sbellard mach_port_t masterPort; 58*3b0d4f61Sbellard CFMutableDictionaryRef classesToMatch; 59*3b0d4f61Sbellard 60*3b0d4f61Sbellard kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort ); 61*3b0d4f61Sbellard if ( KERN_SUCCESS != kernResult ) { 62*3b0d4f61Sbellard printf( "IOMasterPort returned %d\n", kernResult ); 63*3b0d4f61Sbellard } 64*3b0d4f61Sbellard 65*3b0d4f61Sbellard classesToMatch = IOServiceMatching( kIOCDMediaClass ); 66*3b0d4f61Sbellard if ( classesToMatch == NULL ) { 67*3b0d4f61Sbellard printf( "IOServiceMatching returned a NULL dictionary.\n" ); 68*3b0d4f61Sbellard } else { 69*3b0d4f61Sbellard CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue ); 70*3b0d4f61Sbellard } 71*3b0d4f61Sbellard kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, mediaIterator ); 72*3b0d4f61Sbellard if ( KERN_SUCCESS != kernResult ) 73*3b0d4f61Sbellard { 74*3b0d4f61Sbellard printf( "IOServiceGetMatchingServices returned %d\n", kernResult ); 75*3b0d4f61Sbellard } 76*3b0d4f61Sbellard 77*3b0d4f61Sbellard return kernResult; 78*3b0d4f61Sbellard } 79*3b0d4f61Sbellard 80*3b0d4f61Sbellard kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize ) 81*3b0d4f61Sbellard { 82*3b0d4f61Sbellard io_object_t nextMedia; 83*3b0d4f61Sbellard kern_return_t kernResult = KERN_FAILURE; 84*3b0d4f61Sbellard *bsdPath = '\0'; 85*3b0d4f61Sbellard nextMedia = IOIteratorNext( mediaIterator ); 86*3b0d4f61Sbellard if ( nextMedia ) 87*3b0d4f61Sbellard { 88*3b0d4f61Sbellard CFTypeRef bsdPathAsCFString; 89*3b0d4f61Sbellard bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia, CFSTR( kIOBSDNameKey ), kCFAllocatorDefault, 0 ); 90*3b0d4f61Sbellard if ( bsdPathAsCFString ) { 91*3b0d4f61Sbellard size_t devPathLength; 92*3b0d4f61Sbellard strcpy( bsdPath, _PATH_DEV ); 93*3b0d4f61Sbellard strcat( bsdPath, "r" ); 94*3b0d4f61Sbellard devPathLength = strlen( bsdPath ); 95*3b0d4f61Sbellard if ( CFStringGetCString( bsdPathAsCFString, bsdPath + devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) { 96*3b0d4f61Sbellard kernResult = KERN_SUCCESS; 97*3b0d4f61Sbellard } 98*3b0d4f61Sbellard CFRelease( bsdPathAsCFString ); 99*3b0d4f61Sbellard } 100*3b0d4f61Sbellard IOObjectRelease( nextMedia ); 101*3b0d4f61Sbellard } 102*3b0d4f61Sbellard 103*3b0d4f61Sbellard return kernResult; 104*3b0d4f61Sbellard } 105*3b0d4f61Sbellard 106*3b0d4f61Sbellard #endif 107*3b0d4f61Sbellard 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 191*3b0d4f61Sbellard #ifdef CONFIG_COCOA 192*3b0d4f61Sbellard u_int32_t blockSize = 512; 193*3b0d4f61Sbellard if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize > bufsize) { 194*3b0d4f61Sbellard bufsize = blockSize; 195*3b0d4f61Sbellard } 196*3b0d4f61Sbellard #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 { 224*3b0d4f61Sbellard #ifdef CONFIG_COCOA 225*3b0d4f61Sbellard if ( strncmp( filename, "/dev/cdrom", 10 ) == 0 ) { 226*3b0d4f61Sbellard kern_return_t kernResult; 227*3b0d4f61Sbellard io_iterator_t mediaIterator; 228*3b0d4f61Sbellard char bsdPath[ MAXPATHLEN ]; 229*3b0d4f61Sbellard int fd; 230*3b0d4f61Sbellard 231*3b0d4f61Sbellard kernResult = FindEjectableCDMedia( &mediaIterator ); 232*3b0d4f61Sbellard kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) ); 233*3b0d4f61Sbellard 234*3b0d4f61Sbellard if ( bsdPath[ 0 ] != '\0' ) { 235*3b0d4f61Sbellard strcat(bsdPath,"s0"); 236*3b0d4f61Sbellard /* some CDs don't have a partition 0 */ 237*3b0d4f61Sbellard fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE); 238*3b0d4f61Sbellard if (fd < 0) { 239*3b0d4f61Sbellard bsdPath[strlen(bsdPath)-1] = '1'; 240*3b0d4f61Sbellard } else { 241*3b0d4f61Sbellard close(fd); 242*3b0d4f61Sbellard } 243*3b0d4f61Sbellard filename = bsdPath; 244*3b0d4f61Sbellard } 245*3b0d4f61Sbellard 246*3b0d4f61Sbellard if ( mediaIterator ) 247*3b0d4f61Sbellard IOObjectRelease( mediaIterator ); 248*3b0d4f61Sbellard } 249*3b0d4f61Sbellard #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; 447ea2384d3Sbellard return bs->drv->bdrv_write(bs, sector_num, buf, nb_sectors); 448fc01f7e7Sbellard } 449fc01f7e7Sbellard 450fc01f7e7Sbellard void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr) 451fc01f7e7Sbellard { 452fc01f7e7Sbellard *nb_sectors_ptr = bs->total_sectors; 453fc01f7e7Sbellard } 454cf98951bSbellard 455cf98951bSbellard /* force a given boot sector. */ 456cf98951bSbellard void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size) 457cf98951bSbellard { 458cf98951bSbellard bs->boot_sector_enabled = 1; 459cf98951bSbellard if (size > 512) 460cf98951bSbellard size = 512; 461cf98951bSbellard memcpy(bs->boot_sector_data, data, size); 462cf98951bSbellard memset(bs->boot_sector_data + size, 0, 512 - size); 463cf98951bSbellard } 464b338082bSbellard 465b338082bSbellard void bdrv_set_geometry_hint(BlockDriverState *bs, 466b338082bSbellard int cyls, int heads, int secs) 467b338082bSbellard { 468b338082bSbellard bs->cyls = cyls; 469b338082bSbellard bs->heads = heads; 470b338082bSbellard bs->secs = secs; 471b338082bSbellard } 472b338082bSbellard 473b338082bSbellard void bdrv_set_type_hint(BlockDriverState *bs, int type) 474b338082bSbellard { 475b338082bSbellard bs->type = type; 476b338082bSbellard bs->removable = ((type == BDRV_TYPE_CDROM || 477b338082bSbellard type == BDRV_TYPE_FLOPPY)); 478b338082bSbellard } 479b338082bSbellard 48046d4767dSbellard void bdrv_set_translation_hint(BlockDriverState *bs, int translation) 48146d4767dSbellard { 48246d4767dSbellard bs->translation = translation; 48346d4767dSbellard } 48446d4767dSbellard 485b338082bSbellard void bdrv_get_geometry_hint(BlockDriverState *bs, 486b338082bSbellard int *pcyls, int *pheads, int *psecs) 487b338082bSbellard { 488b338082bSbellard *pcyls = bs->cyls; 489b338082bSbellard *pheads = bs->heads; 490b338082bSbellard *psecs = bs->secs; 491b338082bSbellard } 492b338082bSbellard 493b338082bSbellard int bdrv_get_type_hint(BlockDriverState *bs) 494b338082bSbellard { 495b338082bSbellard return bs->type; 496b338082bSbellard } 497b338082bSbellard 49846d4767dSbellard int bdrv_get_translation_hint(BlockDriverState *bs) 49946d4767dSbellard { 50046d4767dSbellard return bs->translation; 50146d4767dSbellard } 50246d4767dSbellard 503b338082bSbellard int bdrv_is_removable(BlockDriverState *bs) 504b338082bSbellard { 505b338082bSbellard return bs->removable; 506b338082bSbellard } 507b338082bSbellard 508b338082bSbellard int bdrv_is_read_only(BlockDriverState *bs) 509b338082bSbellard { 510b338082bSbellard return bs->read_only; 511b338082bSbellard } 512b338082bSbellard 513b338082bSbellard int bdrv_is_inserted(BlockDriverState *bs) 514b338082bSbellard { 515b338082bSbellard return bs->inserted; 516b338082bSbellard } 517b338082bSbellard 518b338082bSbellard int bdrv_is_locked(BlockDriverState *bs) 519b338082bSbellard { 520b338082bSbellard return bs->locked; 521b338082bSbellard } 522b338082bSbellard 523b338082bSbellard void bdrv_set_locked(BlockDriverState *bs, int locked) 524b338082bSbellard { 525b338082bSbellard bs->locked = locked; 526b338082bSbellard } 527b338082bSbellard 528b338082bSbellard void bdrv_set_change_cb(BlockDriverState *bs, 529b338082bSbellard void (*change_cb)(void *opaque), void *opaque) 530b338082bSbellard { 531b338082bSbellard bs->change_cb = change_cb; 532b338082bSbellard bs->change_opaque = opaque; 533b338082bSbellard } 534b338082bSbellard 535ea2384d3Sbellard int bdrv_is_encrypted(BlockDriverState *bs) 536ea2384d3Sbellard { 537ea2384d3Sbellard if (bs->backing_hd && bs->backing_hd->encrypted) 538ea2384d3Sbellard return 1; 539ea2384d3Sbellard return bs->encrypted; 540ea2384d3Sbellard } 541ea2384d3Sbellard 542ea2384d3Sbellard int bdrv_set_key(BlockDriverState *bs, const char *key) 543ea2384d3Sbellard { 544ea2384d3Sbellard int ret; 545ea2384d3Sbellard if (bs->backing_hd && bs->backing_hd->encrypted) { 546ea2384d3Sbellard ret = bdrv_set_key(bs->backing_hd, key); 547ea2384d3Sbellard if (ret < 0) 548ea2384d3Sbellard return ret; 549ea2384d3Sbellard if (!bs->encrypted) 550ea2384d3Sbellard return 0; 551ea2384d3Sbellard } 552ea2384d3Sbellard if (!bs->encrypted || !bs->drv || !bs->drv->bdrv_set_key) 553ea2384d3Sbellard return -1; 554ea2384d3Sbellard return bs->drv->bdrv_set_key(bs, key); 555ea2384d3Sbellard } 556ea2384d3Sbellard 557ea2384d3Sbellard void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size) 558ea2384d3Sbellard { 559ea2384d3Sbellard if (!bs->inserted || !bs->drv) { 560ea2384d3Sbellard buf[0] = '\0'; 561ea2384d3Sbellard } else { 562ea2384d3Sbellard pstrcpy(buf, buf_size, bs->drv->format_name); 563ea2384d3Sbellard } 564ea2384d3Sbellard } 565ea2384d3Sbellard 566ea2384d3Sbellard void bdrv_iterate_format(void (*it)(void *opaque, const char *name), 567ea2384d3Sbellard void *opaque) 568ea2384d3Sbellard { 569ea2384d3Sbellard BlockDriver *drv; 570ea2384d3Sbellard 571ea2384d3Sbellard for (drv = first_drv; drv != NULL; drv = drv->next) { 572ea2384d3Sbellard it(opaque, drv->format_name); 573ea2384d3Sbellard } 574ea2384d3Sbellard } 575ea2384d3Sbellard 576b338082bSbellard BlockDriverState *bdrv_find(const char *name) 577b338082bSbellard { 578b338082bSbellard BlockDriverState *bs; 579b338082bSbellard 580b338082bSbellard for (bs = bdrv_first; bs != NULL; bs = bs->next) { 581b338082bSbellard if (!strcmp(name, bs->device_name)) 582b338082bSbellard return bs; 583b338082bSbellard } 584b338082bSbellard return NULL; 585b338082bSbellard } 586b338082bSbellard 58781d0912dSbellard void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque) 58881d0912dSbellard { 58981d0912dSbellard BlockDriverState *bs; 59081d0912dSbellard 59181d0912dSbellard for (bs = bdrv_first; bs != NULL; bs = bs->next) { 59281d0912dSbellard it(opaque, bs->device_name); 59381d0912dSbellard } 59481d0912dSbellard } 59581d0912dSbellard 596ea2384d3Sbellard const char *bdrv_get_device_name(BlockDriverState *bs) 597ea2384d3Sbellard { 598ea2384d3Sbellard return bs->device_name; 599ea2384d3Sbellard } 600ea2384d3Sbellard 601b338082bSbellard void bdrv_info(void) 602b338082bSbellard { 603b338082bSbellard BlockDriverState *bs; 604b338082bSbellard 605b338082bSbellard for (bs = bdrv_first; bs != NULL; bs = bs->next) { 606b338082bSbellard term_printf("%s:", bs->device_name); 607b338082bSbellard term_printf(" type="); 608b338082bSbellard switch(bs->type) { 609b338082bSbellard case BDRV_TYPE_HD: 610b338082bSbellard term_printf("hd"); 611b338082bSbellard break; 612b338082bSbellard case BDRV_TYPE_CDROM: 613b338082bSbellard term_printf("cdrom"); 614b338082bSbellard break; 615b338082bSbellard case BDRV_TYPE_FLOPPY: 616b338082bSbellard term_printf("floppy"); 617b338082bSbellard break; 618b338082bSbellard } 619b338082bSbellard term_printf(" removable=%d", bs->removable); 620b338082bSbellard if (bs->removable) { 621b338082bSbellard term_printf(" locked=%d", bs->locked); 622b338082bSbellard } 623b338082bSbellard if (bs->inserted) { 624b338082bSbellard term_printf(" file=%s", bs->filename); 625ea2384d3Sbellard if (bs->backing_file[0] != '\0') 626ea2384d3Sbellard term_printf(" backing_file=%s", bs->backing_file); 627b338082bSbellard term_printf(" ro=%d", bs->read_only); 628ea2384d3Sbellard term_printf(" drv=%s", bs->drv->format_name); 629ea2384d3Sbellard if (bs->encrypted) 630ea2384d3Sbellard term_printf(" encrypted"); 631b338082bSbellard } else { 632b338082bSbellard term_printf(" [not inserted]"); 633b338082bSbellard } 634b338082bSbellard term_printf("\n"); 635b338082bSbellard } 636b338082bSbellard } 637ea2384d3Sbellard 638ea2384d3Sbellard 639ea2384d3Sbellard /**************************************************************/ 640ea2384d3Sbellard /* RAW block driver */ 641ea2384d3Sbellard 642ea2384d3Sbellard typedef struct BDRVRawState { 643ea2384d3Sbellard int fd; 644ea2384d3Sbellard } BDRVRawState; 645ea2384d3Sbellard 646ea2384d3Sbellard static int raw_probe(const uint8_t *buf, int buf_size, const char *filename) 647ea2384d3Sbellard { 648ea2384d3Sbellard return 1; /* maybe */ 649ea2384d3Sbellard } 650ea2384d3Sbellard 651ea2384d3Sbellard static int raw_open(BlockDriverState *bs, const char *filename) 652ea2384d3Sbellard { 653ea2384d3Sbellard BDRVRawState *s = bs->opaque; 654ea2384d3Sbellard int fd; 655ea2384d3Sbellard int64_t size; 656e5484d33Sbellard #ifdef _BSD 657e5484d33Sbellard struct stat sb; 658e5484d33Sbellard #endif 659ea2384d3Sbellard 660ea2384d3Sbellard fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); 661ea2384d3Sbellard if (fd < 0) { 662ea2384d3Sbellard fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); 663ea2384d3Sbellard if (fd < 0) 664ea2384d3Sbellard return -1; 665ea2384d3Sbellard bs->read_only = 1; 666ea2384d3Sbellard } 6677674e7bfSbellard #ifdef _BSD 6687674e7bfSbellard if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) { 6697674e7bfSbellard #ifdef DIOCGMEDIASIZE 6707674e7bfSbellard if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size)) 6717674e7bfSbellard #endif 672*3b0d4f61Sbellard #ifdef CONFIG_COCOA 673*3b0d4f61Sbellard size = LONG_LONG_MAX; 674*3b0d4f61Sbellard #else 6757674e7bfSbellard size = lseek(fd, 0LL, SEEK_END); 676*3b0d4f61Sbellard #endif 6777674e7bfSbellard } else 6787674e7bfSbellard #endif 6797674e7bfSbellard { 680d5249393Sbellard size = lseek(fd, 0, SEEK_END); 6817674e7bfSbellard } 682c747cd1fSbellard #ifdef _WIN32 683c747cd1fSbellard /* On Windows hosts it can happen that we're unable to get file size 684c747cd1fSbellard for CD-ROM raw device (it's inherent limitation of the CDFS driver). */ 685c747cd1fSbellard if (size == -1) 686c747cd1fSbellard size = LONG_LONG_MAX; 687c747cd1fSbellard #endif 688ea2384d3Sbellard bs->total_sectors = size / 512; 689ea2384d3Sbellard s->fd = fd; 690ea2384d3Sbellard return 0; 691ea2384d3Sbellard } 692ea2384d3Sbellard 693ea2384d3Sbellard static int raw_read(BlockDriverState *bs, int64_t sector_num, 694ea2384d3Sbellard uint8_t *buf, int nb_sectors) 695ea2384d3Sbellard { 696ea2384d3Sbellard BDRVRawState *s = bs->opaque; 697ea2384d3Sbellard int ret; 698ea2384d3Sbellard 699d5249393Sbellard lseek(s->fd, sector_num * 512, SEEK_SET); 700ea2384d3Sbellard ret = read(s->fd, buf, nb_sectors * 512); 701ea2384d3Sbellard if (ret != nb_sectors * 512) 702ea2384d3Sbellard return -1; 703ea2384d3Sbellard return 0; 704ea2384d3Sbellard } 705ea2384d3Sbellard 706ea2384d3Sbellard static int raw_write(BlockDriverState *bs, int64_t sector_num, 707ea2384d3Sbellard const 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 = write(s->fd, buf, nb_sectors * 512); 714ea2384d3Sbellard if (ret != nb_sectors * 512) 715ea2384d3Sbellard return -1; 716ea2384d3Sbellard return 0; 717ea2384d3Sbellard } 718ea2384d3Sbellard 719e2731addSbellard static void raw_close(BlockDriverState *bs) 720ea2384d3Sbellard { 721ea2384d3Sbellard BDRVRawState *s = bs->opaque; 722ea2384d3Sbellard close(s->fd); 723ea2384d3Sbellard } 724ea2384d3Sbellard 725ea2384d3Sbellard static int raw_create(const char *filename, int64_t total_size, 726ea2384d3Sbellard const char *backing_file, int flags) 727ea2384d3Sbellard { 728ea2384d3Sbellard int fd; 729ea2384d3Sbellard 730ea2384d3Sbellard if (flags || backing_file) 731ea2384d3Sbellard return -ENOTSUP; 732ea2384d3Sbellard 733ea2384d3Sbellard fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 734ea2384d3Sbellard 0644); 735ea2384d3Sbellard if (fd < 0) 736ea2384d3Sbellard return -EIO; 737d5249393Sbellard ftruncate(fd, total_size * 512); 738ea2384d3Sbellard close(fd); 739ea2384d3Sbellard return 0; 740ea2384d3Sbellard } 741ea2384d3Sbellard 742ea2384d3Sbellard BlockDriver bdrv_raw = { 743ea2384d3Sbellard "raw", 744ea2384d3Sbellard sizeof(BDRVRawState), 745ea2384d3Sbellard raw_probe, 746ea2384d3Sbellard raw_open, 747ea2384d3Sbellard raw_read, 748ea2384d3Sbellard raw_write, 749ea2384d3Sbellard raw_close, 750ea2384d3Sbellard raw_create, 751ea2384d3Sbellard }; 752ea2384d3Sbellard 753ea2384d3Sbellard void bdrv_init(void) 754ea2384d3Sbellard { 755ea2384d3Sbellard bdrv_register(&bdrv_raw); 756ea2384d3Sbellard #ifndef _WIN32 757ea2384d3Sbellard bdrv_register(&bdrv_cow); 758ea2384d3Sbellard #endif 759ea2384d3Sbellard bdrv_register(&bdrv_qcow); 760ea2384d3Sbellard bdrv_register(&bdrv_vmdk); 7613c56521bSbellard bdrv_register(&bdrv_cloop); 762585d0ed9Sbellard bdrv_register(&bdrv_dmg); 763a8753c34Sbellard bdrv_register(&bdrv_bochs); 7646a0f9e82Sbellard bdrv_register(&bdrv_vpc); 765712e7874Sbellard bdrv_register(&bdrv_vvfat); 766ea2384d3Sbellard } 767