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; }