File:  [Qemu by Fabrice Bellard] / qemu / block.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 16:40:43 2018 UTC (2 years, 5 months ago) by root
Branches: qemu, MAIN
CVS tags: qemu0081, HEAD
qemu 0.8.1

    1: /*
    2:  * QEMU System Emulator block driver
    3:  * 
    4:  * Copyright (c) 2003 Fabrice Bellard
    5:  * 
    6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
    7:  * of this software and associated documentation files (the "Software"), to deal
    8:  * in the Software without restriction, including without limitation the rights
    9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   10:  * copies of the Software, and to permit persons to whom the Software is
   11:  * furnished to do so, subject to the following conditions:
   12:  *
   13:  * The above copyright notice and this permission notice shall be included in
   14:  * all copies or substantial portions of the Software.
   15:  *
   16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   22:  * THE SOFTWARE.
   23:  */
   24: #include "vl.h"
   25: #include "block_int.h"
   26: 
   27: #ifdef _BSD
   28: #include <sys/types.h>
   29: #include <sys/stat.h>
   30: #include <sys/ioctl.h>
   31: #include <sys/queue.h>
   32: #include <sys/disk.h>
   33: #endif
   34: 
   35: #ifdef CONFIG_COCOA
   36: #include <paths.h>
   37: #include <sys/param.h>
   38: #include <IOKit/IOKitLib.h>
   39: #include <IOKit/IOBSD.h>
   40: #include <IOKit/storage/IOMediaBSDClient.h>
   41: #include <IOKit/storage/IOMedia.h>
   42: #include <IOKit/storage/IOCDMedia.h>
   43: //#include <IOKit/storage/IOCDTypes.h>
   44: #include <CoreFoundation/CoreFoundation.h>
   45: #endif
   46: 
   47: #ifdef __sun__
   48: #include <sys/dkio.h>
   49: #endif
   50: 
   51: static BlockDriverState *bdrv_first;
   52: static BlockDriver *first_drv;
   53: 
   54: #ifdef CONFIG_COCOA
   55: static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator );
   56: static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize );
   57: 
   58: kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
   59: {
   60:     kern_return_t       kernResult; 
   61:     mach_port_t     masterPort;
   62:     CFMutableDictionaryRef  classesToMatch;
   63: 
   64:     kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort );
   65:     if ( KERN_SUCCESS != kernResult ) {
   66:         printf( "IOMasterPort returned %d\n", kernResult );
   67:     }
   68:     
   69:     classesToMatch = IOServiceMatching( kIOCDMediaClass ); 
   70:     if ( classesToMatch == NULL ) {
   71:         printf( "IOServiceMatching returned a NULL dictionary.\n" );
   72:     } else {
   73:     CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue );
   74:     }
   75:     kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, mediaIterator );
   76:     if ( KERN_SUCCESS != kernResult )
   77:     {
   78:         printf( "IOServiceGetMatchingServices returned %d\n", kernResult );
   79:     }
   80:     
   81:     return kernResult;
   82: }
   83: 
   84: kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize )
   85: {
   86:     io_object_t     nextMedia;
   87:     kern_return_t   kernResult = KERN_FAILURE;
   88:     *bsdPath = '\0';
   89:     nextMedia = IOIteratorNext( mediaIterator );
   90:     if ( nextMedia )
   91:     {
   92:         CFTypeRef   bsdPathAsCFString;
   93:     bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia, CFSTR( kIOBSDNameKey ), kCFAllocatorDefault, 0 );
   94:         if ( bsdPathAsCFString ) {
   95:             size_t devPathLength;
   96:             strcpy( bsdPath, _PATH_DEV );
   97:             strcat( bsdPath, "r" );
   98:             devPathLength = strlen( bsdPath );
   99:             if ( CFStringGetCString( bsdPathAsCFString, bsdPath + devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) {
  100:                 kernResult = KERN_SUCCESS;
  101:             }
  102:             CFRelease( bsdPathAsCFString );
  103:         }
  104:         IOObjectRelease( nextMedia );
  105:     }
  106:     
  107:     return kernResult;
  108: }
  109: 
  110: #endif
  111: 
  112: void bdrv_register(BlockDriver *bdrv)
  113: {
  114:     bdrv->next = first_drv;
  115:     first_drv = bdrv;
  116: }
  117: 
  118: /* create a new block device (by default it is empty) */
  119: BlockDriverState *bdrv_new(const char *device_name)
  120: {
  121:     BlockDriverState **pbs, *bs;
  122: 
  123:     bs = qemu_mallocz(sizeof(BlockDriverState));
  124:     if(!bs)
  125:         return NULL;
  126:     pstrcpy(bs->device_name, sizeof(bs->device_name), device_name);
  127:     if (device_name[0] != '\0') {
  128:         /* insert at the end */
  129:         pbs = &bdrv_first;
  130:         while (*pbs != NULL)
  131:             pbs = &(*pbs)->next;
  132:         *pbs = bs;
  133:     }
  134:     return bs;
  135: }
  136: 
  137: BlockDriver *bdrv_find_format(const char *format_name)
  138: {
  139:     BlockDriver *drv1;
  140:     for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
  141:         if (!strcmp(drv1->format_name, format_name))
  142:             return drv1;
  143:     }
  144:     return NULL;
  145: }
  146: 
  147: int bdrv_create(BlockDriver *drv, 
  148:                 const char *filename, int64_t size_in_sectors,
  149:                 const char *backing_file, int flags)
  150: {
  151:     if (!drv->bdrv_create)
  152:         return -ENOTSUP;
  153:     return drv->bdrv_create(filename, size_in_sectors, backing_file, flags);
  154: }
  155: 
  156: #ifdef _WIN32
  157: void get_tmp_filename(char *filename, int size)
  158: {
  159:     char* p = strrchr(filename, '/');
  160: 
  161:     if (p == NULL)
  162: 	return;
  163: 
  164:     /* XXX: find a better function */
  165:     tmpnam(p);
  166:     *p = '/';
  167: }
  168: #else
  169: void get_tmp_filename(char *filename, int size)
  170: {
  171:     int fd;
  172:     /* XXX: race condition possible */
  173:     pstrcpy(filename, size, "/tmp/vl.XXXXXX");
  174:     fd = mkstemp(filename);
  175:     close(fd);
  176: }
  177: #endif
  178: 
  179: /* XXX: force raw format if block or character device ? It would
  180:    simplify the BSD case */
  181: static BlockDriver *find_image_format(const char *filename)
  182: {
  183:     int fd, ret, score, score_max;
  184:     BlockDriver *drv1, *drv;
  185:     uint8_t *buf;
  186:     size_t bufsize = 1024;
  187: 
  188:     fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
  189:     if (fd < 0) {
  190:         buf = NULL;
  191:         ret = 0;
  192:     } else {
  193: #ifdef DIOCGSECTORSIZE
  194:         {
  195:             unsigned int sectorsize = 512;
  196:             if (!ioctl(fd, DIOCGSECTORSIZE, &sectorsize) &&
  197:                 sectorsize > bufsize)
  198:                 bufsize = sectorsize;
  199:         }
  200: #endif
  201: #ifdef CONFIG_COCOA
  202:         u_int32_t   blockSize = 512;
  203:         if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize > bufsize) {
  204:             bufsize = blockSize;
  205:         }
  206: #endif
  207:         buf = qemu_malloc(bufsize);
  208:         if (!buf)
  209:             return NULL;
  210:         ret = read(fd, buf, bufsize);
  211:         if (ret < 0) {
  212:             close(fd);
  213:             qemu_free(buf);
  214:             return NULL;
  215:         }
  216:         close(fd);
  217:     }
  218:     
  219:     drv = NULL;
  220:     score_max = 0;
  221:     for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
  222:         score = drv1->bdrv_probe(buf, ret, filename);
  223:         if (score > score_max) {
  224:             score_max = score;
  225:             drv = drv1;
  226:         }
  227:     }
  228:     qemu_free(buf);
  229:     return drv;
  230: }
  231: 
  232: int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot)
  233: {
  234: #ifdef CONFIG_COCOA
  235:     if ( strncmp( filename, "/dev/cdrom", 10 ) == 0 ) {
  236:         kern_return_t kernResult;
  237:         io_iterator_t mediaIterator;
  238:         char bsdPath[ MAXPATHLEN ];
  239:         int fd;
  240:  
  241:         kernResult = FindEjectableCDMedia( &mediaIterator );
  242:         kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) );
  243:     
  244:         if ( bsdPath[ 0 ] != '\0' ) {
  245:             strcat(bsdPath,"s0");
  246:             /* some CDs don't have a partition 0 */
  247:             fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE);
  248:             if (fd < 0) {
  249:                 bsdPath[strlen(bsdPath)-1] = '1';
  250:             } else {
  251:                 close(fd);
  252:             }
  253:             filename = bsdPath;
  254:         }
  255:         
  256:         if ( mediaIterator )
  257:             IOObjectRelease( mediaIterator );
  258:     }
  259: #endif
  260:     return bdrv_open2(bs, filename, snapshot, NULL);
  261: }
  262: 
  263: int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot,
  264:                BlockDriver *drv)
  265: {
  266:     int ret;
  267:     char tmp_filename[1024];
  268:     
  269:     bs->read_only = 0;
  270:     bs->is_temporary = 0;
  271:     bs->encrypted = 0;
  272: 
  273:     if (snapshot) {
  274:         BlockDriverState *bs1;
  275:         int64_t total_size;
  276:         
  277:         /* if snapshot, we create a temporary backing file and open it
  278:            instead of opening 'filename' directly */
  279: 
  280:         /* if there is a backing file, use it */
  281:         bs1 = bdrv_new("");
  282:         if (!bs1) {
  283:             return -1;
  284:         }
  285:         if (bdrv_open(bs1, filename, 0) < 0) {
  286:             bdrv_delete(bs1);
  287:             return -1;
  288:         }
  289:         total_size = bs1->total_sectors;
  290:         bdrv_delete(bs1);
  291:         
  292:         get_tmp_filename(tmp_filename, sizeof(tmp_filename));
  293:         /* XXX: use cow for linux as it is more efficient ? */
  294:         if (bdrv_create(&bdrv_qcow, tmp_filename, 
  295:                         total_size, filename, 0) < 0) {
  296:             return -1;
  297:         }
  298:         filename = tmp_filename;
  299:         bs->is_temporary = 1;
  300:     }
  301: 
  302:     pstrcpy(bs->filename, sizeof(bs->filename), filename);
  303:     if (!drv) {
  304:         drv = find_image_format(filename);
  305:         if (!drv)
  306:             return -1;
  307:     }
  308:     bs->drv = drv;
  309:     bs->opaque = qemu_mallocz(drv->instance_size);
  310:     if (bs->opaque == NULL && drv->instance_size > 0)
  311:         return -1;
  312:     
  313:     ret = drv->bdrv_open(bs, filename);
  314:     if (ret < 0) {
  315:         qemu_free(bs->opaque);
  316:         return -1;
  317:     }
  318: #ifndef _WIN32
  319:     if (bs->is_temporary) {
  320:         unlink(filename);
  321:     }
  322: #endif
  323:     if (bs->backing_file[0] != '\0' && drv->bdrv_is_allocated) {
  324:         /* if there is a backing file, use it */
  325:         bs->backing_hd = bdrv_new("");
  326:         if (!bs->backing_hd) {
  327:         fail:
  328:             bdrv_close(bs);
  329:             return -1;
  330:         }
  331:         if (bdrv_open(bs->backing_hd, bs->backing_file, 0) < 0)
  332:             goto fail;
  333:     }
  334: 
  335:     bs->inserted = 1;
  336: 
  337:     /* call the change callback */
  338:     if (bs->change_cb)
  339:         bs->change_cb(bs->change_opaque);
  340: 
  341:     return 0;
  342: }
  343: 
  344: void bdrv_close(BlockDriverState *bs)
  345: {
  346:     if (bs->inserted) {
  347:         if (bs->backing_hd)
  348:             bdrv_delete(bs->backing_hd);
  349:         bs->drv->bdrv_close(bs);
  350:         qemu_free(bs->opaque);
  351: #ifdef _WIN32
  352:         if (bs->is_temporary) {
  353:             unlink(bs->filename);
  354:         }
  355: #endif
  356:         bs->opaque = NULL;
  357:         bs->drv = NULL;
  358:         bs->inserted = 0;
  359: 
  360:         /* call the change callback */
  361:         if (bs->change_cb)
  362:             bs->change_cb(bs->change_opaque);
  363:     }
  364: }
  365: 
  366: void bdrv_delete(BlockDriverState *bs)
  367: {
  368:     /* XXX: remove the driver list */
  369:     bdrv_close(bs);
  370:     qemu_free(bs);
  371: }
  372: 
  373: /* commit COW file into the raw image */
  374: int bdrv_commit(BlockDriverState *bs)
  375: {
  376:     int64_t i;
  377:     int n, j;
  378:     unsigned char sector[512];
  379: 
  380:     if (!bs->inserted)
  381:         return -ENOENT;
  382: 
  383:     if (bs->read_only) {
  384: 	return -EACCES;
  385:     }
  386: 
  387:     if (!bs->backing_hd) {
  388: 	return -ENOTSUP;
  389:     }
  390: 
  391:     for (i = 0; i < bs->total_sectors;) {
  392:         if (bs->drv->bdrv_is_allocated(bs, i, 65536, &n)) {
  393:             for(j = 0; j < n; j++) {
  394:                 if (bdrv_read(bs, i, sector, 1) != 0) {
  395:                     return -EIO;
  396:                 }
  397: 
  398:                 if (bdrv_write(bs->backing_hd, i, sector, 1) != 0) {
  399:                     return -EIO;
  400:                 }
  401:                 i++;
  402: 	    }
  403: 	} else {
  404:             i += n;
  405:         }
  406:     }
  407: 
  408:     if (bs->drv->bdrv_make_empty)
  409: 	return bs->drv->bdrv_make_empty(bs);
  410: 
  411:     return 0;
  412: }
  413: 
  414: /* return -1 if error */
  415: int bdrv_read(BlockDriverState *bs, int64_t sector_num, 
  416:               uint8_t *buf, int nb_sectors)
  417: {
  418:     int ret, n;
  419:     BlockDriver *drv = bs->drv;
  420: 
  421:     if (!bs->inserted)
  422:         return -1;
  423: 
  424:     while (nb_sectors > 0) {
  425:         if (sector_num == 0 && bs->boot_sector_enabled) {
  426:             memcpy(buf, bs->boot_sector_data, 512);
  427:             n = 1;
  428:         } else if (bs->backing_hd) {
  429:             if (drv->bdrv_is_allocated(bs, sector_num, nb_sectors, &n)) {
  430:                 ret = drv->bdrv_read(bs, sector_num, buf, n);
  431:                 if (ret < 0)
  432:                     return -1;
  433:             } else {
  434:                 /* read from the base image */
  435:                 ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
  436:                 if (ret < 0)
  437:                     return -1;
  438:             }
  439:         } else {
  440:             ret = drv->bdrv_read(bs, sector_num, buf, nb_sectors);
  441:             if (ret < 0)
  442:                 return -1;
  443:             /* no need to loop */
  444:             break;
  445:         }
  446:         nb_sectors -= n;
  447:         sector_num += n;
  448:         buf += n * 512;
  449:     }
  450:     return 0;
  451: }
  452: 
  453: /* return -1 if error */
  454: int bdrv_write(BlockDriverState *bs, int64_t sector_num, 
  455:                const uint8_t *buf, int nb_sectors)
  456: {
  457:     if (!bs->inserted)
  458:         return -1;
  459:     if (bs->read_only)
  460:         return -1;
  461:     if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
  462:         memcpy(bs->boot_sector_data, buf, 512);   
  463:     }
  464:     return bs->drv->bdrv_write(bs, sector_num, buf, nb_sectors);
  465: }
  466: 
  467: void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)
  468: {
  469:     *nb_sectors_ptr = bs->total_sectors;
  470: }
  471: 
  472: /* force a given boot sector. */
  473: void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size)
  474: {
  475:     bs->boot_sector_enabled = 1;
  476:     if (size > 512)
  477:         size = 512;
  478:     memcpy(bs->boot_sector_data, data, size);
  479:     memset(bs->boot_sector_data + size, 0, 512 - size);
  480: }
  481: 
  482: void bdrv_set_geometry_hint(BlockDriverState *bs, 
  483:                             int cyls, int heads, int secs)
  484: {
  485:     bs->cyls = cyls;
  486:     bs->heads = heads;
  487:     bs->secs = secs;
  488: }
  489: 
  490: void bdrv_set_type_hint(BlockDriverState *bs, int type)
  491: {
  492:     bs->type = type;
  493:     bs->removable = ((type == BDRV_TYPE_CDROM ||
  494:                       type == BDRV_TYPE_FLOPPY));
  495: }
  496: 
  497: void bdrv_set_translation_hint(BlockDriverState *bs, int translation)
  498: {
  499:     bs->translation = translation;
  500: }
  501: 
  502: void bdrv_get_geometry_hint(BlockDriverState *bs, 
  503:                             int *pcyls, int *pheads, int *psecs)
  504: {
  505:     *pcyls = bs->cyls;
  506:     *pheads = bs->heads;
  507:     *psecs = bs->secs;
  508: }
  509: 
  510: int bdrv_get_type_hint(BlockDriverState *bs)
  511: {
  512:     return bs->type;
  513: }
  514: 
  515: int bdrv_get_translation_hint(BlockDriverState *bs)
  516: {
  517:     return bs->translation;
  518: }
  519: 
  520: int bdrv_is_removable(BlockDriverState *bs)
  521: {
  522:     return bs->removable;
  523: }
  524: 
  525: int bdrv_is_read_only(BlockDriverState *bs)
  526: {
  527:     return bs->read_only;
  528: }
  529: 
  530: int bdrv_is_inserted(BlockDriverState *bs)
  531: {
  532:     return bs->inserted;
  533: }
  534: 
  535: int bdrv_is_locked(BlockDriverState *bs)
  536: {
  537:     return bs->locked;
  538: }
  539: 
  540: void bdrv_set_locked(BlockDriverState *bs, int locked)
  541: {
  542:     bs->locked = locked;
  543: }
  544: 
  545: void bdrv_set_change_cb(BlockDriverState *bs, 
  546:                         void (*change_cb)(void *opaque), void *opaque)
  547: {
  548:     bs->change_cb = change_cb;
  549:     bs->change_opaque = opaque;
  550: }
  551: 
  552: int bdrv_is_encrypted(BlockDriverState *bs)
  553: {
  554:     if (bs->backing_hd && bs->backing_hd->encrypted)
  555:         return 1;
  556:     return bs->encrypted;
  557: }
  558: 
  559: int bdrv_set_key(BlockDriverState *bs, const char *key)
  560: {
  561:     int ret;
  562:     if (bs->backing_hd && bs->backing_hd->encrypted) {
  563:         ret = bdrv_set_key(bs->backing_hd, key);
  564:         if (ret < 0)
  565:             return ret;
  566:         if (!bs->encrypted)
  567:             return 0;
  568:     }
  569:     if (!bs->encrypted || !bs->drv || !bs->drv->bdrv_set_key)
  570:         return -1;
  571:     return bs->drv->bdrv_set_key(bs, key);
  572: }
  573: 
  574: void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size)
  575: {
  576:     if (!bs->inserted || !bs->drv) {
  577:         buf[0] = '\0';
  578:     } else {
  579:         pstrcpy(buf, buf_size, bs->drv->format_name);
  580:     }
  581: }
  582: 
  583: void bdrv_iterate_format(void (*it)(void *opaque, const char *name), 
  584:                          void *opaque)
  585: {
  586:     BlockDriver *drv;
  587: 
  588:     for (drv = first_drv; drv != NULL; drv = drv->next) {
  589:         it(opaque, drv->format_name);
  590:     }
  591: }
  592: 
  593: BlockDriverState *bdrv_find(const char *name)
  594: {
  595:     BlockDriverState *bs;
  596: 
  597:     for (bs = bdrv_first; bs != NULL; bs = bs->next) {
  598:         if (!strcmp(name, bs->device_name))
  599:             return bs;
  600:     }
  601:     return NULL;
  602: }
  603: 
  604: void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque)
  605: {
  606:     BlockDriverState *bs;
  607: 
  608:     for (bs = bdrv_first; bs != NULL; bs = bs->next) {
  609:         it(opaque, bs->device_name);
  610:     }
  611: }
  612: 
  613: const char *bdrv_get_device_name(BlockDriverState *bs)
  614: {
  615:     return bs->device_name;
  616: }
  617: 
  618: void bdrv_info(void)
  619: {
  620:     BlockDriverState *bs;
  621: 
  622:     for (bs = bdrv_first; bs != NULL; bs = bs->next) {
  623:         term_printf("%s:", bs->device_name);
  624:         term_printf(" type=");
  625:         switch(bs->type) {
  626:         case BDRV_TYPE_HD:
  627:             term_printf("hd");
  628:             break;
  629:         case BDRV_TYPE_CDROM:
  630:             term_printf("cdrom");
  631:             break;
  632:         case BDRV_TYPE_FLOPPY:
  633:             term_printf("floppy");
  634:             break;
  635:         }
  636:         term_printf(" removable=%d", bs->removable);
  637:         if (bs->removable) {
  638:             term_printf(" locked=%d", bs->locked);
  639:         }
  640:         if (bs->inserted) {
  641:             term_printf(" file=%s", bs->filename);
  642:             if (bs->backing_file[0] != '\0')
  643:                 term_printf(" backing_file=%s", bs->backing_file);
  644:             term_printf(" ro=%d", bs->read_only);
  645:             term_printf(" drv=%s", bs->drv->format_name);
  646:             if (bs->encrypted)
  647:                 term_printf(" encrypted");
  648:         } else {
  649:             term_printf(" [not inserted]");
  650:         }
  651:         term_printf("\n");
  652:     }
  653: }
  654: 
  655: /**************************************************************/
  656: /* RAW block driver */
  657: 
  658: typedef struct BDRVRawState {
  659:     int fd;
  660: } BDRVRawState;
  661: 
  662: static int raw_probe(const uint8_t *buf, int buf_size, const char *filename)
  663: {
  664:     return 1; /* maybe */
  665: }
  666: 
  667: static int raw_open(BlockDriverState *bs, const char *filename)
  668: {
  669:     BDRVRawState *s = bs->opaque;
  670:     int fd;
  671:     int64_t size;
  672: #ifdef _BSD
  673:     struct stat sb;
  674: #endif
  675: #ifdef __sun__
  676:     struct dk_minfo minfo;
  677:     int rv;
  678: #endif
  679: 
  680:     fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
  681:     if (fd < 0) {
  682:         fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
  683:         if (fd < 0)
  684:             return -1;
  685:         bs->read_only = 1;
  686:     }
  687: #ifdef _BSD
  688:     if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
  689: #ifdef DIOCGMEDIASIZE
  690: 	if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
  691: #endif
  692: #ifdef CONFIG_COCOA
  693:         size = LONG_LONG_MAX;
  694: #else
  695:         size = lseek(fd, 0LL, SEEK_END);
  696: #endif
  697:     } else
  698: #endif
  699: #ifdef __sun__
  700:     /*
  701:      * use the DKIOCGMEDIAINFO ioctl to read the size.
  702:      */
  703:     rv = ioctl ( fd, DKIOCGMEDIAINFO, &minfo );
  704:     if ( rv != -1 ) {
  705:         size = minfo.dki_lbsize * minfo.dki_capacity;
  706:     } else /* there are reports that lseek on some devices
  707:               fails, but irc discussion said that contingency
  708:               on contingency was overkill */
  709: #endif
  710:     {
  711:         size = lseek(fd, 0, SEEK_END);
  712:     }
  713: #ifdef _WIN32
  714:     /* On Windows hosts it can happen that we're unable to get file size
  715:        for CD-ROM raw device (it's inherent limitation of the CDFS driver). */
  716:     if (size == -1)
  717:         size = LONG_LONG_MAX;
  718: #endif
  719:     bs->total_sectors = size / 512;
  720:     s->fd = fd;
  721:     return 0;
  722: }
  723: 
  724: static int raw_read(BlockDriverState *bs, int64_t sector_num, 
  725:                     uint8_t *buf, int nb_sectors)
  726: {
  727:     BDRVRawState *s = bs->opaque;
  728:     int ret;
  729:     
  730:     lseek(s->fd, sector_num * 512, SEEK_SET);
  731:     ret = read(s->fd, buf, nb_sectors * 512);
  732:     if (ret != nb_sectors * 512) 
  733:         return -1;
  734:     return 0;
  735: }
  736: 
  737: static int raw_write(BlockDriverState *bs, int64_t sector_num, 
  738:                      const uint8_t *buf, int nb_sectors)
  739: {
  740:     BDRVRawState *s = bs->opaque;
  741:     int ret;
  742:     
  743:     lseek(s->fd, sector_num * 512, SEEK_SET);
  744:     ret = write(s->fd, buf, nb_sectors * 512);
  745:     if (ret != nb_sectors * 512) 
  746:         return -1;
  747:     return 0;
  748: }
  749: 
  750: static void raw_close(BlockDriverState *bs)
  751: {
  752:     BDRVRawState *s = bs->opaque;
  753:     close(s->fd);
  754: }
  755: 
  756: static int raw_create(const char *filename, int64_t total_size,
  757:                       const char *backing_file, int flags)
  758: {
  759:     int fd;
  760: 
  761:     if (flags || backing_file)
  762:         return -ENOTSUP;
  763: 
  764:     fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 
  765:               0644);
  766:     if (fd < 0)
  767:         return -EIO;
  768:     ftruncate(fd, total_size * 512);
  769:     close(fd);
  770:     return 0;
  771: }
  772: 
  773: BlockDriver bdrv_raw = {
  774:     "raw",
  775:     sizeof(BDRVRawState),
  776:     raw_probe,
  777:     raw_open,
  778:     raw_read,
  779:     raw_write,
  780:     raw_close,
  781:     raw_create,
  782: };
  783: 
  784: void bdrv_init(void)
  785: {
  786:     bdrv_register(&bdrv_raw);
  787: #ifndef _WIN32
  788:     bdrv_register(&bdrv_cow);
  789: #endif
  790:     bdrv_register(&bdrv_qcow);
  791:     bdrv_register(&bdrv_vmdk);
  792:     bdrv_register(&bdrv_cloop);
  793:     bdrv_register(&bdrv_dmg);
  794:     bdrv_register(&bdrv_bochs);
  795:     bdrv_register(&bdrv_vpc);
  796:     bdrv_register(&bdrv_vvfat);
  797: }

unix.superglobalmegacorp.com