diff --git a/headers/posix/fcntl.h b/headers/posix/fcntl.h index e16dd1634c..539034ffa9 100644 --- a/headers/posix/fcntl.h +++ b/headers/posix/fcntl.h @@ -99,6 +99,7 @@ extern int openat(int fd, const char *path, int openMode, ...); extern int fcntl(int fd, int op, ...); extern int posix_fadvise(int fd, off_t offset, off_t len, int advice); +extern int posix_fallocate(int fd, off_t offset, off_t len); #ifdef __cplusplus } diff --git a/headers/private/kernel/vfs.h b/headers/private/kernel/vfs.h index b79731ef09..0bbdc82350 100644 --- a/headers/private/kernel/vfs.h +++ b/headers/private/kernel/vfs.h @@ -252,6 +252,7 @@ int _user_dup(int fd); int _user_dup2(int ofd, int nfd); status_t _user_lock_node(int fd); status_t _user_unlock_node(int fd); +status_t _user_preallocate(int fd, off_t offset, off_t length); /* socket user prototypes (implementation in socket.cpp) */ int _user_socket(int family, int type, int protocol); diff --git a/headers/private/system/syscalls.h b/headers/private/system/syscalls.h index c844095b74..125a6e3716 100644 --- a/headers/private/system/syscalls.h +++ b/headers/private/system/syscalls.h @@ -338,6 +338,7 @@ extern status_t _kern_lock_node(int fd); extern status_t _kern_unlock_node(int fd); extern status_t _kern_get_next_fd_info(team_id team, uint32 *_cookie, struct fd_info *info, size_t infoSize); +extern status_t _kern_preallocate(int fd, off_t offset, off_t length); // socket functions extern int _kern_socket(int family, int type, int protocol); diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index f3d8ca2268..e0a4a1831b 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -6438,6 +6438,48 @@ common_unlock_node(int fd, bool kernel) } +static status_t +common_preallocate(int fd, off_t offset, off_t length, bool kernel) +{ + struct file_descriptor* descriptor; + struct vnode* vnode; + + if (offset < 0 || length == 0) + return B_BAD_VALUE; + if (offset > OFF_MAX - length) + return B_FILE_TOO_LARGE; + + descriptor = get_fd_and_vnode(fd, &vnode, kernel); + if (descriptor == NULL || (descriptor->open_mode & O_RWMASK) == O_RDONLY) + return B_FILE_ERROR; + + switch (vnode->Type() & S_IFMT) { + case S_IFIFO: + case S_IFSOCK: + return ESPIPE; + + case S_IFBLK: + case S_IFCHR: + case S_IFDIR: + case S_IFLNK: + return B_DEVICE_NOT_FOUND; + + case S_IFREG: + break; + } + + status_t status = B_OK; + if (HAS_FS_CALL(vnode, preallocate)) { + status = FS_CALL(vnode, preallocate, offset, length); + } else { + status = HAS_FS_CALL(vnode, write) + ? B_UNSUPPORTED : B_READ_ONLY_DEVICE; + } + + return status; +} + + static status_t common_read_link(int fd, char* path, char* buffer, size_t* _bufferSize, bool kernel) @@ -8435,6 +8477,13 @@ _kern_unlock_node(int fd) } +status_t +_kern_preallocate(int fd, off_t offset, off_t length) +{ + return common_preallocate(fd, offset, length, true); +} + + status_t _kern_create_dir_entry_ref(dev_t device, ino_t inode, const char* name, int perms) @@ -9319,6 +9368,13 @@ _user_unlock_node(int fd) } +status_t +_user_preallocate(int fd, off_t offset, off_t length) +{ + return common_preallocate(fd, offset, length, false); +} + + status_t _user_create_dir_entry_ref(dev_t device, ino_t inode, const char* userName, int perms) diff --git a/src/system/libroot/posix/fcntl.cpp b/src/system/libroot/posix/fcntl.cpp index 49f2f1ce9e..ad9874a3f1 100644 --- a/src/system/libroot/posix/fcntl.cpp +++ b/src/system/libroot/posix/fcntl.cpp @@ -95,3 +95,12 @@ posix_fadvise(int fd, off_t offset, off_t len, int advice) return 0; } + +int +posix_fallocate(int fd, off_t offset, off_t len) +{ + if (len == 0 || offset < 0) + return EINVAL; + + return _kern_preallocate(fd, offset, len); +} diff --git a/src/system/libroot/stubbed/libroot_stubs.c b/src/system/libroot/stubbed/libroot_stubs.c index 73d0c7dfd2..1ace035e55 100644 --- a/src/system/libroot/stubbed/libroot_stubs.c +++ b/src/system/libroot/stubbed/libroot_stubs.c @@ -2424,6 +2424,8 @@ void popen() {} void port_buffer_size() {} void port_buffer_size_etc() {} void port_count() {} +void posix_fadvise() {} +void posix_fallocate() {} void posix_madvise() {} void posix_memalign() {} void posix_openpt() {} diff --git a/src/system/libroot/stubbed/libroot_stubs_legacy.c b/src/system/libroot/stubbed/libroot_stubs_legacy.c index 2de2f3aa35..b1ea45746a 100644 --- a/src/system/libroot/stubbed/libroot_stubs_legacy.c +++ b/src/system/libroot/stubbed/libroot_stubs_legacy.c @@ -2354,6 +2354,8 @@ void popen() {} void port_buffer_size() {} void port_buffer_size_etc() {} void port_count() {} +void posix_fadvise() {} +void posix_fallocate() {} void posix_madvise() {} void posix_memalign() {} void posix_openpt() {}