On macOS, lseek may not always report a trailing hole, in which case
seeking with SEEK_HOLE or SEEK_DATA will fail with ENXIO. Detect this
condition by checking if errno is set to ENXIO even with a valid offset
and return ENOTSUP instead so that it can be correctly handled rather
than the file being considered empty.
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3124
Signed-off-by: Mohamed Akram <mohd.akram@outlook.com>
---
block/file-posix.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/block/file-posix.c b/block/file-posix.c
index 8c738674c..89b3e338c 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -3190,6 +3190,20 @@ static int find_allocation(BlockDriverState *bs, off_t start,
BDRVRawState *s = bs->opaque;
off_t offs;
+ /*
+ * When using SEEK_HOLE on macOS, if errno is ENXIO even if start is not
+ * beyond EOF, then SEEK_HOLE and SEEK_DATA aren't supported for this file.
+ */
+#ifdef __APPLE__
+ offs = lseek(s->fd, start, SEEK_HOLE);
+ if (offs < 0) {
+ if (errno == ENXIO && start < bs->total_sectors * BDRV_SECTOR_SIZE) {
+ return -ENOTSUP;
+ }
+ return -errno;
+ }
+#endif
+
/*
* SEEK_DATA cases:
* D1. offs == start: start is in data
--
2.51.0