Annotation of qemu/block.c, revision 1.1

1.1     ! root        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: static BlockDriverState *bdrv_first;
        !            36: static BlockDriver *first_drv;
        !            37: 
        !            38: void bdrv_register(BlockDriver *bdrv)
        !            39: {
        !            40:     bdrv->next = first_drv;
        !            41:     first_drv = bdrv;
        !            42: }
        !            43: 
        !            44: /* create a new block device (by default it is empty) */
        !            45: BlockDriverState *bdrv_new(const char *device_name)
        !            46: {
        !            47:     BlockDriverState **pbs, *bs;
        !            48: 
        !            49:     bs = qemu_mallocz(sizeof(BlockDriverState));
        !            50:     if(!bs)
        !            51:         return NULL;
        !            52:     pstrcpy(bs->device_name, sizeof(bs->device_name), device_name);
        !            53:     if (device_name[0] != '\0') {
        !            54:         /* insert at the end */
        !            55:         pbs = &bdrv_first;
        !            56:         while (*pbs != NULL)
        !            57:             pbs = &(*pbs)->next;
        !            58:         *pbs = bs;
        !            59:     }
        !            60:     return bs;
        !            61: }
        !            62: 
        !            63: BlockDriver *bdrv_find_format(const char *format_name)
        !            64: {
        !            65:     BlockDriver *drv1;
        !            66:     for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
        !            67:         if (!strcmp(drv1->format_name, format_name))
        !            68:             return drv1;
        !            69:     }
        !            70:     return NULL;
        !            71: }
        !            72: 
        !            73: int bdrv_create(BlockDriver *drv, 
        !            74:                 const char *filename, int64_t size_in_sectors,
        !            75:                 const char *backing_file, int flags)
        !            76: {
        !            77:     if (!drv->bdrv_create)
        !            78:         return -ENOTSUP;
        !            79:     return drv->bdrv_create(filename, size_in_sectors, backing_file, flags);
        !            80: }
        !            81: 
        !            82: #ifdef _WIN32
        !            83: static void get_tmp_filename(char *filename, int size)
        !            84: {
        !            85:     /* XXX: find a better function */
        !            86:     tmpnam(filename);
        !            87: }
        !            88: #else
        !            89: static void get_tmp_filename(char *filename, int size)
        !            90: {
        !            91:     int fd;
        !            92:     /* XXX: race condition possible */
        !            93:     pstrcpy(filename, size, "/tmp/vl.XXXXXX");
        !            94:     fd = mkstemp(filename);
        !            95:     close(fd);
        !            96: }
        !            97: #endif
        !            98: 
        !            99: /* XXX: force raw format if block or character device ? It would
        !           100:    simplify the BSD case */
        !           101: static BlockDriver *find_image_format(const char *filename)
        !           102: {
        !           103:     int fd, ret, score, score_max;
        !           104:     BlockDriver *drv1, *drv;
        !           105:     uint8_t *buf;
        !           106:     size_t bufsize = 1024;
        !           107: 
        !           108:     fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
        !           109:     if (fd < 0) {
        !           110:         buf = NULL;
        !           111:         ret = 0;
        !           112:     } else {
        !           113: #ifdef DIOCGSECTORSIZE
        !           114:         {
        !           115:             unsigned int sectorsize = 512;
        !           116:             if (!ioctl(fd, DIOCGSECTORSIZE, &sectorsize) &&
        !           117:                 sectorsize > bufsize)
        !           118:                 bufsize = sectorsize;
        !           119:         }
        !           120: #endif
        !           121:         buf = qemu_malloc(bufsize);
        !           122:         if (!buf)
        !           123:             return NULL;
        !           124:         ret = read(fd, buf, bufsize);
        !           125:         if (ret < 0) {
        !           126:             close(fd);
        !           127:             qemu_free(buf);
        !           128:             return NULL;
        !           129:         }
        !           130:         close(fd);
        !           131:     }
        !           132:     
        !           133:     drv = NULL;
        !           134:     score_max = 0;
        !           135:     for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
        !           136:         score = drv1->bdrv_probe(buf, ret, filename);
        !           137:         if (score > score_max) {
        !           138:             score_max = score;
        !           139:             drv = drv1;
        !           140:         }
        !           141:     }
        !           142:     qemu_free(buf);
        !           143:     return drv;
        !           144: }
        !           145: 
        !           146: int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot)
        !           147: {
        !           148:     return bdrv_open2(bs, filename, snapshot, NULL);
        !           149: }
        !           150: 
        !           151: int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot,
        !           152:                BlockDriver *drv)
        !           153: {
        !           154:     int ret;
        !           155:     char tmp_filename[1024];
        !           156:     
        !           157:     bs->read_only = 0;
        !           158:     bs->is_temporary = 0;
        !           159:     bs->encrypted = 0;
        !           160: 
        !           161:     if (snapshot) {
        !           162:         BlockDriverState *bs1;
        !           163:         int64_t total_size;
        !           164:         
        !           165:         /* if snapshot, we create a temporary backing file and open it
        !           166:            instead of opening 'filename' directly */
        !           167: 
        !           168:         /* if there is a backing file, use it */
        !           169:         bs1 = bdrv_new("");
        !           170:         if (!bs1) {
        !           171:             return -1;
        !           172:         }
        !           173:         if (bdrv_open(bs1, filename, 0) < 0) {
        !           174:             bdrv_delete(bs1);
        !           175:             return -1;
        !           176:         }
        !           177:         total_size = bs1->total_sectors;
        !           178:         bdrv_delete(bs1);
        !           179:         
        !           180:         get_tmp_filename(tmp_filename, sizeof(tmp_filename));
        !           181:         /* XXX: use cow for linux as it is more efficient ? */
        !           182:         if (bdrv_create(&bdrv_qcow, tmp_filename, 
        !           183:                         total_size, filename, 0) < 0) {
        !           184:             return -1;
        !           185:         }
        !           186:         filename = tmp_filename;
        !           187:         bs->is_temporary = 1;
        !           188:     }
        !           189: 
        !           190:     pstrcpy(bs->filename, sizeof(bs->filename), filename);
        !           191:     if (!drv) {
        !           192:         drv = find_image_format(filename);
        !           193:         if (!drv)
        !           194:             return -1;
        !           195:     }
        !           196:     bs->drv = drv;
        !           197:     bs->opaque = qemu_mallocz(drv->instance_size);
        !           198:     if (bs->opaque == NULL && drv->instance_size > 0)
        !           199:         return -1;
        !           200:     
        !           201:     ret = drv->bdrv_open(bs, filename);
        !           202:     if (ret < 0) {
        !           203:         qemu_free(bs->opaque);
        !           204:         return -1;
        !           205:     }
        !           206: #ifndef _WIN32
        !           207:     if (bs->is_temporary) {
        !           208:         unlink(filename);
        !           209:     }
        !           210: #endif
        !           211:     if (bs->backing_file[0] != '\0' && drv->bdrv_is_allocated) {
        !           212:         /* if there is a backing file, use it */
        !           213:         bs->backing_hd = bdrv_new("");
        !           214:         if (!bs->backing_hd) {
        !           215:         fail:
        !           216:             bdrv_close(bs);
        !           217:             return -1;
        !           218:         }
        !           219:         if (bdrv_open(bs->backing_hd, bs->backing_file, 0) < 0)
        !           220:             goto fail;
        !           221:     }
        !           222: 
        !           223:     bs->inserted = 1;
        !           224: 
        !           225:     /* call the change callback */
        !           226:     if (bs->change_cb)
        !           227:         bs->change_cb(bs->change_opaque);
        !           228: 
        !           229:     return 0;
        !           230: }
        !           231: 
        !           232: void bdrv_close(BlockDriverState *bs)
        !           233: {
        !           234:     if (bs->inserted) {
        !           235:         if (bs->backing_hd)
        !           236:             bdrv_delete(bs->backing_hd);
        !           237:         bs->drv->bdrv_close(bs);
        !           238:         qemu_free(bs->opaque);
        !           239: #ifdef _WIN32
        !           240:         if (bs->is_temporary) {
        !           241:             unlink(bs->filename);
        !           242:         }
        !           243: #endif
        !           244:         bs->opaque = NULL;
        !           245:         bs->drv = NULL;
        !           246:         bs->inserted = 0;
        !           247: 
        !           248:         /* call the change callback */
        !           249:         if (bs->change_cb)
        !           250:             bs->change_cb(bs->change_opaque);
        !           251:     }
        !           252: }
        !           253: 
        !           254: void bdrv_delete(BlockDriverState *bs)
        !           255: {
        !           256:     /* XXX: remove the driver list */
        !           257:     bdrv_close(bs);
        !           258:     qemu_free(bs);
        !           259: }
        !           260: 
        !           261: /* commit COW file into the raw image */
        !           262: int bdrv_commit(BlockDriverState *bs)
        !           263: {
        !           264:     int64_t i;
        !           265:     int n, j;
        !           266:     unsigned char sector[512];
        !           267: 
        !           268:     if (!bs->inserted)
        !           269:         return -ENOENT;
        !           270: 
        !           271:     if (bs->read_only) {
        !           272:        return -EACCES;
        !           273:     }
        !           274: 
        !           275:     if (!bs->backing_hd) {
        !           276:        return -ENOTSUP;
        !           277:     }
        !           278: 
        !           279:     for (i = 0; i < bs->total_sectors;) {
        !           280:         if (bs->drv->bdrv_is_allocated(bs, i, 65536, &n)) {
        !           281:             for(j = 0; j < n; j++) {
        !           282:                 if (bdrv_read(bs, i, sector, 1) != 0) {
        !           283:                     return -EIO;
        !           284:                 }
        !           285: 
        !           286:                 if (bdrv_write(bs->backing_hd, i, sector, 1) != 0) {
        !           287:                     return -EIO;
        !           288:                 }
        !           289:                 i++;
        !           290:            }
        !           291:        } else {
        !           292:             i += n;
        !           293:         }
        !           294:     }
        !           295:     return 0;
        !           296: }
        !           297: 
        !           298: /* return -1 if error */
        !           299: int bdrv_read(BlockDriverState *bs, int64_t sector_num, 
        !           300:               uint8_t *buf, int nb_sectors)
        !           301: {
        !           302:     int ret, n;
        !           303:     BlockDriver *drv = bs->drv;
        !           304: 
        !           305:     if (!bs->inserted)
        !           306:         return -1;
        !           307: 
        !           308:     while (nb_sectors > 0) {
        !           309:         if (sector_num == 0 && bs->boot_sector_enabled) {
        !           310:             memcpy(buf, bs->boot_sector_data, 512);
        !           311:             n = 1;
        !           312:         } else if (bs->backing_hd) {
        !           313:             if (drv->bdrv_is_allocated(bs, sector_num, nb_sectors, &n)) {
        !           314:                 ret = drv->bdrv_read(bs, sector_num, buf, n);
        !           315:                 if (ret < 0)
        !           316:                     return -1;
        !           317:             } else {
        !           318:                 /* read from the base image */
        !           319:                 ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
        !           320:                 if (ret < 0)
        !           321:                     return -1;
        !           322:             }
        !           323:         } else {
        !           324:             ret = drv->bdrv_read(bs, sector_num, buf, nb_sectors);
        !           325:             if (ret < 0)
        !           326:                 return -1;
        !           327:             /* no need to loop */
        !           328:             break;
        !           329:         }
        !           330:         nb_sectors -= n;
        !           331:         sector_num += n;
        !           332:         buf += n * 512;
        !           333:     }
        !           334:     return 0;
        !           335: }
        !           336: 
        !           337: /* return -1 if error */
        !           338: int bdrv_write(BlockDriverState *bs, int64_t sector_num, 
        !           339:                const uint8_t *buf, int nb_sectors)
        !           340: {
        !           341:     if (!bs->inserted)
        !           342:         return -1;
        !           343:     if (bs->read_only)
        !           344:         return -1;
        !           345:     return bs->drv->bdrv_write(bs, sector_num, buf, nb_sectors);
        !           346: }
        !           347: 
        !           348: void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)
        !           349: {
        !           350:     *nb_sectors_ptr = bs->total_sectors;
        !           351: }
        !           352: 
        !           353: /* force a given boot sector. */
        !           354: void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size)
        !           355: {
        !           356:     bs->boot_sector_enabled = 1;
        !           357:     if (size > 512)
        !           358:         size = 512;
        !           359:     memcpy(bs->boot_sector_data, data, size);
        !           360:     memset(bs->boot_sector_data + size, 0, 512 - size);
        !           361: }
        !           362: 
        !           363: void bdrv_set_geometry_hint(BlockDriverState *bs, 
        !           364:                             int cyls, int heads, int secs)
        !           365: {
        !           366:     bs->cyls = cyls;
        !           367:     bs->heads = heads;
        !           368:     bs->secs = secs;
        !           369: }
        !           370: 
        !           371: void bdrv_set_type_hint(BlockDriverState *bs, int type)
        !           372: {
        !           373:     bs->type = type;
        !           374:     bs->removable = ((type == BDRV_TYPE_CDROM ||
        !           375:                       type == BDRV_TYPE_FLOPPY));
        !           376: }
        !           377: 
        !           378: void bdrv_set_translation_hint(BlockDriverState *bs, int translation)
        !           379: {
        !           380:     bs->translation = translation;
        !           381: }
        !           382: 
        !           383: void bdrv_get_geometry_hint(BlockDriverState *bs, 
        !           384:                             int *pcyls, int *pheads, int *psecs)
        !           385: {
        !           386:     *pcyls = bs->cyls;
        !           387:     *pheads = bs->heads;
        !           388:     *psecs = bs->secs;
        !           389: }
        !           390: 
        !           391: int bdrv_get_type_hint(BlockDriverState *bs)
        !           392: {
        !           393:     return bs->type;
        !           394: }
        !           395: 
        !           396: int bdrv_get_translation_hint(BlockDriverState *bs)
        !           397: {
        !           398:     return bs->translation;
        !           399: }
        !           400: 
        !           401: int bdrv_is_removable(BlockDriverState *bs)
        !           402: {
        !           403:     return bs->removable;
        !           404: }
        !           405: 
        !           406: int bdrv_is_read_only(BlockDriverState *bs)
        !           407: {
        !           408:     return bs->read_only;
        !           409: }
        !           410: 
        !           411: int bdrv_is_inserted(BlockDriverState *bs)
        !           412: {
        !           413:     return bs->inserted;
        !           414: }
        !           415: 
        !           416: int bdrv_is_locked(BlockDriverState *bs)
        !           417: {
        !           418:     return bs->locked;
        !           419: }
        !           420: 
        !           421: void bdrv_set_locked(BlockDriverState *bs, int locked)
        !           422: {
        !           423:     bs->locked = locked;
        !           424: }
        !           425: 
        !           426: void bdrv_set_change_cb(BlockDriverState *bs, 
        !           427:                         void (*change_cb)(void *opaque), void *opaque)
        !           428: {
        !           429:     bs->change_cb = change_cb;
        !           430:     bs->change_opaque = opaque;
        !           431: }
        !           432: 
        !           433: int bdrv_is_encrypted(BlockDriverState *bs)
        !           434: {
        !           435:     if (bs->backing_hd && bs->backing_hd->encrypted)
        !           436:         return 1;
        !           437:     return bs->encrypted;
        !           438: }
        !           439: 
        !           440: int bdrv_set_key(BlockDriverState *bs, const char *key)
        !           441: {
        !           442:     int ret;
        !           443:     if (bs->backing_hd && bs->backing_hd->encrypted) {
        !           444:         ret = bdrv_set_key(bs->backing_hd, key);
        !           445:         if (ret < 0)
        !           446:             return ret;
        !           447:         if (!bs->encrypted)
        !           448:             return 0;
        !           449:     }
        !           450:     if (!bs->encrypted || !bs->drv || !bs->drv->bdrv_set_key)
        !           451:         return -1;
        !           452:     return bs->drv->bdrv_set_key(bs, key);
        !           453: }
        !           454: 
        !           455: void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size)
        !           456: {
        !           457:     if (!bs->inserted || !bs->drv) {
        !           458:         buf[0] = '\0';
        !           459:     } else {
        !           460:         pstrcpy(buf, buf_size, bs->drv->format_name);
        !           461:     }
        !           462: }
        !           463: 
        !           464: void bdrv_iterate_format(void (*it)(void *opaque, const char *name), 
        !           465:                          void *opaque)
        !           466: {
        !           467:     BlockDriver *drv;
        !           468: 
        !           469:     for (drv = first_drv; drv != NULL; drv = drv->next) {
        !           470:         it(opaque, drv->format_name);
        !           471:     }
        !           472: }
        !           473: 
        !           474: BlockDriverState *bdrv_find(const char *name)
        !           475: {
        !           476:     BlockDriverState *bs;
        !           477: 
        !           478:     for (bs = bdrv_first; bs != NULL; bs = bs->next) {
        !           479:         if (!strcmp(name, bs->device_name))
        !           480:             return bs;
        !           481:     }
        !           482:     return NULL;
        !           483: }
        !           484: 
        !           485: void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque)
        !           486: {
        !           487:     BlockDriverState *bs;
        !           488: 
        !           489:     for (bs = bdrv_first; bs != NULL; bs = bs->next) {
        !           490:         it(opaque, bs->device_name);
        !           491:     }
        !           492: }
        !           493: 
        !           494: const char *bdrv_get_device_name(BlockDriverState *bs)
        !           495: {
        !           496:     return bs->device_name;
        !           497: }
        !           498: 
        !           499: void bdrv_info(void)
        !           500: {
        !           501:     BlockDriverState *bs;
        !           502: 
        !           503:     for (bs = bdrv_first; bs != NULL; bs = bs->next) {
        !           504:         term_printf("%s:", bs->device_name);
        !           505:         term_printf(" type=");
        !           506:         switch(bs->type) {
        !           507:         case BDRV_TYPE_HD:
        !           508:             term_printf("hd");
        !           509:             break;
        !           510:         case BDRV_TYPE_CDROM:
        !           511:             term_printf("cdrom");
        !           512:             break;
        !           513:         case BDRV_TYPE_FLOPPY:
        !           514:             term_printf("floppy");
        !           515:             break;
        !           516:         }
        !           517:         term_printf(" removable=%d", bs->removable);
        !           518:         if (bs->removable) {
        !           519:             term_printf(" locked=%d", bs->locked);
        !           520:         }
        !           521:         if (bs->inserted) {
        !           522:             term_printf(" file=%s", bs->filename);
        !           523:             if (bs->backing_file[0] != '\0')
        !           524:                 term_printf(" backing_file=%s", bs->backing_file);
        !           525:             term_printf(" ro=%d", bs->read_only);
        !           526:             term_printf(" drv=%s", bs->drv->format_name);
        !           527:             if (bs->encrypted)
        !           528:                 term_printf(" encrypted");
        !           529:         } else {
        !           530:             term_printf(" [not inserted]");
        !           531:         }
        !           532:         term_printf("\n");
        !           533:     }
        !           534: }
        !           535: 
        !           536: 
        !           537: /**************************************************************/
        !           538: /* RAW block driver */
        !           539: 
        !           540: typedef struct BDRVRawState {
        !           541:     int fd;
        !           542: } BDRVRawState;
        !           543: 
        !           544: static int raw_probe(const uint8_t *buf, int buf_size, const char *filename)
        !           545: {
        !           546:     return 1; /* maybe */
        !           547: }
        !           548: 
        !           549: static int raw_open(BlockDriverState *bs, const char *filename)
        !           550: {
        !           551:     BDRVRawState *s = bs->opaque;
        !           552:     int fd;
        !           553:     int64_t size;
        !           554: #ifdef _BSD
        !           555:     struct stat sb;
        !           556: #endif
        !           557: 
        !           558:     fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
        !           559:     if (fd < 0) {
        !           560:         fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
        !           561:         if (fd < 0)
        !           562:             return -1;
        !           563:         bs->read_only = 1;
        !           564:     }
        !           565: #ifdef _BSD
        !           566:     if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
        !           567: #ifdef DIOCGMEDIASIZE
        !           568:        if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
        !           569: #endif
        !           570:            size = lseek(fd, 0LL, SEEK_END);
        !           571:     } else
        !           572: #endif
        !           573:     {
        !           574:         size = lseek(fd, 0, SEEK_END);
        !           575:     }
        !           576: #ifdef _WIN32
        !           577:     /* On Windows hosts it can happen that we're unable to get file size
        !           578:        for CD-ROM raw device (it's inherent limitation of the CDFS driver). */
        !           579:     if (size == -1)
        !           580:         size = LONG_LONG_MAX;
        !           581: #endif
        !           582:     bs->total_sectors = size / 512;
        !           583:     s->fd = fd;
        !           584:     return 0;
        !           585: }
        !           586: 
        !           587: static int raw_read(BlockDriverState *bs, int64_t sector_num, 
        !           588:                     uint8_t *buf, int nb_sectors)
        !           589: {
        !           590:     BDRVRawState *s = bs->opaque;
        !           591:     int ret;
        !           592:     
        !           593:     lseek(s->fd, sector_num * 512, SEEK_SET);
        !           594:     ret = read(s->fd, buf, nb_sectors * 512);
        !           595:     if (ret != nb_sectors * 512) 
        !           596:         return -1;
        !           597:     return 0;
        !           598: }
        !           599: 
        !           600: static int raw_write(BlockDriverState *bs, int64_t sector_num, 
        !           601:                      const uint8_t *buf, int nb_sectors)
        !           602: {
        !           603:     BDRVRawState *s = bs->opaque;
        !           604:     int ret;
        !           605:     
        !           606:     lseek(s->fd, sector_num * 512, SEEK_SET);
        !           607:     ret = write(s->fd, buf, nb_sectors * 512);
        !           608:     if (ret != nb_sectors * 512) 
        !           609:         return -1;
        !           610:     return 0;
        !           611: }
        !           612: 
        !           613: static void raw_close(BlockDriverState *bs)
        !           614: {
        !           615:     BDRVRawState *s = bs->opaque;
        !           616:     close(s->fd);
        !           617: }
        !           618: 
        !           619: static int raw_create(const char *filename, int64_t total_size,
        !           620:                       const char *backing_file, int flags)
        !           621: {
        !           622:     int fd;
        !           623: 
        !           624:     if (flags || backing_file)
        !           625:         return -ENOTSUP;
        !           626: 
        !           627:     fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 
        !           628:               0644);
        !           629:     if (fd < 0)
        !           630:         return -EIO;
        !           631:     ftruncate(fd, total_size * 512);
        !           632:     close(fd);
        !           633:     return 0;
        !           634: }
        !           635: 
        !           636: BlockDriver bdrv_raw = {
        !           637:     "raw",
        !           638:     sizeof(BDRVRawState),
        !           639:     raw_probe,
        !           640:     raw_open,
        !           641:     raw_read,
        !           642:     raw_write,
        !           643:     raw_close,
        !           644:     raw_create,
        !           645: };
        !           646: 
        !           647: void bdrv_init(void)
        !           648: {
        !           649:     bdrv_register(&bdrv_raw);
        !           650: #ifndef _WIN32
        !           651:     bdrv_register(&bdrv_cow);
        !           652: #endif
        !           653:     bdrv_register(&bdrv_qcow);
        !           654:     bdrv_register(&bdrv_vmdk);
        !           655:     bdrv_register(&bdrv_cloop);
        !           656:     bdrv_register(&bdrv_dmg);
        !           657:     bdrv_register(&bdrv_bochs);
        !           658:     bdrv_register(&bdrv_vpc);
        !           659:     bdrv_register(&bdrv_vvfat);
        !           660: }

unix.superglobalmegacorp.com