Break up vl.h.
[qemu] / block-raw.c
index 3a2843c..732b4b8 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * 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
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-#include "vl.h"
+#include "qemu-common.h"
+#ifndef QEMU_IMG
+#include "qemu-timer.h"
+#include "exec-all.h"
+#endif
 #include "block_int.h"
 #include <assert.h>
 #ifndef _WIN32
 #include <aio.h>
 
-#ifndef QEMU_TOOL
-#include "exec-all.h"
-#endif
-
 #ifdef CONFIG_COCOA
 #include <paths.h>
 #include <sys/param.h>
@@ -44,6 +44,8 @@
 #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_IMG)
+#define DEBUG_BLOCK_PRINT(formatCstr, args...) do { if (loglevel != 0) \
+    { fprintf(logfile, formatCstr, ##args); fflush(logfile); } } while (0)
+#else
+#define DEBUG_BLOCK_PRINT(formatCstr, args...)
+#endif
+
 #define FTYPE_FILE   0
 #define FTYPE_CD     1
 #define FTYPE_FD     2
@@ -65,6 +78,7 @@
 typedef struct BDRVRawState {
     int fd;
     int type;
+    unsigned int lseek_err_cnt;
 #if defined(__linux__)
     /* linux floppy specific */
     int fd_open_flags;
@@ -82,6 +96,8 @@ static int raw_open(BlockDriverState *bs, const char *filename, int 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;
@@ -122,33 +138,92 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
 #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, %" PRId64 ", %p, %d) [%" PRId64
+                              "] 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, %" PRId64 ", %p, %d) [%" PRId64
+                      "] 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, %" PRId64 ", %p, %d) [%" PRId64
+                          "] 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, %" PRId64 ", %p, %d) [%"
+                              PRId64 "] 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, %" PRId64 ", %p, %d) [%" PRId64
+                      "] 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;
 }
 
@@ -167,7 +242,7 @@ static int aio_initialized = 0;
 
 static void aio_signal_handler(int signum)
 {
-#ifndef QEMU_TOOL
+#ifndef QEMU_IMG
     CPUState *env = cpu_single_env;
     if (env) {
         /* stop the currently executing cpu because a timer occured */
@@ -186,7 +261,7 @@ void qemu_aio_init(void)
     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;
@@ -277,7 +352,7 @@ void qemu_aio_wait(void)
     sigset_t set;
     int nb_sigs;
 
-#ifndef QEMU_TOOL
+#ifndef QEMU_IMG
     if (qemu_bh_poll())
         return;
 #endif
@@ -328,7 +403,7 @@ static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs,
     if (aio_read(&acb->aiocb) < 0) {
         qemu_aio_release(acb);
         return NULL;
-    } 
+    }
     return &acb->common;
 }
 
@@ -344,7 +419,7 @@ static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs,
     if (aio_write(&acb->aiocb) < 0) {
         qemu_aio_release(acb);
         return NULL;
-    } 
+    }
     return &acb->common;
 }
 
@@ -449,7 +524,7 @@ static int raw_create(const char *filename, int64_t total_size,
     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;
@@ -474,7 +549,7 @@ BlockDriver bdrv_raw = {
     raw_close,
     raw_create,
     raw_flush,
-    
+
     .bdrv_aio_read = raw_aio_read,
     .bdrv_aio_write = raw_aio_write,
     .bdrv_aio_cancel = raw_aio_cancel,
@@ -495,7 +570,7 @@ static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFI
 
 kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
 {
-    kern_return_t       kernResult; 
+    kern_return_t       kernResult;
     mach_port_t     masterPort;
     CFMutableDictionaryRef  classesToMatch;
 
@@ -503,8 +578,8 @@ kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
     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 {
@@ -515,7 +590,7 @@ kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
     {
         printf( "IOServiceGetMatchingServices returned %d\n", kernResult );
     }
-    
+
     return kernResult;
 }
 
@@ -541,7 +616,7 @@ kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex ma
         }
         IOObjectRelease( nextMedia );
     }
-    
+
     return kernResult;
 }
 
@@ -558,10 +633,10 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
         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 */
@@ -573,7 +648,7 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
             }
             filename = bsdPath;
         }
-        
+
         if ( mediaIterator )
             IOObjectRelease( mediaIterator );
     }
@@ -618,7 +693,7 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
     return 0;
 }
 
-#if defined(__linux__) && !defined(QEMU_TOOL)
+#if defined(__linux__) && !defined(QEMU_IMG)
 
 /* Note: we do not have a reliable method to detect if the floppy is
    present. The current method is to try to open the floppy at every
@@ -631,7 +706,7 @@ static int fd_open(BlockDriverState *bs)
     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;
@@ -640,7 +715,7 @@ static int fd_open(BlockDriverState *bs)
 #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");
@@ -810,7 +885,7 @@ BlockDriver bdrv_host_device = {
     raw_close,
     NULL,
     raw_flush,
-    
+
     .bdrv_aio_read = raw_aio_read,
     .bdrv_aio_write = raw_aio_write,
     .bdrv_aio_cancel = raw_aio_cancel,
@@ -833,6 +908,7 @@ BlockDriver bdrv_host_device = {
 
 #define FTYPE_FILE 0
 #define FTYPE_CD     1
+#define FTYPE_HARDDISK 2
 
 typedef struct BDRVRawState {
     HANDLE hfile;
@@ -900,27 +976,32 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
     } else {
         create_flags = OPEN_EXISTING;
     }
-#ifdef QEMU_TOOL
-    overlapped = 0;
+#ifdef QEMU_IMG
+    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;
@@ -935,14 +1016,14 @@ static int raw_pread(BlockDriverState *bs, int64_t offset,
     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;
@@ -957,7 +1038,8 @@ static int raw_pwrite(BlockDriverState *bs, int64_t offset,
     return ret_count;
 }
 
-#ifndef QEMU_TOOL
+#if 0
+#ifndef QEMU_IMG
 static void raw_aio_cb(void *opaque)
 {
     RawAIOCB *acb = opaque;
@@ -996,7 +1078,7 @@ static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
     acb->ov.OffsetHigh = offset >> 32;
     acb->ov.hEvent = acb->hEvent;
     acb->count = nb_sectors * 512;
-#ifndef QEMU_TOOL
+#ifndef QEMU_IMG
     qemu_add_wait_object(acb->ov.hEvent, raw_aio_cb, acb);
 #endif
     return acb;
@@ -1018,7 +1100,7 @@ static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs,
         qemu_aio_release(acb);
         return NULL;
     }
-#ifdef QEMU_TOOL
+#ifdef QEMU_IMG
     qemu_aio_release(acb);
 #endif
     return (BlockDriverAIOCB *)acb;
@@ -1040,7 +1122,7 @@ static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs,
         qemu_aio_release(acb);
         return NULL;
     }
-#ifdef QEMU_TOOL
+#ifdef QEMU_IMG
     qemu_aio_release(acb);
 #endif
     return (BlockDriverAIOCB *)acb;
@@ -1048,7 +1130,7 @@ static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs,
 
 static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
 {
-#ifndef QEMU_TOOL
+#ifndef QEMU_IMG
     RawAIOCB *acb = (RawAIOCB *)blockacb;
     BlockDriverState *bs = acb->common.bs;
     BDRVRawState *s = bs->opaque;
@@ -1059,10 +1141,12 @@ static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
     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)
@@ -1089,7 +1173,10 @@ static int64_t raw_getlength(BlockDriverState *bs)
 {
     BDRVRawState *s = bs->opaque;
     LARGE_INTEGER l;
-    ULARGE_INTEGER available, total, total_free; 
+    ULARGE_INTEGER available, total, total_free;
+    DISK_GEOMETRY_EX dg;
+    DWORD count;
+    BOOL status;
 
     switch(s->type) {
     case FTYPE_FILE:
@@ -1102,6 +1189,13 @@ static int64_t raw_getlength(BlockDriverState *bs)
             return -EIO;
         l.QuadPart = total.QuadPart;
         break;
+    case FTYPE_HARDDISK:
+        status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
+                                 NULL, 0, &dg, sizeof(dg), &count, NULL);
+        if (status != 0) {
+            l = dg.DiskSize;
+        }
+        break;
     default:
         return -EIO;
     }
@@ -1116,7 +1210,7 @@ static int raw_create(const char *filename, int64_t total_size,
     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;
@@ -1134,13 +1228,17 @@ void qemu_aio_poll(void)
 {
 }
 
+void qemu_aio_flush(void)
+{
+}
+
 void qemu_aio_wait_start(void)
 {
 }
 
 void qemu_aio_wait(void)
 {
-#ifndef QEMU_TOOL
+#ifndef QEMU_IMG
     qemu_bh_poll();
 #endif
 }
@@ -1159,7 +1257,7 @@ BlockDriver bdrv_raw = {
     raw_close,
     raw_create,
     raw_flush,
-    
+
 #if 0
     .bdrv_aio_read = raw_aio_read,
     .bdrv_aio_write = raw_aio_write,
@@ -1204,6 +1302,8 @@ static int find_device_type(BlockDriverState *bs, const char *filename)
 
     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)
@@ -1244,22 +1344,27 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
     }
     create_flags = OPEN_EXISTING;
 
-#ifdef QEMU_TOOL
-    overlapped = 0;
+#ifdef QEMU_IMG
+    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)
 {
@@ -1278,10 +1383,10 @@ static int raw_eject(BlockDriverState *bs, int eject_flag)
     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);
     }
 }
@@ -1302,7 +1407,7 @@ BlockDriver bdrv_host_device = {
     raw_close,
     NULL,
     raw_flush,
-    
+
 #if 0
     .bdrv_aio_read = raw_aio_read,
     .bdrv_aio_write = raw_aio_write,