diff options
author | Hendiadyoin1 <leon.a@serenityos.org> | 2022-06-18 18:37:54 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-07-15 12:42:43 +0200 |
commit | d783389877435ef937b4306ac689470a5ca576bb (patch) | |
tree | 843854df4a14ace514d1f4e803e3e3a582bab5bb | |
parent | ad904cdcab84bc2afe0c648ca126f12a781dbf5f (diff) | |
download | serenity-d783389877435ef937b4306ac689470a5ca576bb.zip |
Kernel+LibC: Add posix_fallocate syscall
-rw-r--r-- | Kernel/API/Syscall.h | 1 | ||||
-rw-r--r-- | Kernel/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Kernel/Process.h | 1 | ||||
-rw-r--r-- | Kernel/Syscalls/fallocate.cpp | 59 | ||||
-rw-r--r-- | Userland/Libraries/LibC/fcntl.cpp | 7 | ||||
-rw-r--r-- | Userland/Libraries/LibC/fcntl.h | 1 |
6 files changed, 70 insertions, 0 deletions
diff --git a/Kernel/API/Syscall.h b/Kernel/API/Syscall.h index 72c89d587e..c973b14883 100644 --- a/Kernel/API/Syscall.h +++ b/Kernel/API/Syscall.h @@ -128,6 +128,7 @@ enum class NeedsBigProcessLock { S(pipe, NeedsBigProcessLock::Yes) \ S(pledge, NeedsBigProcessLock::Yes) \ S(poll, NeedsBigProcessLock::Yes) \ + S(posix_fallocate, NeedsBigProcessLock::No) \ S(prctl, NeedsBigProcessLock::Yes) \ S(profiling_disable, NeedsBigProcessLock::Yes) \ S(profiling_enable, NeedsBigProcessLock::Yes) \ diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index b7efb3d917..ecbeb7db77 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -243,6 +243,7 @@ set(KERNEL_SOURCES Syscalls/emuctl.cpp Syscalls/execve.cpp Syscalls/exit.cpp + Syscalls/fallocate.cpp Syscalls/fcntl.cpp Syscalls/fork.cpp Syscalls/fsync.cpp diff --git a/Kernel/Process.h b/Kernel/Process.h index aae7df23e5..5b64a578b3 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -301,6 +301,7 @@ public: ErrorOr<FlatPtr> sys$stat(Userspace<Syscall::SC_stat_params const*>); ErrorOr<FlatPtr> sys$lseek(int fd, Userspace<off_t*>, int whence); ErrorOr<FlatPtr> sys$ftruncate(int fd, Userspace<off_t const*>); + ErrorOr<FlatPtr> sys$posix_fallocate(int fd, Userspace<off_t const*>, Userspace<off_t const*>); ErrorOr<FlatPtr> sys$kill(pid_t pid_or_pgid, int sig); [[noreturn]] void sys$exit(int status); ErrorOr<FlatPtr> sys$sigreturn(RegisterState& registers); diff --git a/Kernel/Syscalls/fallocate.cpp b/Kernel/Syscalls/fallocate.cpp new file mode 100644 index 0000000000..1a46b54d25 --- /dev/null +++ b/Kernel/Syscalls/fallocate.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2022, Leon Albrecht <leon.a@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <AK/Checked.h> +#include <Kernel/FileSystem/Inode.h> +#include <Kernel/FileSystem/InodeFile.h> +#include <Kernel/FileSystem/OpenFileDescription.h> +#include <Kernel/Process.h> + +namespace Kernel { + +ErrorOr<FlatPtr> Process::sys$posix_fallocate(int fd, Userspace<off_t const*> userspace_offset, Userspace<off_t const*> userspace_length) +{ + VERIFY_NO_PROCESS_BIG_LOCK(this); + TRY(require_promise(Pledge::stdio)); + + auto offset = TRY(copy_typed_from_user(userspace_offset)); + if (offset < 0) + return EINVAL; + auto length = TRY(copy_typed_from_user(userspace_length)); + if (length <= 0) + return EINVAL; + + Checked<size_t> checked_size { length }; + checked_size += offset; + // FIXME: Return EFBIG if offset+length > FileSizeMax + if (checked_size.has_overflow()) + return EFBIG; + + auto description = TRY(open_file_description(fd)); + if (!description->is_writable()) + return EBADF; + + if (description->is_fifo()) + return ESPIPE; + + if (!S_ISREG(TRY(description->file().stat()).st_mode)) + return ENODEV; + + VERIFY(description->file().is_inode()); + + auto& file = static_cast<InodeFile&>(description->file()); + if (file.inode().size() >= checked_size.value()) + return 0; + + // Note: truncate essentially calls resize in the inodes implementation + // while resize is not a standard member of an inode, so we just call + // truncate instead + TRY(file.inode().truncate(checked_size.value())); + + // FIXME: ENOSPC: There is not enough space left on the device containing the file referred to by fd. + // FIXME: EINTR: A signal was caught during execution. + return 0; +} + +} diff --git a/Userland/Libraries/LibC/fcntl.cpp b/Userland/Libraries/LibC/fcntl.cpp index e67a82d357..97fe440606 100644 --- a/Userland/Libraries/LibC/fcntl.cpp +++ b/Userland/Libraries/LibC/fcntl.cpp @@ -104,6 +104,13 @@ int posix_fadvise(int fd, off_t offset, off_t len, int advice) return 0; } +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_fallocate.html +int posix_fallocate(int fd, off_t offset, off_t len) +{ + // posix_fallocate does not set errno. + return static_cast<int>(syscall(SC_posix_fallocate, fd, &offset, &len)); +} + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimensat.html int utimensat(int dirfd, char const* path, struct timespec const times[2], int flag) { diff --git a/Userland/Libraries/LibC/fcntl.h b/Userland/Libraries/LibC/fcntl.h index 3704d6a7a7..bf640c79f5 100644 --- a/Userland/Libraries/LibC/fcntl.h +++ b/Userland/Libraries/LibC/fcntl.h @@ -29,6 +29,7 @@ int inode_watcher_add_watch(int fd, char const* path, size_t path_length, unsign int inode_watcher_remove_watch(int fd, int wd); int posix_fadvise(int fd, off_t offset, off_t len, int advice); +int posix_fallocate(int fd, off_t offset, off_t len); int utimensat(int dirfd, char const* path, struct timespec const times[2], int flag); |