From a9c09fcaaecaba9ea7e8628afc9922e40eed9fd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Sat, 7 Nov 2020 12:02:58 +0100 Subject: [PATCH] POSIX: lseek: support SEEK_DATA and SEEK_HOLE constants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit this is queued for issue 8: https://www.austingroupbugs.net/view.php?id=415 this implementation calls the ioctl hook of the filesystem with BSD-like constants FIOSEEKDATA and FIOSEEKHOLE. if the hook doesn't know the constants, we use the stat size to return the last hole (as proposed in the draft spec). Change-Id: I5d052eed87e29b70491a7ff534e244896469d03e Reviewed-on: https://review.haiku-os.org/c/haiku/+/3385 Reviewed-by: Jérôme Duval --- headers/posix/sys/ioctl.h | 3 +++ headers/posix/unistd.h | 6 ++++++ src/system/kernel/fs/vfs.cpp | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/headers/posix/sys/ioctl.h b/headers/posix/sys/ioctl.h index 22c3094cfa..fbf34aabf5 100644 --- a/headers/posix/sys/ioctl.h +++ b/headers/posix/sys/ioctl.h @@ -12,4 +12,7 @@ #define FIONBIO 0xbe000000 #define FIONREAD 0xbe000001 +#define FIOSEEKDATA 0xbe000002 +#define FIOSEEKHOLE 0xbe000003 + #endif /* _SYS_IOCTL_H */ diff --git a/headers/posix/unistd.h b/headers/posix/unistd.h index 4874da9fc4..94fa05d71a 100644 --- a/headers/posix/unistd.h +++ b/headers/posix/unistd.h @@ -151,6 +151,12 @@ #ifndef SEEK_END # define SEEK_END 2 #endif +#ifndef SEEK_DATA +# define SEEK_DATA 3 +#endif +#ifndef SEEK_HOLE +# define SEEK_HOLE 4 +#endif #ifdef __cplusplus diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index e0a4a1831b..58d5b5e191 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -5858,6 +5859,39 @@ file_seek(struct file_descriptor* descriptor, off_t pos, int seekType) break; } + case SEEK_DATA: + case SEEK_HOLE: + { + status_t status = B_BAD_VALUE; + if (HAS_FS_CALL(vnode, ioctl)) { + offset = pos; + status = FS_CALL(vnode, ioctl, descriptor->cookie, + seekType == SEEK_DATA ? FIOSEEKDATA : FIOSEEKHOLE, + &offset, sizeof(offset)); + if (status == B_OK) { + if (offset > pos) + offset -= pos; + break; + } + } + if (status != B_BAD_VALUE && status != B_DEV_INVALID_IOCTL) + return status; + + // basic implementation with stat() the node + if (!HAS_FS_CALL(vnode, read_stat) || isDevice) + return B_BAD_VALUE; + + struct stat stat; + status = FS_CALL(vnode, read_stat, &stat); + if (status != B_OK) + return status; + + off_t end = stat.st_size; + if (pos >= end) + return ENXIO; + offset = seekType == SEEK_HOLE ? end - pos : 0; + break; + } default: return B_BAD_VALUE; }