]> Git Repo - qemu.git/blobdiff - block/raw-posix.c
block-raw: Allow pread beyond the end of growable images
[qemu.git] / block / raw-posix.c
index ae2f70f01d032686eb1b9f24094439b743008170..8b1e67c0634176a073e8e17916184c4cec4ff835 100644 (file)
@@ -117,15 +117,14 @@ typedef struct BDRVRawState {
 static int posix_aio_init(void);
 
 static int fd_open(BlockDriverState *bs);
+static int64_t raw_getlength(BlockDriverState *bs);
 
 #if defined(__FreeBSD__)
-static int cd_open(BlockDriverState *bs);
+static int cdrom_reopen(BlockDriverState *bs);
 #endif
 
-static int raw_is_inserted(BlockDriverState *bs);
-
 static int raw_open_common(BlockDriverState *bs, const char *filename,
-        int flags)
+                           int bdrv_flags, int open_flags)
 {
     BDRVRawState *s = bs->opaque;
     int fd, ret;
@@ -134,8 +133,9 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
 
     s->lseek_err_cnt = 0;
 
-    s->open_flags |= O_BINARY;
-    if ((flags & BDRV_O_ACCESS) == O_RDWR) {
+    s->open_flags = open_flags | O_BINARY;
+    s->open_flags &= ~O_ACCMODE;
+    if ((bdrv_flags & BDRV_O_ACCESS) == BDRV_O_RDWR) {
         s->open_flags |= O_RDWR;
     } else {
         s->open_flags |= O_RDONLY;
@@ -144,9 +144,9 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
 
     /* Use O_DSYNC for write-through caching, no flags for write-back caching,
      * and O_DIRECT for no caching. */
-    if ((flags & BDRV_O_NOCACHE))
+    if ((bdrv_flags & BDRV_O_NOCACHE))
         s->open_flags |= O_DIRECT;
-    else if (!(flags & BDRV_O_CACHE_WB))
+    else if (!(bdrv_flags & BDRV_O_CACHE_WB))
         s->open_flags |= O_DSYNC;
 
     s->fd = -1;
@@ -159,7 +159,7 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
     }
     s->fd = fd;
     s->aligned_buf = NULL;
-    if ((flags & BDRV_O_NOCACHE)) {
+    if ((bdrv_flags & BDRV_O_NOCACHE)) {
         s->aligned_buf = qemu_blockalign(bs, ALIGNED_BUFFER_SIZE);
         if (s->aligned_buf == NULL) {
             ret = -errno;
@@ -173,12 +173,13 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
 static int raw_open(BlockDriverState *bs, const char *filename, int flags)
 {
     BDRVRawState *s = bs->opaque;
+    int open_flags = 0;
 
     s->type = FTYPE_FILE;
     if (flags & BDRV_O_CREAT)
-        s->open_flags |= O_CREAT | O_TRUNC;
+        open_flags = O_CREAT | O_TRUNC;
 
-    return raw_open_common(bs, filename, flags);
+    return raw_open_common(bs, filename, flags, open_flags);
 }
 
 /* XXX: use host sector size if necessary with:
@@ -231,6 +232,16 @@ static int raw_pread_aligned(BlockDriverState *bs, int64_t offset,
     if (ret == count)
         goto label__raw_read__success;
 
+    /* Allow reads beyond the end (needed for pwrite) */
+    if ((ret == 0) && bs->growable) {
+        int64_t size = raw_getlength(bs);
+        if (offset >= size) {
+            memset(buf, 0, count);
+            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,
@@ -808,7 +819,7 @@ again:
             if (size == 2048LL * (unsigned)-1)
                 size = 0;
             /* XXX no disc?  maybe we need to reopen... */
-            if (size <= 0 && !reopened && cd_open(bs) >= 0) {
+            if (size <= 0 && !reopened && cdrom_reopen(bs) >= 0) {
                 reopened = 1;
                 goto again;
             }
@@ -892,6 +903,7 @@ static BlockDriver bdrv_raw = {
     .bdrv_getlength = raw_getlength,
 
     .create_options = raw_create_options,
+    .protocol_name = "file",
 };
 
 /***********************************************/
@@ -955,10 +967,25 @@ kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex ma
 
 #endif
 
+static int hdev_probe_device(const char *filename)
+{
+    struct stat st;
+
+    /* allow a dedicated CD-ROM driver to match with a higher priority */
+    if (strstart(filename, "/dev/cdrom", NULL))
+        return 50;
+
+    if (stat(filename, &st) >= 0 &&
+            (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))) {
+        return 100;
+    }
+
+    return 0;
+}
+
 static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
 {
     BDRVRawState *s = bs->opaque;
-    int ret;
 
 #ifdef CONFIG_COCOA
     if (strstart(filename, "/dev/cdrom", NULL)) {
@@ -988,46 +1015,13 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
 #endif
 
     s->type = FTYPE_FILE;
-#if defined(__linux__)
-    if (strstart(filename, "/dev/cd", NULL)) {
-        /* open will not fail even if no CD is inserted */
-        s->open_flags |= O_NONBLOCK;
-        s->type = FTYPE_CD;
-    } else if (strstart(filename, "/dev/fd", NULL)) {
-        s->type = FTYPE_FD;
-        /* open will not fail even if no floppy is inserted */
-        s->open_flags |= O_NONBLOCK;
-#ifdef CONFIG_AIO
-    } else if (strstart(filename, "/dev/sg", NULL)) {
+#if defined(__linux__) && defined(CONFIG_AIO)
+    if (strstart(filename, "/dev/sg", NULL)) {
         bs->sg = 1;
-#endif
-    }
-#endif
-#if defined(__FreeBSD__)
-    if (strstart(filename, "/dev/cd", NULL) ||
-        strstart(filename, "/dev/acd", NULL)) {
-        s->type = FTYPE_CD;
     }
 #endif
 
-    ret = raw_open_common(bs, filename, flags);
-    if (ret)
-        return ret;
-
-#if defined(__FreeBSD__)
-    /* make sure the door isnt locked at this time */
-    if (s->type == FTYPE_CD)
-        ioctl (s->fd, CDIOCALLOW);
-#endif
-#if defined(__linux__)
-    /* close fd so that we can reopen it as needed */
-    if (s->type == FTYPE_FD) {
-        close(s->fd);
-        s->fd = -1;
-        s->fd_media_changed = 1;
-    }
-#endif
-    return 0;
+    return raw_open_common(bs, filename, flags, 0);
 }
 
 #if defined(__linux__)
@@ -1080,106 +1074,7 @@ static int fd_open(BlockDriverState *bs)
     return 0;
 }
 
-static int raw_is_inserted(BlockDriverState *bs)
-{
-    BDRVRawState *s = bs->opaque;
-    int ret;
-
-    switch(s->type) {
-    case FTYPE_CD:
-        ret = ioctl(s->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
-        if (ret == CDS_DISC_OK)
-            return 1;
-        else
-            return 0;
-        break;
-    case FTYPE_FD:
-        ret = fd_open(bs);
-        return (ret >= 0);
-    default:
-        return 1;
-    }
-}
-
-/* currently only used by fdc.c, but a CD version would be good too */
-static int raw_media_changed(BlockDriverState *bs)
-{
-    BDRVRawState *s = bs->opaque;
-
-    switch(s->type) {
-    case FTYPE_FD:
-        {
-            int ret;
-            /* XXX: we do not have a true media changed indication. It
-               does not work if the floppy is changed without trying
-               to read it */
-            fd_open(bs);
-            ret = s->fd_media_changed;
-            s->fd_media_changed = 0;
-#ifdef DEBUG_FLOPPY
-            printf("Floppy changed=%d\n", ret);
-#endif
-            return ret;
-        }
-    default:
-        return -ENOTSUP;
-    }
-}
-
-static int raw_eject(BlockDriverState *bs, int eject_flag)
-{
-    BDRVRawState *s = bs->opaque;
-
-    switch(s->type) {
-    case FTYPE_CD:
-        if (eject_flag) {
-            if (ioctl (s->fd, CDROMEJECT, NULL) < 0)
-                perror("CDROMEJECT");
-        } else {
-            if (ioctl (s->fd, CDROMCLOSETRAY, NULL) < 0)
-                perror("CDROMEJECT");
-        }
-        break;
-    case FTYPE_FD:
-        {
-            int fd;
-            if (s->fd >= 0) {
-                close(s->fd);
-                s->fd = -1;
-            }
-            fd = open(bs->filename, s->open_flags | O_NONBLOCK);
-            if (fd >= 0) {
-                if (ioctl(fd, FDEJECT, 0) < 0)
-                    perror("FDEJECT");
-                close(fd);
-            }
-        }
-        break;
-    default:
-        return -ENOTSUP;
-    }
-    return 0;
-}
-
-static int raw_set_locked(BlockDriverState *bs, int locked)
-{
-    BDRVRawState *s = bs->opaque;
-
-    switch(s->type) {
-    case FTYPE_CD:
-        if (ioctl (s->fd, CDROM_LOCKDOOR, locked) < 0) {
-            /* Note: an error can happen if the distribution automatically
-               mounts the CD-ROM */
-            //        perror("CDROM_LOCKDOOR");
-        }
-        break;
-    default:
-        return -ENOTSUP;
-    }
-    return 0;
-}
-
-static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
+static int hdev_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
 {
     BDRVRawState *s = bs->opaque;
 
@@ -1187,7 +1082,7 @@ static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
 }
 
 #ifdef CONFIG_AIO
-static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs,
+static BlockDriverAIOCB *hdev_aio_ioctl(BlockDriverState *bs,
         unsigned long int req, void *buf,
         BlockDriverCompletionFunc *cb, void *opaque)
 {
@@ -1220,7 +1115,6 @@ static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs,
 #endif
 
 #elif defined(__FreeBSD__)
-
 static int fd_open(BlockDriverState *bs)
 {
     BDRVRawState *s = bs->opaque;
@@ -1230,207 +1124,390 @@ static int fd_open(BlockDriverState *bs)
         return 0;
     return -EIO;
 }
+#else /* !linux && !FreeBSD */
 
-static int cd_open(BlockDriverState *bs)
+static int fd_open(BlockDriverState *bs)
+{
+    return 0;
+}
+
+#endif /* !linux && !FreeBSD */
+
+static int hdev_create(const char *filename, QEMUOptionParameter *options)
 {
-#if defined(__FreeBSD__)
-    BDRVRawState *s = bs->opaque;
     int fd;
+    int ret = 0;
+    struct stat stat_buf;
+    int64_t total_size = 0;
 
-    switch(s->type) {
-    case FTYPE_CD:
-        /* XXX force reread of possibly changed/newly loaded disc,
-         * FreeBSD seems to not notice sometimes... */
-        if (s->fd >= 0)
-            close (s->fd);
-        fd = open(bs->filename, s->open_flags, 0644);
-        if (fd < 0) {
-            s->fd = -1;
-            return -EIO;
+    /* Read out options */
+    while (options && options->name) {
+        if (!strcmp(options->name, "size")) {
+            total_size = options->value.n / 512;
         }
-        s->fd = fd;
-        /* make sure the door isnt locked at this time */
-        ioctl (s->fd, CDIOCALLOW);
+        options++;
     }
+
+    fd = open(filename, O_WRONLY | O_BINARY);
+    if (fd < 0)
+        return -EIO;
+
+    if (fstat(fd, &stat_buf) < 0)
+        ret = -EIO;
+    else if (!S_ISBLK(stat_buf.st_mode) && !S_ISCHR(stat_buf.st_mode))
+        ret = -EIO;
+    else if (lseek(fd, 0, SEEK_END) < total_size * 512)
+        ret = -ENOSPC;
+
+    close(fd);
+    return ret;
+}
+
+static BlockDriver bdrv_host_device = {
+    .format_name       = "host_device",
+    .instance_size     = sizeof(BDRVRawState),
+    .bdrv_probe_device = hdev_probe_device,
+    .bdrv_open         = hdev_open,
+    .bdrv_close                = raw_close,
+    .bdrv_create        = hdev_create,
+    .bdrv_flush                = raw_flush,
+
+#ifdef CONFIG_AIO
+    .bdrv_aio_readv    = raw_aio_readv,
+    .bdrv_aio_writev   = raw_aio_writev,
 #endif
+
+    .bdrv_read          = raw_read,
+    .bdrv_write         = raw_write,
+    .bdrv_getlength    = raw_getlength,
+
+    /* generic scsi device */
+#ifdef __linux__
+    .bdrv_ioctl         = hdev_ioctl,
+#ifdef CONFIG_AIO
+    .bdrv_aio_ioctl     = hdev_aio_ioctl,
+#endif
+#endif
+};
+
+#ifdef __linux__
+static int floppy_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVRawState *s = bs->opaque;
+    int ret;
+
+    posix_aio_init();
+
+    s->type = FTYPE_FD;
+
+    /* open will not fail even if no floppy is inserted, so add O_NONBLOCK */
+    ret = raw_open_common(bs, filename, flags, O_NONBLOCK);
+    if (ret)
+        return ret;
+
+    /* close fd so that we can reopen it as needed */
+    close(s->fd);
+    s->fd = -1;
+    s->fd_media_changed = 1;
+
     return 0;
 }
 
-static int raw_is_inserted(BlockDriverState *bs)
+static int floppy_probe_device(const char *filename)
 {
-    BDRVRawState *s = bs->opaque;
+    if (strstart(filename, "/dev/fd", NULL))
+        return 100;
+    return 0;
+}
 
-    switch(s->type) {
-    case FTYPE_CD:
-        return (raw_getlength(bs) > 0);
-    case FTYPE_FD:
-        /* XXX handle this */
-        /* FALLTHRU */
-    default:
-        return 1;
-    }
+
+static int floppy_is_inserted(BlockDriverState *bs)
+{
+    return fd_open(bs) >= 0;
 }
 
-static int raw_media_changed(BlockDriverState *bs)
+static int floppy_media_changed(BlockDriverState *bs)
 {
-    return -ENOTSUP;
+    BDRVRawState *s = bs->opaque;
+    int ret;
+
+    /*
+     * XXX: we do not have a true media changed indication.
+     * It does not work if the floppy is changed without trying to read it.
+     */
+    fd_open(bs);
+    ret = s->fd_media_changed;
+    s->fd_media_changed = 0;
+#ifdef DEBUG_FLOPPY
+    printf("Floppy changed=%d\n", ret);
+#endif
+    return ret;
 }
 
-static int raw_eject(BlockDriverState *bs, int eject_flag)
+static int floppy_eject(BlockDriverState *bs, int eject_flag)
 {
     BDRVRawState *s = bs->opaque;
+    int fd;
 
-    switch(s->type) {
-    case FTYPE_CD:
-        if (s->fd < 0)
-            return -ENOTSUP;
-        (void) ioctl (s->fd, CDIOCALLOW);
-        if (eject_flag) {
-            if (ioctl (s->fd, CDIOCEJECT) < 0)
-                perror("CDIOCEJECT");
-        } else {
-            if (ioctl (s->fd, CDIOCCLOSE) < 0)
-                perror("CDIOCCLOSE");
-        }
-        if (cd_open(bs) < 0)
-            return -ENOTSUP;
-        break;
-    case FTYPE_FD:
-        /* XXX handle this */
-        /* FALLTHRU */
-    default:
-        return -ENOTSUP;
+    if (s->fd >= 0) {
+        close(s->fd);
+        s->fd = -1;
+    }
+    fd = open(bs->filename, s->open_flags | O_NONBLOCK);
+    if (fd >= 0) {
+        if (ioctl(fd, FDEJECT, 0) < 0)
+            perror("FDEJECT");
+        close(fd);
     }
+
     return 0;
 }
 
-static int raw_set_locked(BlockDriverState *bs, int locked)
+static BlockDriver bdrv_host_floppy = {
+    .format_name        = "host_floppy",
+    .instance_size      = sizeof(BDRVRawState),
+    .bdrv_probe_device = floppy_probe_device,
+    .bdrv_open          = floppy_open,
+    .bdrv_close         = raw_close,
+    .bdrv_create        = hdev_create,
+    .bdrv_flush         = raw_flush,
+
+#ifdef CONFIG_AIO
+    .bdrv_aio_readv     = raw_aio_readv,
+    .bdrv_aio_writev    = raw_aio_writev,
+#endif
+
+    .bdrv_read          = raw_read,
+    .bdrv_write         = raw_write,
+    .bdrv_getlength    = raw_getlength,
+
+    /* removable device support */
+    .bdrv_is_inserted   = floppy_is_inserted,
+    .bdrv_media_changed = floppy_media_changed,
+    .bdrv_eject         = floppy_eject,
+};
+
+static int cdrom_open(BlockDriverState *bs, const char *filename, int flags)
 {
     BDRVRawState *s = bs->opaque;
 
-    switch(s->type) {
-    case FTYPE_CD:
-        if (s->fd < 0)
-            return -ENOTSUP;
-        if (ioctl (s->fd, (locked ? CDIOCPREVENT : CDIOCALLOW)) < 0) {
-            /* Note: an error can happen if the distribution automatically
-               mounts the CD-ROM */
-            //        perror("CDROM_LOCKDOOR");
-        }
-        break;
-    default:
-        return -ENOTSUP;
-    }
-    return 0;
+    s->type = FTYPE_CD;
+
+    /* open will not fail even if no CD is inserted, so add O_NONBLOCK */
+    return raw_open_common(bs, filename, flags, O_NONBLOCK);
 }
 
-static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
+static int cdrom_probe_device(const char *filename)
 {
-    return -ENOTSUP;
+    if (strstart(filename, "/dev/cd", NULL))
+        return 100;
+    return 0;
 }
-#else /* !linux && !FreeBSD */
 
-static int fd_open(BlockDriverState *bs)
+static int cdrom_is_inserted(BlockDriverState *bs)
 {
+    BDRVRawState *s = bs->opaque;
+    int ret;
+
+    ret = ioctl(s->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
+    if (ret == CDS_DISC_OK)
+        return 1;
     return 0;
 }
 
-static int raw_is_inserted(BlockDriverState *bs)
+static int cdrom_eject(BlockDriverState *bs, int eject_flag)
 {
-    return 1;
+    BDRVRawState *s = bs->opaque;
+
+    if (eject_flag) {
+        if (ioctl(s->fd, CDROMEJECT, NULL) < 0)
+            perror("CDROMEJECT");
+    } else {
+        if (ioctl(s->fd, CDROMCLOSETRAY, NULL) < 0)
+            perror("CDROMEJECT");
+    }
+
+    return 0;
 }
 
-static int raw_media_changed(BlockDriverState *bs)
+static int cdrom_set_locked(BlockDriverState *bs, int locked)
 {
-    return -ENOTSUP;
+    BDRVRawState *s = bs->opaque;
+
+    if (ioctl(s->fd, CDROM_LOCKDOOR, locked) < 0) {
+        /*
+         * Note: an error can happen if the distribution automatically
+         * mounts the CD-ROM
+         */
+        /* perror("CDROM_LOCKDOOR"); */
+    }
+
+    return 0;
 }
 
-static int raw_eject(BlockDriverState *bs, int eject_flag)
+static BlockDriver bdrv_host_cdrom = {
+    .format_name        = "host_cdrom",
+    .instance_size      = sizeof(BDRVRawState),
+    .bdrv_probe_device = cdrom_probe_device,
+    .bdrv_open          = cdrom_open,
+    .bdrv_close         = raw_close,
+    .bdrv_create        = hdev_create,
+    .bdrv_flush         = raw_flush,
+
+#ifdef CONFIG_AIO
+    .bdrv_aio_readv     = raw_aio_readv,
+    .bdrv_aio_writev    = raw_aio_writev,
+#endif
+
+    .bdrv_read          = raw_read,
+    .bdrv_write         = raw_write,
+    .bdrv_getlength     = raw_getlength,
+
+    /* removable device support */
+    .bdrv_is_inserted   = cdrom_is_inserted,
+    .bdrv_eject         = cdrom_eject,
+    .bdrv_set_locked    = cdrom_set_locked,
+
+    /* generic scsi device */
+    .bdrv_ioctl         = hdev_ioctl,
+#ifdef CONFIG_AIO
+    .bdrv_aio_ioctl     = hdev_aio_ioctl,
+#endif
+};
+#endif /* __linux__ */
+
+#ifdef __FreeBSD__
+static int cdrom_open(BlockDriverState *bs, const char *filename, int flags)
 {
-    return -ENOTSUP;
+    BDRVRawState *s = bs->opaque;
+    int ret;
+
+    s->type = FTYPE_CD;
+
+    ret = raw_open_common(bs, filename, flags, 0);
+    if (ret)
+        return ret;
+
+    /* make sure the door isnt locked at this time */
+    ioctl(s->fd, CDIOCALLOW);
+    return 0;
 }
 
-static int raw_set_locked(BlockDriverState *bs, int locked)
+static int cdrom_probe_device(const char *filename)
 {
-    return -ENOTSUP;
+    if (strstart(filename, "/dev/cd", NULL) ||
+            strstart(filename, "/dev/acd", NULL))
+        return 100;
+    return 0;
 }
 
-static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
+static int cdrom_reopen(BlockDriverState *bs)
 {
-    return -ENOTSUP;
+    BDRVRawState *s = bs->opaque;
+    int fd;
+
+    /*
+     * Force reread of possibly changed/newly loaded disc,
+     * FreeBSD seems to not notice sometimes...
+     */
+    if (s->fd >= 0)
+        close(s->fd);
+    fd = open(bs->filename, s->open_flags, 0644);
+    if (fd < 0) {
+        s->fd = -1;
+        return -EIO;
+    }
+    s->fd = fd;
+
+    /* make sure the door isnt locked at this time */
+    ioctl(s->fd, CDIOCALLOW);
+    return 0;
 }
 
-static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs,
-        unsigned long int req, void *buf,
-        BlockDriverCompletionFunc *cb, void *opaque)
+static int cdrom_is_inserted(BlockDriverState *bs)
 {
-    return NULL;
+    return raw_getlength(bs) > 0;
 }
-#endif /* !linux && !FreeBSD */
 
-static int hdev_create(const char *filename, QEMUOptionParameter *options)
+static int cdrom_eject(BlockDriverState *bs, int eject_flag)
 {
-    int fd;
-    int ret = 0;
-    struct stat stat_buf;
-    int64_t total_size = 0;
+    BDRVRawState *s = bs->opaque;
 
-    /* Read out options */
-    while (options && options->name) {
-        if (!strcmp(options->name, "size")) {
-            total_size = options->value.n / 512;
-        }
-        options++;
+    if (s->fd < 0)
+        return -ENOTSUP;
+
+    (void) ioctl(s->fd, CDIOCALLOW);
+
+    if (eject_flag) {
+        if (ioctl(s->fd, CDIOCEJECT) < 0)
+            perror("CDIOCEJECT");
+    } else {
+        if (ioctl(s->fd, CDIOCCLOSE) < 0)
+            perror("CDIOCCLOSE");
     }
 
-    fd = open(filename, O_WRONLY | O_BINARY);
-    if (fd < 0)
-        return -EIO;
+    if (cdrom_reopen(bs) < 0)
+        return -ENOTSUP;
+    return 0;
+}
 
-    if (fstat(fd, &stat_buf) < 0)
-        ret = -EIO;
-    else if (!S_ISBLK(stat_buf.st_mode) && !S_ISCHR(stat_buf.st_mode))
-        ret = -EIO;
-    else if (lseek(fd, 0, SEEK_END) < total_size * 512)
-        ret = -ENOSPC;
+static int cdrom_set_locked(BlockDriverState *bs, int locked)
+{
+    BDRVRawState *s = bs->opaque;
 
-    close(fd);
-    return ret;
+    if (s->fd < 0)
+        return -ENOTSUP;
+    if (ioctl(s->fd, (locked ? CDIOCPREVENT : CDIOCALLOW)) < 0) {
+        /*
+         * Note: an error can happen if the distribution automatically
+         * mounts the CD-ROM
+         */
+        /* perror("CDROM_LOCKDOOR"); */
+    }
+
+    return 0;
 }
 
-static BlockDriver bdrv_host_device = {
-    .format_name       = "host_device",
-    .instance_size     = sizeof(BDRVRawState),
-    .bdrv_open         = hdev_open,
-    .bdrv_close                = raw_close,
+static BlockDriver bdrv_host_cdrom = {
+    .format_name        = "host_cdrom",
+    .instance_size      = sizeof(BDRVRawState),
+    .bdrv_probe_device = cdrom_probe_device,
+    .bdrv_open          = cdrom_open,
+    .bdrv_close         = raw_close,
     .bdrv_create        = hdev_create,
-    .bdrv_flush                = raw_flush,
+    .bdrv_flush         = raw_flush,
 
 #ifdef CONFIG_AIO
-    .bdrv_aio_readv    = raw_aio_readv,
-    .bdrv_aio_writev   = raw_aio_writev,
+    .bdrv_aio_readv     = raw_aio_readv,
+    .bdrv_aio_writev    = raw_aio_writev,
 #endif
 
     .bdrv_read          = raw_read,
     .bdrv_write         = raw_write,
-    .bdrv_getlength    = raw_getlength,
+    .bdrv_getlength     = raw_getlength,
 
     /* removable device support */
-    .bdrv_is_inserted  = raw_is_inserted,
-    .bdrv_media_changed        = raw_media_changed,
-    .bdrv_eject                = raw_eject,
-    .bdrv_set_locked   = raw_set_locked,
-    /* generic scsi device */
-    .bdrv_ioctl                = raw_ioctl,
-#ifdef CONFIG_AIO
-    .bdrv_aio_ioctl    = raw_aio_ioctl,
-#endif
+    .bdrv_is_inserted   = cdrom_is_inserted,
+    .bdrv_eject         = cdrom_eject,
+    .bdrv_set_locked    = cdrom_set_locked,
 };
+#endif /* __FreeBSD__ */
 
 static void bdrv_raw_init(void)
 {
+    /*
+     * Register all the drivers.  Note that order is important, the driver
+     * registered last will get probed first.
+     */
     bdrv_register(&bdrv_raw);
     bdrv_register(&bdrv_host_device);
+#ifdef __linux__
+    bdrv_register(&bdrv_host_floppy);
+    bdrv_register(&bdrv_host_cdrom);
+#endif
+#ifdef __FreeBSD__
+    bdrv_register(&bdrv_host_cdrom);
+#endif
 }
 
 block_init(bdrv_raw_init);
This page took 0.044106 seconds and 4 git commands to generate.