📄 block.c
字号:
/* * QEMU System Emulator block driver * * Copyright (c) 2003 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */#include "vl.h"#include "block_int.h"#ifdef _BSD#include <sys/types.h>#include <sys/stat.h>#include <sys/ioctl.h>#include <sys/queue.h>#include <sys/disk.h>#endif#ifdef CONFIG_COCOA#include <paths.h>#include <sys/param.h>#include <IOKit/IOKitLib.h>#include <IOKit/IOBSD.h>#include <IOKit/storage/IOMediaBSDClient.h>#include <IOKit/storage/IOMedia.h>#include <IOKit/storage/IOCDMedia.h>//#include <IOKit/storage/IOCDTypes.h>#include <CoreFoundation/CoreFoundation.h>#endif#ifdef __sun__#include <sys/dkio.h>#endifstatic BlockDriverState *bdrv_first;static BlockDriver *first_drv;#ifdef CONFIG_COCOAstatic kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator );static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize );kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator ){ kern_return_t kernResult; mach_port_t masterPort; CFMutableDictionaryRef classesToMatch; kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort ); if ( KERN_SUCCESS != kernResult ) { printf( "IOMasterPort returned %d\n", kernResult ); } classesToMatch = IOServiceMatching( kIOCDMediaClass ); if ( classesToMatch == NULL ) { printf( "IOServiceMatching returned a NULL dictionary.\n" ); } else { CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue ); } kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, mediaIterator ); if ( KERN_SUCCESS != kernResult ) { printf( "IOServiceGetMatchingServices returned %d\n", kernResult ); } return kernResult;}kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize ){ io_object_t nextMedia; kern_return_t kernResult = KERN_FAILURE; *bsdPath = '\0'; nextMedia = IOIteratorNext( mediaIterator ); if ( nextMedia ) { CFTypeRef bsdPathAsCFString; bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia, CFSTR( kIOBSDNameKey ), kCFAllocatorDefault, 0 ); if ( bsdPathAsCFString ) { size_t devPathLength; strcpy( bsdPath, _PATH_DEV ); strcat( bsdPath, "r" ); devPathLength = strlen( bsdPath ); if ( CFStringGetCString( bsdPathAsCFString, bsdPath + devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) { kernResult = KERN_SUCCESS; } CFRelease( bsdPathAsCFString ); } IOObjectRelease( nextMedia ); } return kernResult;}#endifvoid bdrv_register(BlockDriver *bdrv){ bdrv->next = first_drv; first_drv = bdrv;}/* create a new block device (by default it is empty) */BlockDriverState *bdrv_new(const char *device_name){ BlockDriverState **pbs, *bs; bs = qemu_mallocz(sizeof(BlockDriverState)); if(!bs) return NULL; pstrcpy(bs->device_name, sizeof(bs->device_name), device_name); if (device_name[0] != '\0') { /* insert at the end */ pbs = &bdrv_first; while (*pbs != NULL) pbs = &(*pbs)->next; *pbs = bs; } return bs;}BlockDriver *bdrv_find_format(const char *format_name){ BlockDriver *drv1; for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) { if (!strcmp(drv1->format_name, format_name)) return drv1; } return NULL;}int bdrv_create(BlockDriver *drv, const char *filename, int64_t size_in_sectors, const char *backing_file, int flags){ if (!drv->bdrv_create) return -ENOTSUP; return drv->bdrv_create(filename, size_in_sectors, backing_file, flags);}#ifdef _WIN32void get_tmp_filename(char *filename, int size){ char* p = strrchr(filename, '/'); if (p == NULL) return; /* XXX: find a better function */ tmpnam(p); *p = '/';}#elsevoid get_tmp_filename(char *filename, int size){ int fd; /* XXX: race condition possible */ pstrcpy(filename, size, "/tmp/vl.XXXXXX"); fd = mkstemp(filename); close(fd);}#endif/* XXX: force raw format if block or character device ? It would simplify the BSD case */static BlockDriver *find_image_format(const char *filename){ int fd, ret, score, score_max; BlockDriver *drv1, *drv; uint8_t *buf; size_t bufsize = 1024; fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); if (fd < 0) { buf = NULL; ret = 0; } else {#ifdef DIOCGSECTORSIZE { unsigned int sectorsize = 512; if (!ioctl(fd, DIOCGSECTORSIZE, §orsize) && sectorsize > bufsize) bufsize = sectorsize; }#endif#ifdef CONFIG_COCOA u_int32_t blockSize = 512; if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize > bufsize) { bufsize = blockSize; }#endif buf = qemu_malloc(bufsize); if (!buf) return NULL; ret = read(fd, buf, bufsize); if (ret < 0) { close(fd); qemu_free(buf); return NULL; } close(fd); } drv = NULL; score_max = 0; for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) { score = drv1->bdrv_probe(buf, ret, filename); if (score > score_max) { score_max = score; drv = drv1; } } qemu_free(buf); return drv;}int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot){#ifdef CONFIG_COCOA if ( strncmp( filename, "/dev/cdrom", 10 ) == 0 ) { kern_return_t kernResult; io_iterator_t mediaIterator; char bsdPath[ MAXPATHLEN ]; int fd; kernResult = FindEjectableCDMedia( &mediaIterator ); kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) ); if ( bsdPath[ 0 ] != '\0' ) { strcat(bsdPath,"s0"); /* some CDs don't have a partition 0 */ fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE); if (fd < 0) { bsdPath[strlen(bsdPath)-1] = '1'; } else { close(fd); } filename = bsdPath; } if ( mediaIterator ) IOObjectRelease( mediaIterator ); }#endif return bdrv_open2(bs, filename, snapshot, NULL);}int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot, BlockDriver *drv){ int ret; char tmp_filename[1024]; bs->read_only = 0; bs->is_temporary = 0; bs->encrypted = 0; if (snapshot) { BlockDriverState *bs1; int64_t total_size; /* if snapshot, we create a temporary backing file and open it instead of opening 'filename' directly */ /* if there is a backing file, use it */ bs1 = bdrv_new(""); if (!bs1) { return -1; } if (bdrv_open(bs1, filename, 0) < 0) { bdrv_delete(bs1); return -1; } total_size = bs1->total_sectors; bdrv_delete(bs1); get_tmp_filename(tmp_filename, sizeof(tmp_filename)); /* XXX: use cow for linux as it is more efficient ? */ if (bdrv_create(&bdrv_qcow, tmp_filename, total_size, filename, 0) < 0) { return -1; } filename = tmp_filename; bs->is_temporary = 1; } pstrcpy(bs->filename, sizeof(bs->filename), filename); if (!drv) { drv = find_image_format(filename); if (!drv) return -1; } bs->drv = drv; bs->opaque = qemu_mallocz(drv->instance_size); if (bs->opaque == NULL && drv->instance_size > 0) return -1; ret = drv->bdrv_open(bs, filename); if (ret < 0) { qemu_free(bs->opaque); return -1; }#ifndef _WIN32 if (bs->is_temporary) { unlink(filename); }#endif if (bs->backing_file[0] != '\0' && drv->bdrv_is_allocated) { /* if there is a backing file, use it */ bs->backing_hd = bdrv_new(""); if (!bs->backing_hd) { fail: bdrv_close(bs); return -1; } if (bdrv_open(bs->backing_hd, bs->backing_file, 0) < 0) goto fail; } bs->inserted = 1; /* call the change callback */ if (bs->change_cb) bs->change_cb(bs->change_opaque); return 0;}void bdrv_close(BlockDriverState *bs){ if (bs->inserted) { if (bs->backing_hd) bdrv_delete(bs->backing_hd); bs->drv->bdrv_close(bs); qemu_free(bs->opaque);#ifdef _WIN32 if (bs->is_temporary) { unlink(bs->filename); }#endif bs->opaque = NULL; bs->drv = NULL; bs->inserted = 0; /* call the change callback */ if (bs->change_cb) bs->change_cb(bs->change_opaque); }}void bdrv_delete(BlockDriverState *bs){ /* XXX: remove the driver list */ bdrv_close(bs); qemu_free(bs);}/* commit COW file into the raw image */int bdrv_commit(BlockDriverState *bs){ int64_t i; int n, j; unsigned char sector[512]; if (!bs->inserted) return -ENOENT; if (bs->read_only) { return -EACCES; } if (!bs->backing_hd) { return -ENOTSUP; } for (i = 0; i < bs->total_sectors;) { if (bs->drv->bdrv_is_allocated(bs, i, 65536, &n)) { for(j = 0; j < n; j++) { if (bdrv_read(bs, i, sector, 1) != 0) { return -EIO; } if (bdrv_write(bs->backing_hd, i, sector, 1) != 0) { return -EIO;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -