lseek can not work for all block devices as the man page says:
| Some devices are incapable of seeking and POSIX does not specify
| which devices must support lseek().

This patch tries to add the support on Linux by using BLKGETSIZE64
ioctl

Signed-off-by: Xiao Guangrong <guangrong.x...@linux.intel.com>
---
 util/osdep.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/util/osdep.c b/util/osdep.c
index 5a61e19..b20c793 100644
--- a/util/osdep.c
+++ b/util/osdep.c
@@ -45,6 +45,11 @@
 extern int madvise(caddr_t, size_t, int);
 #endif
 
+#ifdef CONFIG_LINUX
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#endif
+
 #include "qemu-common.h"
 #include "qemu/sockets.h"
 #include "qemu/error-report.h"
@@ -433,6 +438,21 @@ int64_t qemu_fd_getlength(int fd)
 {
     int64_t size;
 
+#ifdef CONFIG_LINUX
+    struct stat stat_buf;
+    if (fstat(fd, &stat_buf) < 0) {
+        return -errno;
+    }
+
+    if ((S_ISBLK(stat_buf.st_mode)) && !ioctl(fd, BLKGETSIZE64, &size)) {
+        /* The size of block device is larger than max int64_t? */
+        if (size < 0) {
+            return -EOVERFLOW;
+        }
+        return size;
+    }
+#endif
+
     size = lseek(fd, 0, SEEK_END);
     if (size < 0) {
         return -errno;
-- 
1.8.3.1


Reply via email to