version 1.1.1.4, 2018/04/24 16:42:44
|
version 1.1.1.5, 2018/04/24 16:44:58
|
Line 32
|
Line 32
|
#include <sys/disk.h> |
#include <sys/disk.h> |
#endif |
#endif |
|
|
#ifdef CONFIG_COCOA |
#define SECTOR_BITS 9 |
#include <paths.h> |
#define SECTOR_SIZE (1 << SECTOR_BITS) |
#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__ |
typedef struct BlockDriverAIOCBSync { |
#include <sys/dkio.h> |
BlockDriverAIOCB common; |
#endif |
QEMUBH *bh; |
|
int ret; |
|
} BlockDriverAIOCBSync; |
|
|
|
static BlockDriverAIOCB *bdrv_aio_read_em(BlockDriverState *bs, |
|
int64_t sector_num, uint8_t *buf, int nb_sectors, |
|
BlockDriverCompletionFunc *cb, void *opaque); |
|
static BlockDriverAIOCB *bdrv_aio_write_em(BlockDriverState *bs, |
|
int64_t sector_num, const uint8_t *buf, int nb_sectors, |
|
BlockDriverCompletionFunc *cb, void *opaque); |
|
static void bdrv_aio_cancel_em(BlockDriverAIOCB *acb); |
|
static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num, |
|
uint8_t *buf, int nb_sectors); |
|
static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num, |
|
const uint8_t *buf, int nb_sectors); |
|
|
static BlockDriverState *bdrv_first; |
static BlockDriverState *bdrv_first; |
static BlockDriver *first_drv; |
static BlockDriver *first_drv; |
|
|
#ifdef CONFIG_COCOA |
int path_is_absolute(const char *path) |
static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator ); |
{ |
static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize ); |
const char *p; |
|
#ifdef _WIN32 |
kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator ) |
/* specific case for names like: "\\.\d:" */ |
{ |
if (*path == '/' || *path == '\\') |
kern_return_t kernResult; |
return 1; |
mach_port_t masterPort; |
#endif |
CFMutableDictionaryRef classesToMatch; |
p = strchr(path, ':'); |
|
if (p) |
kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort ); |
p++; |
if ( KERN_SUCCESS != kernResult ) { |
else |
printf( "IOMasterPort returned %d\n", kernResult ); |
p = path; |
} |
#ifdef _WIN32 |
|
return (*p == '/' || *p == '\\'); |
classesToMatch = IOServiceMatching( kIOCDMediaClass ); |
#else |
if ( classesToMatch == NULL ) { |
return (*p == '/'); |
printf( "IOServiceMatching returned a NULL dictionary.\n" ); |
#endif |
} 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 ) |
/* if filename is absolute, just copy it to dest. Otherwise, build a |
{ |
path to it by considering it is relative to base_path. URL are |
io_object_t nextMedia; |
supported. */ |
kern_return_t kernResult = KERN_FAILURE; |
void path_combine(char *dest, int dest_size, |
*bsdPath = '\0'; |
const char *base_path, |
nextMedia = IOIteratorNext( mediaIterator ); |
const char *filename) |
if ( nextMedia ) |
{ |
{ |
const char *p, *p1; |
CFTypeRef bsdPathAsCFString; |
int len; |
bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia, CFSTR( kIOBSDNameKey ), kCFAllocatorDefault, 0 ); |
|
if ( bsdPathAsCFString ) { |
if (dest_size <= 0) |
size_t devPathLength; |
return; |
strcpy( bsdPath, _PATH_DEV ); |
if (path_is_absolute(filename)) { |
strcat( bsdPath, "r" ); |
pstrcpy(dest, dest_size, filename); |
devPathLength = strlen( bsdPath ); |
} else { |
if ( CFStringGetCString( bsdPathAsCFString, bsdPath + devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) { |
p = strchr(base_path, ':'); |
kernResult = KERN_SUCCESS; |
if (p) |
} |
p++; |
CFRelease( bsdPathAsCFString ); |
else |
|
p = base_path; |
|
p1 = strrchr(base_path, '/'); |
|
#ifdef _WIN32 |
|
{ |
|
const char *p2; |
|
p2 = strrchr(base_path, '\\'); |
|
if (!p1 || p2 > p1) |
|
p1 = p2; |
} |
} |
IOObjectRelease( nextMedia ); |
#endif |
|
if (p1) |
|
p1++; |
|
else |
|
p1 = base_path; |
|
if (p1 > p) |
|
p = p1; |
|
len = p - base_path; |
|
if (len > dest_size - 1) |
|
len = dest_size - 1; |
|
memcpy(dest, base_path, len); |
|
dest[len] = '\0'; |
|
pstrcat(dest, dest_size, filename); |
} |
} |
|
|
return kernResult; |
|
} |
} |
|
|
#endif |
|
|
|
void bdrv_register(BlockDriver *bdrv) |
void bdrv_register(BlockDriver *bdrv) |
{ |
{ |
|
if (!bdrv->bdrv_aio_read) { |
|
/* add AIO emulation layer */ |
|
bdrv->bdrv_aio_read = bdrv_aio_read_em; |
|
bdrv->bdrv_aio_write = bdrv_aio_write_em; |
|
bdrv->bdrv_aio_cancel = bdrv_aio_cancel_em; |
|
bdrv->aiocb_size = sizeof(BlockDriverAIOCBSync); |
|
} else if (!bdrv->bdrv_read && !bdrv->bdrv_pread) { |
|
/* add synchronous IO emulation layer */ |
|
bdrv->bdrv_read = bdrv_read_em; |
|
bdrv->bdrv_write = bdrv_write_em; |
|
} |
bdrv->next = first_drv; |
bdrv->next = first_drv; |
first_drv = bdrv; |
first_drv = bdrv; |
} |
} |
Line 156 int bdrv_create(BlockDriver *drv,
|
Line 179 int bdrv_create(BlockDriver *drv,
|
#ifdef _WIN32 |
#ifdef _WIN32 |
void get_tmp_filename(char *filename, int size) |
void get_tmp_filename(char *filename, int size) |
{ |
{ |
char* p = strrchr(filename, '/'); |
char temp_dir[MAX_PATH]; |
|
|
if (p == NULL) |
GetTempPath(MAX_PATH, temp_dir); |
return; |
GetTempFileName(temp_dir, "qem", 0, filename); |
|
|
/* XXX: find a better function */ |
|
tmpnam(p); |
|
*p = '/'; |
|
} |
} |
#else |
#else |
void get_tmp_filename(char *filename, int size) |
void get_tmp_filename(char *filename, int size) |
Line 176 void get_tmp_filename(char *filename, in
|
Line 195 void get_tmp_filename(char *filename, in
|
} |
} |
#endif |
#endif |
|
|
|
#ifdef _WIN32 |
|
static int is_windows_drive_prefix(const char *filename) |
|
{ |
|
return (((filename[0] >= 'a' && filename[0] <= 'z') || |
|
(filename[0] >= 'A' && filename[0] <= 'Z')) && |
|
filename[1] == ':'); |
|
} |
|
|
|
static int is_windows_drive(const char *filename) |
|
{ |
|
if (is_windows_drive_prefix(filename) && |
|
filename[2] == '\0') |
|
return 1; |
|
if (strstart(filename, "\\\\.\\", NULL) || |
|
strstart(filename, "//./", NULL)) |
|
return 1; |
|
return 0; |
|
} |
|
#endif |
|
|
|
static BlockDriver *find_protocol(const char *filename) |
|
{ |
|
BlockDriver *drv1; |
|
char protocol[128]; |
|
int len; |
|
const char *p; |
|
|
|
#ifdef _WIN32 |
|
if (is_windows_drive(filename) || |
|
is_windows_drive_prefix(filename)) |
|
return &bdrv_raw; |
|
#endif |
|
p = strchr(filename, ':'); |
|
if (!p) |
|
return &bdrv_raw; |
|
len = p - filename; |
|
if (len > sizeof(protocol) - 1) |
|
len = sizeof(protocol) - 1; |
|
memcpy(protocol, filename, len); |
|
protocol[len] = '\0'; |
|
for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) { |
|
if (drv1->protocol_name && |
|
!strcmp(drv1->protocol_name, protocol)) |
|
return drv1; |
|
} |
|
return NULL; |
|
} |
|
|
/* XXX: force raw format if block or character device ? It would |
/* XXX: force raw format if block or character device ? It would |
simplify the BSD case */ |
simplify the BSD case */ |
static BlockDriver *find_image_format(const char *filename) |
static BlockDriver *find_image_format(const char *filename) |
{ |
{ |
int fd, ret, score, score_max; |
int ret, score, score_max; |
BlockDriver *drv1, *drv; |
BlockDriver *drv1, *drv; |
uint8_t *buf; |
uint8_t buf[2048]; |
size_t bufsize = 1024; |
BlockDriverState *bs; |
|
|
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); |
/* detect host devices. By convention, /dev/cdrom[N] is always |
if (fd < 0) { |
recognized as a host CDROM */ |
buf = NULL; |
if (strstart(filename, "/dev/cdrom", NULL)) |
ret = 0; |
return &bdrv_host_device; |
} else { |
#ifdef _WIN32 |
#ifdef DIOCGSECTORSIZE |
if (is_windows_drive(filename)) |
{ |
return &bdrv_host_device; |
unsigned int sectorsize = 512; |
#else |
if (!ioctl(fd, DIOCGSECTORSIZE, §orsize) && |
{ |
sectorsize > bufsize) |
struct stat st; |
bufsize = sectorsize; |
if (stat(filename, &st) >= 0 && |
} |
(S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))) { |
#endif |
return &bdrv_host_device; |
#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); |
|
} |
} |
|
#endif |
|
|
drv = NULL; |
drv = find_protocol(filename); |
|
/* no need to test disk image formats for vvfat */ |
|
if (drv == &bdrv_vvfat) |
|
return drv; |
|
|
|
ret = bdrv_file_open(&bs, filename, BDRV_O_RDONLY); |
|
if (ret < 0) |
|
return NULL; |
|
ret = bdrv_pread(bs, 0, buf, sizeof(buf)); |
|
bdrv_delete(bs); |
|
if (ret < 0) { |
|
return NULL; |
|
} |
|
|
score_max = 0; |
score_max = 0; |
for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) { |
for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) { |
score = drv1->bdrv_probe(buf, ret, filename); |
if (drv1->bdrv_probe) { |
if (score > score_max) { |
score = drv1->bdrv_probe(buf, ret, filename); |
score_max = score; |
if (score > score_max) { |
drv = drv1; |
score_max = score; |
|
drv = drv1; |
|
} |
} |
} |
} |
} |
qemu_free(buf); |
|
return drv; |
return drv; |
} |
} |
|
|
int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) |
int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags) |
{ |
{ |
#ifdef CONFIG_COCOA |
BlockDriverState *bs; |
if ( strncmp( filename, "/dev/cdrom", 10 ) == 0 ) { |
int ret; |
kern_return_t kernResult; |
|
io_iterator_t mediaIterator; |
bs = bdrv_new(""); |
char bsdPath[ MAXPATHLEN ]; |
if (!bs) |
int fd; |
return -ENOMEM; |
|
ret = bdrv_open2(bs, filename, flags | BDRV_O_FILE, NULL); |
kernResult = FindEjectableCDMedia( &mediaIterator ); |
if (ret < 0) { |
kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) ); |
bdrv_delete(bs); |
|
return ret; |
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 |
*pbs = bs; |
return bdrv_open2(bs, filename, snapshot, NULL); |
return 0; |
|
} |
|
|
|
int bdrv_open(BlockDriverState *bs, const char *filename, int flags) |
|
{ |
|
return bdrv_open2(bs, filename, flags, NULL); |
} |
} |
|
|
int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot, |
int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, |
BlockDriver *drv) |
BlockDriver *drv) |
{ |
{ |
int ret; |
int ret, open_flags; |
char tmp_filename[1024]; |
char tmp_filename[1024]; |
|
char backing_filename[1024]; |
|
|
bs->read_only = 0; |
bs->read_only = 0; |
bs->is_temporary = 0; |
bs->is_temporary = 0; |
bs->encrypted = 0; |
bs->encrypted = 0; |
|
|
if (snapshot) { |
if (flags & BDRV_O_SNAPSHOT) { |
BlockDriverState *bs1; |
BlockDriverState *bs1; |
int64_t total_size; |
int64_t total_size; |
|
|
Line 280 int bdrv_open2(BlockDriverState *bs, con
|
Line 339 int bdrv_open2(BlockDriverState *bs, con
|
/* if there is a backing file, use it */ |
/* if there is a backing file, use it */ |
bs1 = bdrv_new(""); |
bs1 = bdrv_new(""); |
if (!bs1) { |
if (!bs1) { |
return -1; |
return -ENOMEM; |
} |
} |
if (bdrv_open(bs1, filename, 0) < 0) { |
if (bdrv_open(bs1, filename, 0) < 0) { |
bdrv_delete(bs1); |
bdrv_delete(bs1); |
return -1; |
return -1; |
} |
} |
total_size = bs1->total_sectors; |
total_size = bdrv_getlength(bs1) >> SECTOR_BITS; |
bdrv_delete(bs1); |
bdrv_delete(bs1); |
|
|
get_tmp_filename(tmp_filename, sizeof(tmp_filename)); |
get_tmp_filename(tmp_filename, sizeof(tmp_filename)); |
/* XXX: use cow for linux as it is more efficient ? */ |
realpath(filename, backing_filename); |
if (bdrv_create(&bdrv_qcow, tmp_filename, |
if (bdrv_create(&bdrv_qcow2, tmp_filename, |
total_size, filename, 0) < 0) { |
total_size, backing_filename, 0) < 0) { |
return -1; |
return -1; |
} |
} |
filename = tmp_filename; |
filename = tmp_filename; |
Line 300 int bdrv_open2(BlockDriverState *bs, con
|
Line 359 int bdrv_open2(BlockDriverState *bs, con
|
} |
} |
|
|
pstrcpy(bs->filename, sizeof(bs->filename), filename); |
pstrcpy(bs->filename, sizeof(bs->filename), filename); |
if (!drv) { |
if (flags & BDRV_O_FILE) { |
drv = find_image_format(filename); |
drv = find_protocol(filename); |
if (!drv) |
if (!drv) |
return -1; |
return -ENOENT; |
|
} else { |
|
if (!drv) { |
|
drv = find_image_format(filename); |
|
if (!drv) |
|
return -1; |
|
} |
} |
} |
bs->drv = drv; |
bs->drv = drv; |
bs->opaque = qemu_mallocz(drv->instance_size); |
bs->opaque = qemu_mallocz(drv->instance_size); |
if (bs->opaque == NULL && drv->instance_size > 0) |
if (bs->opaque == NULL && drv->instance_size > 0) |
return -1; |
return -1; |
|
/* Note: for compatibility, we open disk image files as RDWR, and |
ret = drv->bdrv_open(bs, filename); |
RDONLY as fallback */ |
|
if (!(flags & BDRV_O_FILE)) |
|
open_flags = BDRV_O_RDWR; |
|
else |
|
open_flags = flags & ~(BDRV_O_FILE | BDRV_O_SNAPSHOT); |
|
ret = drv->bdrv_open(bs, filename, open_flags); |
|
if (ret == -EACCES && !(flags & BDRV_O_FILE)) { |
|
ret = drv->bdrv_open(bs, filename, BDRV_O_RDONLY); |
|
bs->read_only = 1; |
|
} |
if (ret < 0) { |
if (ret < 0) { |
qemu_free(bs->opaque); |
qemu_free(bs->opaque); |
return -1; |
bs->opaque = NULL; |
|
bs->drv = NULL; |
|
return ret; |
|
} |
|
if (drv->bdrv_getlength) { |
|
bs->total_sectors = bdrv_getlength(bs) >> SECTOR_BITS; |
} |
} |
#ifndef _WIN32 |
#ifndef _WIN32 |
if (bs->is_temporary) { |
if (bs->is_temporary) { |
unlink(filename); |
unlink(filename); |
} |
} |
#endif |
#endif |
if (bs->backing_file[0] != '\0' && drv->bdrv_is_allocated) { |
if (bs->backing_file[0] != '\0') { |
/* if there is a backing file, use it */ |
/* if there is a backing file, use it */ |
bs->backing_hd = bdrv_new(""); |
bs->backing_hd = bdrv_new(""); |
if (!bs->backing_hd) { |
if (!bs->backing_hd) { |
fail: |
fail: |
bdrv_close(bs); |
bdrv_close(bs); |
return -1; |
return -ENOMEM; |
} |
} |
if (bdrv_open(bs->backing_hd, bs->backing_file, 0) < 0) |
path_combine(backing_filename, sizeof(backing_filename), |
|
filename, bs->backing_file); |
|
if (bdrv_open(bs->backing_hd, backing_filename, 0) < 0) |
goto fail; |
goto fail; |
} |
} |
|
|
bs->inserted = 1; |
|
|
|
/* call the change callback */ |
/* call the change callback */ |
|
bs->media_changed = 1; |
if (bs->change_cb) |
if (bs->change_cb) |
bs->change_cb(bs->change_opaque); |
bs->change_cb(bs->change_opaque); |
|
|
Line 343 int bdrv_open2(BlockDriverState *bs, con
|
Line 423 int bdrv_open2(BlockDriverState *bs, con
|
|
|
void bdrv_close(BlockDriverState *bs) |
void bdrv_close(BlockDriverState *bs) |
{ |
{ |
if (bs->inserted) { |
if (bs->drv) { |
if (bs->backing_hd) |
if (bs->backing_hd) |
bdrv_delete(bs->backing_hd); |
bdrv_delete(bs->backing_hd); |
bs->drv->bdrv_close(bs); |
bs->drv->bdrv_close(bs); |
Line 355 void bdrv_close(BlockDriverState *bs)
|
Line 435 void bdrv_close(BlockDriverState *bs)
|
#endif |
#endif |
bs->opaque = NULL; |
bs->opaque = NULL; |
bs->drv = NULL; |
bs->drv = NULL; |
bs->inserted = 0; |
|
|
|
/* call the change callback */ |
/* call the change callback */ |
|
bs->media_changed = 1; |
if (bs->change_cb) |
if (bs->change_cb) |
bs->change_cb(bs->change_opaque); |
bs->change_cb(bs->change_opaque); |
} |
} |
Line 373 void bdrv_delete(BlockDriverState *bs)
|
Line 453 void bdrv_delete(BlockDriverState *bs)
|
/* commit COW file into the raw image */ |
/* commit COW file into the raw image */ |
int bdrv_commit(BlockDriverState *bs) |
int bdrv_commit(BlockDriverState *bs) |
{ |
{ |
int64_t i; |
BlockDriver *drv = bs->drv; |
|
int64_t i, total_sectors; |
int n, j; |
int n, j; |
unsigned char sector[512]; |
unsigned char sector[512]; |
|
|
if (!bs->inserted) |
if (!drv) |
return -ENOENT; |
return -ENOMEDIUM; |
|
|
if (bs->read_only) { |
if (bs->read_only) { |
return -EACCES; |
return -EACCES; |
Line 388 int bdrv_commit(BlockDriverState *bs)
|
Line 469 int bdrv_commit(BlockDriverState *bs)
|
return -ENOTSUP; |
return -ENOTSUP; |
} |
} |
|
|
for (i = 0; i < bs->total_sectors;) { |
total_sectors = bdrv_getlength(bs) >> SECTOR_BITS; |
if (bs->drv->bdrv_is_allocated(bs, i, 65536, &n)) { |
for (i = 0; i < total_sectors;) { |
|
if (drv->bdrv_is_allocated(bs, i, 65536, &n)) { |
for(j = 0; j < n; j++) { |
for(j = 0; j < n; j++) { |
if (bdrv_read(bs, i, sector, 1) != 0) { |
if (bdrv_read(bs, i, sector, 1) != 0) { |
return -EIO; |
return -EIO; |
Line 405 int bdrv_commit(BlockDriverState *bs)
|
Line 487 int bdrv_commit(BlockDriverState *bs)
|
} |
} |
} |
} |
|
|
if (bs->drv->bdrv_make_empty) |
if (drv->bdrv_make_empty) |
return bs->drv->bdrv_make_empty(bs); |
return drv->bdrv_make_empty(bs); |
|
|
return 0; |
return 0; |
} |
} |
|
|
/* return -1 if error */ |
/* return < 0 if error. See bdrv_write() for the return codes */ |
int bdrv_read(BlockDriverState *bs, int64_t sector_num, |
int bdrv_read(BlockDriverState *bs, int64_t sector_num, |
uint8_t *buf, int nb_sectors) |
uint8_t *buf, int nb_sectors) |
{ |
{ |
int ret, n; |
|
BlockDriver *drv = bs->drv; |
BlockDriver *drv = bs->drv; |
|
|
if (!bs->inserted) |
if (!drv) |
return -1; |
return -ENOMEDIUM; |
|
|
while (nb_sectors > 0) { |
if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { |
if (sector_num == 0 && bs->boot_sector_enabled) { |
|
memcpy(buf, bs->boot_sector_data, 512); |
memcpy(buf, bs->boot_sector_data, 512); |
n = 1; |
sector_num++; |
} else if (bs->backing_hd) { |
nb_sectors--; |
if (drv->bdrv_is_allocated(bs, sector_num, nb_sectors, &n)) { |
buf += 512; |
ret = drv->bdrv_read(bs, sector_num, buf, n); |
if (nb_sectors == 0) |
if (ret < 0) |
return 0; |
return -1; |
} |
} else { |
if (drv->bdrv_pread) { |
/* read from the base image */ |
int ret, len; |
ret = bdrv_read(bs->backing_hd, sector_num, buf, n); |
len = nb_sectors * 512; |
if (ret < 0) |
ret = drv->bdrv_pread(bs, sector_num * 512, buf, len); |
return -1; |
if (ret < 0) |
} |
return ret; |
} else { |
else if (ret != len) |
ret = drv->bdrv_read(bs, sector_num, buf, nb_sectors); |
return -EINVAL; |
if (ret < 0) |
else |
return -1; |
return 0; |
/* no need to loop */ |
} else { |
break; |
return drv->bdrv_read(bs, sector_num, buf, nb_sectors); |
} |
|
nb_sectors -= n; |
|
sector_num += n; |
|
buf += n * 512; |
|
} |
} |
return 0; |
|
} |
} |
|
|
/* return -1 if error */ |
/* Return < 0 if error. Important errors are: |
|
-EIO generic I/O error (may happen for all errors) |
|
-ENOMEDIUM No media inserted. |
|
-EINVAL Invalid sector number or nb_sectors |
|
-EACCES Trying to write a read-only device |
|
*/ |
int bdrv_write(BlockDriverState *bs, int64_t sector_num, |
int bdrv_write(BlockDriverState *bs, int64_t sector_num, |
const uint8_t *buf, int nb_sectors) |
const uint8_t *buf, int nb_sectors) |
{ |
{ |
if (!bs->inserted) |
BlockDriver *drv = bs->drv; |
return -1; |
if (!bs->drv) |
|
return -ENOMEDIUM; |
if (bs->read_only) |
if (bs->read_only) |
return -1; |
return -EACCES; |
if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { |
if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { |
memcpy(bs->boot_sector_data, buf, 512); |
memcpy(bs->boot_sector_data, buf, 512); |
} |
} |
return bs->drv->bdrv_write(bs, sector_num, buf, nb_sectors); |
if (drv->bdrv_pwrite) { |
|
int ret, len; |
|
len = nb_sectors * 512; |
|
ret = drv->bdrv_pwrite(bs, sector_num * 512, buf, len); |
|
if (ret < 0) |
|
return ret; |
|
else if (ret != len) |
|
return -EIO; |
|
else |
|
return 0; |
|
} else { |
|
return drv->bdrv_write(bs, sector_num, buf, nb_sectors); |
|
} |
} |
} |
|
|
|
static int bdrv_pread_em(BlockDriverState *bs, int64_t offset, |
|
uint8_t *buf, int count1) |
|
{ |
|
uint8_t tmp_buf[SECTOR_SIZE]; |
|
int len, nb_sectors, count; |
|
int64_t sector_num; |
|
|
|
count = count1; |
|
/* first read to align to sector start */ |
|
len = (SECTOR_SIZE - offset) & (SECTOR_SIZE - 1); |
|
if (len > count) |
|
len = count; |
|
sector_num = offset >> SECTOR_BITS; |
|
if (len > 0) { |
|
if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0) |
|
return -EIO; |
|
memcpy(buf, tmp_buf + (offset & (SECTOR_SIZE - 1)), len); |
|
count -= len; |
|
if (count == 0) |
|
return count1; |
|
sector_num++; |
|
buf += len; |
|
} |
|
|
|
/* read the sectors "in place" */ |
|
nb_sectors = count >> SECTOR_BITS; |
|
if (nb_sectors > 0) { |
|
if (bdrv_read(bs, sector_num, buf, nb_sectors) < 0) |
|
return -EIO; |
|
sector_num += nb_sectors; |
|
len = nb_sectors << SECTOR_BITS; |
|
buf += len; |
|
count -= len; |
|
} |
|
|
|
/* add data from the last sector */ |
|
if (count > 0) { |
|
if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0) |
|
return -EIO; |
|
memcpy(buf, tmp_buf, count); |
|
} |
|
return count1; |
|
} |
|
|
|
static int bdrv_pwrite_em(BlockDriverState *bs, int64_t offset, |
|
const uint8_t *buf, int count1) |
|
{ |
|
uint8_t tmp_buf[SECTOR_SIZE]; |
|
int len, nb_sectors, count; |
|
int64_t sector_num; |
|
|
|
count = count1; |
|
/* first write to align to sector start */ |
|
len = (SECTOR_SIZE - offset) & (SECTOR_SIZE - 1); |
|
if (len > count) |
|
len = count; |
|
sector_num = offset >> SECTOR_BITS; |
|
if (len > 0) { |
|
if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0) |
|
return -EIO; |
|
memcpy(tmp_buf + (offset & (SECTOR_SIZE - 1)), buf, len); |
|
if (bdrv_write(bs, sector_num, tmp_buf, 1) < 0) |
|
return -EIO; |
|
count -= len; |
|
if (count == 0) |
|
return count1; |
|
sector_num++; |
|
buf += len; |
|
} |
|
|
|
/* write the sectors "in place" */ |
|
nb_sectors = count >> SECTOR_BITS; |
|
if (nb_sectors > 0) { |
|
if (bdrv_write(bs, sector_num, buf, nb_sectors) < 0) |
|
return -EIO; |
|
sector_num += nb_sectors; |
|
len = nb_sectors << SECTOR_BITS; |
|
buf += len; |
|
count -= len; |
|
} |
|
|
|
/* add data from the last sector */ |
|
if (count > 0) { |
|
if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0) |
|
return -EIO; |
|
memcpy(tmp_buf, buf, count); |
|
if (bdrv_write(bs, sector_num, tmp_buf, 1) < 0) |
|
return -EIO; |
|
} |
|
return count1; |
|
} |
|
|
|
/** |
|
* Read with byte offsets (needed only for file protocols) |
|
*/ |
|
int bdrv_pread(BlockDriverState *bs, int64_t offset, |
|
void *buf1, int count1) |
|
{ |
|
BlockDriver *drv = bs->drv; |
|
|
|
if (!drv) |
|
return -ENOMEDIUM; |
|
if (!drv->bdrv_pread) |
|
return bdrv_pread_em(bs, offset, buf1, count1); |
|
return drv->bdrv_pread(bs, offset, buf1, count1); |
|
} |
|
|
|
/** |
|
* Write with byte offsets (needed only for file protocols) |
|
*/ |
|
int bdrv_pwrite(BlockDriverState *bs, int64_t offset, |
|
const void *buf1, int count1) |
|
{ |
|
BlockDriver *drv = bs->drv; |
|
|
|
if (!drv) |
|
return -ENOMEDIUM; |
|
if (!drv->bdrv_pwrite) |
|
return bdrv_pwrite_em(bs, offset, buf1, count1); |
|
return drv->bdrv_pwrite(bs, offset, buf1, count1); |
|
} |
|
|
|
/** |
|
* Truncate file to 'offset' bytes (needed only for file protocols) |
|
*/ |
|
int bdrv_truncate(BlockDriverState *bs, int64_t offset) |
|
{ |
|
BlockDriver *drv = bs->drv; |
|
if (!drv) |
|
return -ENOMEDIUM; |
|
if (!drv->bdrv_truncate) |
|
return -ENOTSUP; |
|
return drv->bdrv_truncate(bs, offset); |
|
} |
|
|
|
/** |
|
* Length of a file in bytes. Return < 0 if error or unknown. |
|
*/ |
|
int64_t bdrv_getlength(BlockDriverState *bs) |
|
{ |
|
BlockDriver *drv = bs->drv; |
|
if (!drv) |
|
return -ENOMEDIUM; |
|
if (!drv->bdrv_getlength) { |
|
/* legacy mode */ |
|
return bs->total_sectors * SECTOR_SIZE; |
|
} |
|
return drv->bdrv_getlength(bs); |
|
} |
|
|
|
/* return 0 as number of sectors if no device present or error */ |
void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr) |
void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr) |
{ |
{ |
*nb_sectors_ptr = bs->total_sectors; |
int64_t length; |
|
length = bdrv_getlength(bs); |
|
if (length < 0) |
|
length = 0; |
|
else |
|
length = length >> SECTOR_BITS; |
|
*nb_sectors_ptr = length; |
} |
} |
|
|
/* force a given boot sector. */ |
/* force a given boot sector. */ |
Line 527 int bdrv_is_read_only(BlockDriverState *
|
Line 777 int bdrv_is_read_only(BlockDriverState *
|
return bs->read_only; |
return bs->read_only; |
} |
} |
|
|
int bdrv_is_inserted(BlockDriverState *bs) |
/* XXX: no longer used */ |
{ |
|
return bs->inserted; |
|
} |
|
|
|
int bdrv_is_locked(BlockDriverState *bs) |
|
{ |
|
return bs->locked; |
|
} |
|
|
|
void bdrv_set_locked(BlockDriverState *bs, int locked) |
|
{ |
|
bs->locked = locked; |
|
} |
|
|
|
void bdrv_set_change_cb(BlockDriverState *bs, |
void bdrv_set_change_cb(BlockDriverState *bs, |
void (*change_cb)(void *opaque), void *opaque) |
void (*change_cb)(void *opaque), void *opaque) |
{ |
{ |
Line 573 int bdrv_set_key(BlockDriverState *bs, c
|
Line 809 int bdrv_set_key(BlockDriverState *bs, c
|
|
|
void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size) |
void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size) |
{ |
{ |
if (!bs->inserted || !bs->drv) { |
if (!bs->drv) { |
buf[0] = '\0'; |
buf[0] = '\0'; |
} else { |
} else { |
pstrcpy(buf, buf_size, bs->drv->format_name); |
pstrcpy(buf, buf_size, bs->drv->format_name); |
Line 645 void bdrv_info(void)
|
Line 881 void bdrv_info(void)
|
if (bs->removable) { |
if (bs->removable) { |
term_printf(" locked=%d", bs->locked); |
term_printf(" locked=%d", bs->locked); |
} |
} |
if (bs->inserted) { |
if (bs->drv) { |
term_printf(" file=%s", bs->filename); |
term_printf(" file="); |
if (bs->backing_file[0] != '\0') |
term_print_filename(bs->filename); |
term_printf(" backing_file=%s", bs->backing_file); |
if (bs->backing_file[0] != '\0') { |
|
term_printf(" backing_file="); |
|
term_print_filename(bs->backing_file); |
|
} |
term_printf(" ro=%d", bs->read_only); |
term_printf(" ro=%d", bs->read_only); |
term_printf(" drv=%s", bs->drv->format_name); |
term_printf(" drv=%s", bs->drv->format_name); |
if (bs->encrypted) |
if (bs->encrypted) |
Line 660 void bdrv_info(void)
|
Line 899 void bdrv_info(void)
|
} |
} |
} |
} |
|
|
|
void bdrv_get_backing_filename(BlockDriverState *bs, |
|
char *filename, int filename_size) |
|
{ |
|
if (!bs->backing_hd) { |
|
pstrcpy(filename, filename_size, ""); |
|
} else { |
|
pstrcpy(filename, filename_size, bs->backing_file); |
|
} |
|
} |
|
|
|
int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, |
|
const uint8_t *buf, int nb_sectors) |
|
{ |
|
BlockDriver *drv = bs->drv; |
|
if (!drv) |
|
return -ENOMEDIUM; |
|
if (!drv->bdrv_write_compressed) |
|
return -ENOTSUP; |
|
return drv->bdrv_write_compressed(bs, sector_num, buf, nb_sectors); |
|
} |
|
|
|
int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) |
|
{ |
|
BlockDriver *drv = bs->drv; |
|
if (!drv) |
|
return -ENOMEDIUM; |
|
if (!drv->bdrv_get_info) |
|
return -ENOTSUP; |
|
memset(bdi, 0, sizeof(*bdi)); |
|
return drv->bdrv_get_info(bs, bdi); |
|
} |
|
|
/**************************************************************/ |
/**************************************************************/ |
/* RAW block driver */ |
/* handling of snapshots */ |
|
|
typedef struct BDRVRawState { |
int bdrv_snapshot_create(BlockDriverState *bs, |
int fd; |
QEMUSnapshotInfo *sn_info) |
} BDRVRawState; |
{ |
|
BlockDriver *drv = bs->drv; |
|
if (!drv) |
|
return -ENOMEDIUM; |
|
if (!drv->bdrv_snapshot_create) |
|
return -ENOTSUP; |
|
return drv->bdrv_snapshot_create(bs, sn_info); |
|
} |
|
|
static int raw_probe(const uint8_t *buf, int buf_size, const char *filename) |
int bdrv_snapshot_goto(BlockDriverState *bs, |
|
const char *snapshot_id) |
{ |
{ |
return 1; /* maybe */ |
BlockDriver *drv = bs->drv; |
|
if (!drv) |
|
return -ENOMEDIUM; |
|
if (!drv->bdrv_snapshot_goto) |
|
return -ENOTSUP; |
|
return drv->bdrv_snapshot_goto(bs, snapshot_id); |
} |
} |
|
|
static int raw_open(BlockDriverState *bs, const char *filename) |
int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id) |
{ |
{ |
BDRVRawState *s = bs->opaque; |
BlockDriver *drv = bs->drv; |
int fd; |
if (!drv) |
int64_t size; |
return -ENOMEDIUM; |
#ifdef _BSD |
if (!drv->bdrv_snapshot_delete) |
struct stat sb; |
return -ENOTSUP; |
#endif |
return drv->bdrv_snapshot_delete(bs, snapshot_id); |
#ifdef __sun__ |
} |
struct dk_minfo minfo; |
|
int rv; |
|
#endif |
|
|
|
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); |
int bdrv_snapshot_list(BlockDriverState *bs, |
if (fd < 0) { |
QEMUSnapshotInfo **psn_info) |
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); |
{ |
if (fd < 0) |
BlockDriver *drv = bs->drv; |
return -1; |
if (!drv) |
bs->read_only = 1; |
return -ENOMEDIUM; |
|
if (!drv->bdrv_snapshot_list) |
|
return -ENOTSUP; |
|
return drv->bdrv_snapshot_list(bs, psn_info); |
|
} |
|
|
|
#define NB_SUFFIXES 4 |
|
|
|
char *get_human_readable_size(char *buf, int buf_size, int64_t size) |
|
{ |
|
static const char suffixes[NB_SUFFIXES] = "KMGT"; |
|
int64_t base; |
|
int i; |
|
|
|
if (size <= 999) { |
|
snprintf(buf, buf_size, "%" PRId64, size); |
|
} else { |
|
base = 1024; |
|
for(i = 0; i < NB_SUFFIXES; i++) { |
|
if (size < (10 * base)) { |
|
snprintf(buf, buf_size, "%0.1f%c", |
|
(double)size / base, |
|
suffixes[i]); |
|
break; |
|
} else if (size < (1000 * base) || i == (NB_SUFFIXES - 1)) { |
|
snprintf(buf, buf_size, "%" PRId64 "%c", |
|
((size + (base >> 1)) / base), |
|
suffixes[i]); |
|
break; |
|
} |
|
base = base * 1024; |
|
} |
} |
} |
#ifdef _BSD |
return buf; |
if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) { |
} |
#ifdef DIOCGMEDIASIZE |
|
if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size)) |
char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn) |
#endif |
{ |
#ifdef CONFIG_COCOA |
char buf1[128], date_buf[128], clock_buf[128]; |
size = LONG_LONG_MAX; |
#ifdef _WIN32 |
|
struct tm *ptm; |
#else |
#else |
size = lseek(fd, 0LL, SEEK_END); |
struct tm tm; |
#endif |
#endif |
} else |
time_t ti; |
#endif |
int64_t secs; |
#ifdef __sun__ |
|
/* |
if (!sn) { |
* use the DKIOCGMEDIAINFO ioctl to read the size. |
snprintf(buf, buf_size, |
*/ |
"%-10s%-20s%7s%20s%15s", |
rv = ioctl ( fd, DKIOCGMEDIAINFO, &minfo ); |
"ID", "TAG", "VM SIZE", "DATE", "VM CLOCK"); |
if ( rv != -1 ) { |
} else { |
size = minfo.dki_lbsize * minfo.dki_capacity; |
ti = sn->date_sec; |
} else /* there are reports that lseek on some devices |
|
fails, but irc discussion said that contingency |
|
on contingency was overkill */ |
|
#endif |
|
{ |
|
size = lseek(fd, 0, SEEK_END); |
|
} |
|
#ifdef _WIN32 |
#ifdef _WIN32 |
/* On Windows hosts it can happen that we're unable to get file size |
ptm = localtime(&ti); |
for CD-ROM raw device (it's inherent limitation of the CDFS driver). */ |
strftime(date_buf, sizeof(date_buf), |
if (size == -1) |
"%Y-%m-%d %H:%M:%S", ptm); |
size = LONG_LONG_MAX; |
#else |
|
localtime_r(&ti, &tm); |
|
strftime(date_buf, sizeof(date_buf), |
|
"%Y-%m-%d %H:%M:%S", &tm); |
#endif |
#endif |
bs->total_sectors = size / 512; |
secs = sn->vm_clock_nsec / 1000000000; |
s->fd = fd; |
snprintf(clock_buf, sizeof(clock_buf), |
return 0; |
"%02d:%02d:%02d.%03d", |
|
(int)(secs / 3600), |
|
(int)((secs / 60) % 60), |
|
(int)(secs % 60), |
|
(int)((sn->vm_clock_nsec / 1000000) % 1000)); |
|
snprintf(buf, buf_size, |
|
"%-10s%-20s%7s%20s%15s", |
|
sn->id_str, sn->name, |
|
get_human_readable_size(buf1, sizeof(buf1), sn->vm_state_size), |
|
date_buf, |
|
clock_buf); |
|
} |
|
return buf; |
} |
} |
|
|
static int raw_read(BlockDriverState *bs, int64_t sector_num, |
|
uint8_t *buf, int nb_sectors) |
|
{ |
|
BDRVRawState *s = bs->opaque; |
|
int ret; |
|
|
|
lseek(s->fd, sector_num * 512, SEEK_SET); |
|
ret = read(s->fd, buf, nb_sectors * 512); |
|
if (ret != nb_sectors * 512) |
|
return -1; |
|
return 0; |
|
} |
|
|
|
static int raw_write(BlockDriverState *bs, int64_t sector_num, |
/**************************************************************/ |
const uint8_t *buf, int nb_sectors) |
/* async I/Os */ |
|
|
|
BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num, |
|
uint8_t *buf, int nb_sectors, |
|
BlockDriverCompletionFunc *cb, void *opaque) |
{ |
{ |
BDRVRawState *s = bs->opaque; |
BlockDriver *drv = bs->drv; |
int ret; |
|
|
if (!drv) |
|
return NULL; |
|
|
lseek(s->fd, sector_num * 512, SEEK_SET); |
/* XXX: we assume that nb_sectors == 0 is suppored by the async read */ |
ret = write(s->fd, buf, nb_sectors * 512); |
if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { |
if (ret != nb_sectors * 512) |
memcpy(buf, bs->boot_sector_data, 512); |
return -1; |
sector_num++; |
return 0; |
nb_sectors--; |
|
buf += 512; |
|
} |
|
|
|
return drv->bdrv_aio_read(bs, sector_num, buf, nb_sectors, cb, opaque); |
} |
} |
|
|
static void raw_close(BlockDriverState *bs) |
BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num, |
|
const uint8_t *buf, int nb_sectors, |
|
BlockDriverCompletionFunc *cb, void *opaque) |
{ |
{ |
BDRVRawState *s = bs->opaque; |
BlockDriver *drv = bs->drv; |
close(s->fd); |
|
} |
|
|
|
#ifdef _WIN32 |
if (!drv) |
#include <windows.h> |
return NULL; |
#include <winioctl.h> |
if (bs->read_only) |
|
return NULL; |
|
if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { |
|
memcpy(bs->boot_sector_data, buf, 512); |
|
} |
|
|
int qemu_ftruncate64(int fd, int64_t length) |
return drv->bdrv_aio_write(bs, sector_num, buf, nb_sectors, cb, opaque); |
|
} |
|
|
|
void bdrv_aio_cancel(BlockDriverAIOCB *acb) |
{ |
{ |
LARGE_INTEGER li; |
BlockDriver *drv = acb->bs->drv; |
LONG high; |
|
HANDLE h; |
|
BOOL res; |
|
|
|
if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0) |
drv->bdrv_aio_cancel(acb); |
return -1; |
} |
|
|
h = (HANDLE)_get_osfhandle(fd); |
|
|
|
/* get current position, ftruncate do not change position */ |
/**************************************************************/ |
li.HighPart = 0; |
/* async block device emulation */ |
li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT); |
|
if (li.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR) |
|
return -1; |
|
|
|
high = length >> 32; |
#ifdef QEMU_TOOL |
if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN)) |
static BlockDriverAIOCB *bdrv_aio_read_em(BlockDriverState *bs, |
return -1; |
int64_t sector_num, uint8_t *buf, int nb_sectors, |
res = SetEndOfFile(h); |
BlockDriverCompletionFunc *cb, void *opaque) |
|
{ |
|
int ret; |
|
ret = bdrv_read(bs, sector_num, buf, nb_sectors); |
|
cb(opaque, ret); |
|
return NULL; |
|
} |
|
|
/* back to old position */ |
static BlockDriverAIOCB *bdrv_aio_write_em(BlockDriverState *bs, |
SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN); |
int64_t sector_num, const uint8_t *buf, int nb_sectors, |
return res ? 0 : -1; |
BlockDriverCompletionFunc *cb, void *opaque) |
|
{ |
|
int ret; |
|
ret = bdrv_write(bs, sector_num, buf, nb_sectors); |
|
cb(opaque, ret); |
|
return NULL; |
} |
} |
|
|
static int set_sparse(int fd) |
static void bdrv_aio_cancel_em(BlockDriverAIOCB *acb) |
{ |
{ |
DWORD returned; |
|
return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE, |
|
NULL, 0, NULL, 0, &returned, NULL); |
|
} |
} |
#else |
#else |
static inline int set_sparse(int fd) |
static void bdrv_aio_bh_cb(void *opaque) |
{ |
{ |
return 1; |
BlockDriverAIOCBSync *acb = opaque; |
|
acb->common.cb(acb->common.opaque, acb->ret); |
|
qemu_aio_release(acb); |
} |
} |
#endif |
|
|
|
static int raw_create(const char *filename, int64_t total_size, |
static BlockDriverAIOCB *bdrv_aio_read_em(BlockDriverState *bs, |
const char *backing_file, int flags) |
int64_t sector_num, uint8_t *buf, int nb_sectors, |
|
BlockDriverCompletionFunc *cb, void *opaque) |
{ |
{ |
int fd; |
BlockDriverAIOCBSync *acb; |
|
int ret; |
|
|
if (flags || backing_file) |
acb = qemu_aio_get(bs, cb, opaque); |
return -ENOTSUP; |
if (!acb->bh) |
|
acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb); |
|
ret = bdrv_read(bs, sector_num, buf, nb_sectors); |
|
acb->ret = ret; |
|
qemu_bh_schedule(acb->bh); |
|
return &acb->common; |
|
} |
|
|
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, |
static BlockDriverAIOCB *bdrv_aio_write_em(BlockDriverState *bs, |
0644); |
int64_t sector_num, const uint8_t *buf, int nb_sectors, |
if (fd < 0) |
BlockDriverCompletionFunc *cb, void *opaque) |
return -EIO; |
{ |
set_sparse(fd); |
BlockDriverAIOCBSync *acb; |
ftruncate(fd, total_size * 512); |
int ret; |
close(fd); |
|
return 0; |
acb = qemu_aio_get(bs, cb, opaque); |
|
if (!acb->bh) |
|
acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb); |
|
ret = bdrv_write(bs, sector_num, buf, nb_sectors); |
|
acb->ret = ret; |
|
qemu_bh_schedule(acb->bh); |
|
return &acb->common; |
|
} |
|
|
|
static void bdrv_aio_cancel_em(BlockDriverAIOCB *blockacb) |
|
{ |
|
BlockDriverAIOCBSync *acb = (BlockDriverAIOCBSync *)blockacb; |
|
qemu_bh_cancel(acb->bh); |
|
qemu_aio_release(acb); |
} |
} |
|
#endif /* !QEMU_TOOL */ |
|
|
static void raw_flush(BlockDriverState *bs) |
/**************************************************************/ |
|
/* sync block device emulation */ |
|
|
|
static void bdrv_rw_em_cb(void *opaque, int ret) |
{ |
{ |
BDRVRawState *s = bs->opaque; |
*(int *)opaque = ret; |
fsync(s->fd); |
|
} |
} |
|
|
BlockDriver bdrv_raw = { |
#define NOT_DONE 0x7fffffff |
"raw", |
|
sizeof(BDRVRawState), |
static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num, |
raw_probe, |
uint8_t *buf, int nb_sectors) |
raw_open, |
{ |
raw_read, |
int async_ret; |
raw_write, |
BlockDriverAIOCB *acb; |
raw_close, |
|
raw_create, |
async_ret = NOT_DONE; |
raw_flush, |
qemu_aio_wait_start(); |
}; |
acb = bdrv_aio_read(bs, sector_num, buf, nb_sectors, |
|
bdrv_rw_em_cb, &async_ret); |
|
if (acb == NULL) { |
|
qemu_aio_wait_end(); |
|
return -1; |
|
} |
|
while (async_ret == NOT_DONE) { |
|
qemu_aio_wait(); |
|
} |
|
qemu_aio_wait_end(); |
|
return async_ret; |
|
} |
|
|
|
static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num, |
|
const uint8_t *buf, int nb_sectors) |
|
{ |
|
int async_ret; |
|
BlockDriverAIOCB *acb; |
|
|
|
async_ret = NOT_DONE; |
|
qemu_aio_wait_start(); |
|
acb = bdrv_aio_write(bs, sector_num, buf, nb_sectors, |
|
bdrv_rw_em_cb, &async_ret); |
|
if (acb == NULL) { |
|
qemu_aio_wait_end(); |
|
return -1; |
|
} |
|
while (async_ret == NOT_DONE) { |
|
qemu_aio_wait(); |
|
} |
|
qemu_aio_wait_end(); |
|
return async_ret; |
|
} |
|
|
void bdrv_init(void) |
void bdrv_init(void) |
{ |
{ |
bdrv_register(&bdrv_raw); |
bdrv_register(&bdrv_raw); |
|
bdrv_register(&bdrv_host_device); |
#ifndef _WIN32 |
#ifndef _WIN32 |
bdrv_register(&bdrv_cow); |
bdrv_register(&bdrv_cow); |
#endif |
#endif |
Line 855 void bdrv_init(void)
|
Line 1240 void bdrv_init(void)
|
bdrv_register(&bdrv_bochs); |
bdrv_register(&bdrv_bochs); |
bdrv_register(&bdrv_vpc); |
bdrv_register(&bdrv_vpc); |
bdrv_register(&bdrv_vvfat); |
bdrv_register(&bdrv_vvfat); |
|
bdrv_register(&bdrv_qcow2); |
|
} |
|
|
|
void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb, |
|
void *opaque) |
|
{ |
|
BlockDriver *drv; |
|
BlockDriverAIOCB *acb; |
|
|
|
drv = bs->drv; |
|
if (drv->free_aiocb) { |
|
acb = drv->free_aiocb; |
|
drv->free_aiocb = acb->next; |
|
} else { |
|
acb = qemu_mallocz(drv->aiocb_size); |
|
if (!acb) |
|
return NULL; |
|
} |
|
acb->bs = bs; |
|
acb->cb = cb; |
|
acb->opaque = opaque; |
|
return acb; |
|
} |
|
|
|
void qemu_aio_release(void *p) |
|
{ |
|
BlockDriverAIOCB *acb = p; |
|
BlockDriver *drv = acb->bs->drv; |
|
acb->next = drv->free_aiocb; |
|
drv->free_aiocb = acb; |
|
} |
|
|
|
/**************************************************************/ |
|
/* removable device support */ |
|
|
|
/** |
|
* Return TRUE if the media is present |
|
*/ |
|
int bdrv_is_inserted(BlockDriverState *bs) |
|
{ |
|
BlockDriver *drv = bs->drv; |
|
int ret; |
|
if (!drv) |
|
return 0; |
|
if (!drv->bdrv_is_inserted) |
|
return 1; |
|
ret = drv->bdrv_is_inserted(bs); |
|
return ret; |
|
} |
|
|
|
/** |
|
* Return TRUE if the media changed since the last call to this |
|
* function. It is currently only used for floppy disks |
|
*/ |
|
int bdrv_media_changed(BlockDriverState *bs) |
|
{ |
|
BlockDriver *drv = bs->drv; |
|
int ret; |
|
|
|
if (!drv || !drv->bdrv_media_changed) |
|
ret = -ENOTSUP; |
|
else |
|
ret = drv->bdrv_media_changed(bs); |
|
if (ret == -ENOTSUP) |
|
ret = bs->media_changed; |
|
bs->media_changed = 0; |
|
return ret; |
|
} |
|
|
|
/** |
|
* If eject_flag is TRUE, eject the media. Otherwise, close the tray |
|
*/ |
|
void bdrv_eject(BlockDriverState *bs, int eject_flag) |
|
{ |
|
BlockDriver *drv = bs->drv; |
|
int ret; |
|
|
|
if (!drv || !drv->bdrv_eject) { |
|
ret = -ENOTSUP; |
|
} else { |
|
ret = drv->bdrv_eject(bs, eject_flag); |
|
} |
|
if (ret == -ENOTSUP) { |
|
if (eject_flag) |
|
bdrv_close(bs); |
|
} |
|
} |
|
|
|
int bdrv_is_locked(BlockDriverState *bs) |
|
{ |
|
return bs->locked; |
|
} |
|
|
|
/** |
|
* Lock or unlock the media (if it is locked, the user won't be able |
|
* to eject it manually). |
|
*/ |
|
void bdrv_set_locked(BlockDriverState *bs, int locked) |
|
{ |
|
BlockDriver *drv = bs->drv; |
|
|
|
bs->locked = locked; |
|
if (drv && drv->bdrv_set_locked) { |
|
drv->bdrv_set_locked(bs, locked); |
|
} |
} |
} |