/*
* Block driver for RAW files
- *
+ *
* Copyright (c) 2006 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
#endif
#ifdef __sun__
+#define _POSIX_PTHREAD_SEMANTICS 1
+#include <signal.h>
#include <sys/dkio.h>
#endif
#ifdef __linux__
#include <linux/cdrom.h>
#include <linux/fd.h>
#endif
+#ifdef __FreeBSD__
+#include <sys/disk.h>
+#endif
//#define DEBUG_FLOPPY
+#define DEBUG_BLOCK
+#if defined(DEBUG_BLOCK) && !defined(QEMU_TOOL)
+#define DEBUG_BLOCK_PRINT(formatCstr, args...) do { if (loglevel != 0) \
+ { fprintf(stderr, formatCstr, ##args); fflush(stderr); } } while (0)
+#else
+#define DEBUG_BLOCK_PRINT(formatCstr, args...)
+#endif
+
#define FTYPE_FILE 0
#define FTYPE_CD 1
#define FTYPE_FD 2
typedef struct BDRVRawState {
int fd;
int type;
+ unsigned int lseek_err_cnt;
#if defined(__linux__)
/* linux floppy specific */
int fd_open_flags;
BDRVRawState *s = bs->opaque;
int fd, open_flags, ret;
+ s->lseek_err_cnt = 0;
+
open_flags = O_BINARY;
if ((flags & BDRV_O_ACCESS) == O_RDWR) {
open_flags |= O_RDWR;
#endif
*/
-static int raw_pread(BlockDriverState *bs, int64_t offset,
+static int raw_pread(BlockDriverState *bs, int64_t offset,
uint8_t *buf, int count)
{
BDRVRawState *s = bs->opaque;
int ret;
-
+
ret = fd_open(bs);
if (ret < 0)
return ret;
- lseek(s->fd, offset, SEEK_SET);
+ if (lseek(s->fd, offset, SEEK_SET) == (off_t)-1) {
+ ++(s->lseek_err_cnt);
+ if(s->lseek_err_cnt <= 10) {
+ DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %lld, %p, %d) [%lld] lseek failed : %d = %s\n",
+ s->fd, bs->filename, offset, buf, count,
+ bs->total_sectors, errno, strerror(errno));
+ }
+ return -1;
+ }
+ s->lseek_err_cnt=0;
+
ret = read(s->fd, buf, count);
+ if (ret == count)
+ goto label__raw_read__success;
+
+ DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %lld, %p, %d) [%lld] read failed %d : %d = %s\n",
+ s->fd, bs->filename, offset, buf, count,
+ bs->total_sectors, ret, errno, strerror(errno));
+
+ /* Try harder for CDrom. */
+ if (bs->type == BDRV_TYPE_CDROM) {
+ lseek(s->fd, offset, SEEK_SET);
+ ret = read(s->fd, buf, count);
+ if (ret == count)
+ goto label__raw_read__success;
+ lseek(s->fd, offset, SEEK_SET);
+ ret = read(s->fd, buf, count);
+ if (ret == count)
+ goto label__raw_read__success;
+
+ DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %lld, %p, %d) [%lld] retry read failed %d : %d = %s\n",
+ s->fd, bs->filename, offset, buf, count,
+ bs->total_sectors, ret, errno, strerror(errno));
+ }
+
+label__raw_read__success:
+
return ret;
}
-static int raw_pwrite(BlockDriverState *bs, int64_t offset,
+static int raw_pwrite(BlockDriverState *bs, int64_t offset,
const uint8_t *buf, int count)
{
BDRVRawState *s = bs->opaque;
int ret;
-
+
ret = fd_open(bs);
if (ret < 0)
return ret;
- lseek(s->fd, offset, SEEK_SET);
+ if (lseek(s->fd, offset, SEEK_SET) == (off_t)-1) {
+ ++(s->lseek_err_cnt);
+ if(s->lseek_err_cnt) {
+ DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %lld, %p, %d) [%lld] lseek failed : %d = %s\n",
+ s->fd, bs->filename, offset, buf, count,
+ bs->total_sectors, errno, strerror(errno));
+ }
+ return -1;
+ }
+ s->lseek_err_cnt = 0;
+
ret = write(s->fd, buf, count);
+ if (ret == count)
+ goto label__raw_write__success;
+
+ DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %lld, %p, %d) [%lld] write failed %d : %d = %s\n",
+ s->fd, bs->filename, offset, buf, count,
+ bs->total_sectors, ret, errno, strerror(errno));
+
+label__raw_write__success:
+
return ret;
}
struct sigaction act;
aio_initialized = 1;
-
+
sigfillset(&act.sa_mask);
act.sa_flags = 0; /* do not restart syscalls to interrupt select() */
act.sa_handler = aio_signal_handler;
the_end: ;
}
+/* Wait for all IO requests to complete. */
+void qemu_aio_flush(void)
+{
+ qemu_aio_wait_start();
+ qemu_aio_poll();
+ while (first_aio) {
+ qemu_aio_wait();
+ }
+ qemu_aio_wait_end();
+}
+
/* wait until at least one AIO was handled */
static sigset_t wait_oset;
if (aio_read(&acb->aiocb) < 0) {
qemu_aio_release(acb);
return NULL;
- }
+ }
return &acb->common;
}
if (aio_write(&acb->aiocb) < 0) {
qemu_aio_release(acb);
return NULL;
- }
+ }
return &acb->common;
}
if (flags || backing_file)
return -ENOTSUP;
- fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
+ fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
0644);
if (fd < 0)
return -EIO;
raw_close,
raw_create,
raw_flush,
-
+
.bdrv_aio_read = raw_aio_read,
.bdrv_aio_write = raw_aio_write,
.bdrv_aio_cancel = raw_aio_cancel,
kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
{
- kern_return_t kernResult;
+ kern_return_t kernResult;
mach_port_t masterPort;
CFMutableDictionaryRef classesToMatch;
if ( KERN_SUCCESS != kernResult ) {
printf( "IOMasterPort returned %d\n", kernResult );
}
-
- classesToMatch = IOServiceMatching( kIOCDMediaClass );
+
+ classesToMatch = IOServiceMatching( kIOCDMediaClass );
if ( classesToMatch == NULL ) {
printf( "IOServiceMatching returned a NULL dictionary.\n" );
} else {
{
printf( "IOServiceGetMatchingServices returned %d\n", kernResult );
}
-
+
return kernResult;
}
}
IOObjectRelease( nextMedia );
}
-
+
return 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 */
}
filename = bsdPath;
}
-
+
if ( mediaIterator )
IOObjectRelease( mediaIterator );
}
if (s->type != FTYPE_FD)
return 0;
last_media_present = (s->fd >= 0);
- if (s->fd >= 0 &&
+ if (s->fd >= 0 &&
(qemu_get_clock(rt_clock) - s->fd_open_time) >= FD_OPEN_TIMEOUT) {
close(s->fd);
s->fd = -1;
#endif
}
if (s->fd < 0) {
- if (s->fd_got_error &&
+ if (s->fd_got_error &&
(qemu_get_clock(rt_clock) - s->fd_error_time) < FD_OPEN_TIMEOUT) {
#ifdef DEBUG_FLOPPY
printf("No floppy (open delayed)\n");
raw_close,
NULL,
raw_flush,
-
+
.bdrv_aio_read = raw_aio_read,
.bdrv_aio_write = raw_aio_write,
.bdrv_aio_cancel = raw_aio_cancel,
#define FTYPE_FILE 0
#define FTYPE_CD 1
+#define FTYPE_HARDDISK 2
typedef struct BDRVRawState {
HANDLE hfile;
create_flags = OPEN_EXISTING;
}
#ifdef QEMU_TOOL
- overlapped = 0;
+ overlapped = FILE_ATTRIBUTE_NORMAL;
#else
overlapped = FILE_FLAG_OVERLAPPED;
#endif
- s->hfile = CreateFile(filename, access_flags,
+ s->hfile = CreateFile(filename, access_flags,
FILE_SHARE_READ, NULL,
- create_flags, overlapped, 0);
- if (s->hfile == INVALID_HANDLE_VALUE)
+ create_flags, overlapped, NULL);
+ if (s->hfile == INVALID_HANDLE_VALUE) {
+ int err = GetLastError();
+
+ if (err == ERROR_ACCESS_DENIED)
+ return -EACCES;
return -1;
+ }
return 0;
}
-static int raw_pread(BlockDriverState *bs, int64_t offset,
+static int raw_pread(BlockDriverState *bs, int64_t offset,
uint8_t *buf, int count)
{
BDRVRawState *s = bs->opaque;
OVERLAPPED ov;
DWORD ret_count;
int ret;
-
+
memset(&ov, 0, sizeof(ov));
ov.Offset = offset;
ov.OffsetHigh = offset >> 32;
return ret_count;
}
-static int raw_pwrite(BlockDriverState *bs, int64_t offset,
+static int raw_pwrite(BlockDriverState *bs, int64_t offset,
const uint8_t *buf, int count)
{
BDRVRawState *s = bs->opaque;
OVERLAPPED ov;
DWORD ret_count;
int ret;
-
+
memset(&ov, 0, sizeof(ov));
ov.Offset = offset;
ov.OffsetHigh = offset >> 32;
return ret_count;
}
+#if 0
#ifndef QEMU_TOOL
static void raw_aio_cb(void *opaque)
{
qemu_aio_release(acb);
#endif
}
+#endif /* #if 0 */
static void raw_flush(BlockDriverState *bs)
{
- /* XXX: add it */
+ BDRVRawState *s = bs->opaque;
+ FlushFileBuffers(s->hfile);
}
static void raw_close(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
LARGE_INTEGER l;
- ULARGE_INTEGER available, total, total_free;
+ ULARGE_INTEGER available, total, total_free;
+ DISK_GEOMETRY dg;
+ DWORD count;
+ BOOL status;
switch(s->type) {
case FTYPE_FILE:
return -EIO;
l.QuadPart = total.QuadPart;
break;
+ case FTYPE_HARDDISK:
+ status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY,
+ NULL, 0, &dg, sizeof(dg), &count, NULL);
+ if (status != FALSE) {
+ l.QuadPart = dg.Cylinders.QuadPart * dg.TracksPerCylinder
+ * dg.SectorsPerTrack * dg.BytesPerSector;
+ }
+ break;
default:
return -EIO;
}
if (flags || backing_file)
return -ENOTSUP;
- fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
+ fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
0644);
if (fd < 0)
return -EIO;
{
}
+void qemu_aio_flush(void)
+{
+}
+
void qemu_aio_wait_start(void)
{
}
void qemu_aio_wait(void)
{
+#ifndef QEMU_TOOL
+ qemu_bh_poll();
+#endif
}
void qemu_aio_wait_end(void)
raw_close,
raw_create,
raw_flush,
-
+
#if 0
.bdrv_aio_read = raw_aio_read,
.bdrv_aio_write = raw_aio_write,
if (strstart(filename, "\\\\.\\", &p) ||
strstart(filename, "//./", &p)) {
+ if (stristart(p, "PhysicalDrive", NULL))
+ return FTYPE_HARDDISK;
snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", p[0]);
type = GetDriveType(s->drive_path);
if (type == DRIVE_CDROM)
create_flags = OPEN_EXISTING;
#ifdef QEMU_TOOL
- overlapped = 0;
+ overlapped = FILE_ATTRIBUTE_NORMAL;
#else
overlapped = FILE_FLAG_OVERLAPPED;
#endif
- s->hfile = CreateFile(filename, access_flags,
+ s->hfile = CreateFile(filename, access_flags,
FILE_SHARE_READ, NULL,
- create_flags, overlapped, 0);
- if (s->hfile == INVALID_HANDLE_VALUE)
+ create_flags, overlapped, NULL);
+ if (s->hfile == INVALID_HANDLE_VALUE) {
+ int err = GetLastError();
+
+ if (err == ERROR_ACCESS_DENIED)
+ return -EACCES;
return -1;
+ }
return 0;
}
#if 0
/***********************************************/
-/* removable device additionnal commands */
+/* removable device additional commands */
static int raw_is_inserted(BlockDriverState *bs)
{
if (s->type == FTYPE_FILE)
return -ENOTSUP;
if (eject_flag) {
- DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA,
+ DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA,
NULL, 0, NULL, 0, &lpBytesReturned, NULL);
} else {
- DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA,
+ DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA,
NULL, 0, NULL, 0, &lpBytesReturned, NULL);
}
}
raw_close,
NULL,
raw_flush,
-
+
#if 0
.bdrv_aio_read = raw_aio_read,
.bdrv_aio_write = raw_aio_write,