Kernel+LibC+Tests: Implement pwritev(2)
While this isn't really POSIX, it's needed by the Zig port and was simple enough to implement.
This commit is contained in:
parent
70337f3a4b
commit
9b425b860c
Notes:
sideshowbarker
2024-07-17 03:23:36 +09:00
Author: https://github.com/sin-ack Commit: https://github.com/SerenityOS/serenity/commit/9b425b860c Pull-request: https://github.com/SerenityOS/serenity/pull/15428 Reviewed-by: https://github.com/ADKaster ✅ Reviewed-by: https://github.com/AtkinsSJ Reviewed-by: https://github.com/BertalanD Reviewed-by: https://github.com/linusg Reviewed-by: https://github.com/timschumi
6 changed files with 28 additions and 12 deletions
|
@ -195,7 +195,7 @@ enum class NeedsBigProcessLock {
|
|||
S(utimensat, NeedsBigProcessLock::No) \
|
||||
S(waitid, NeedsBigProcessLock::Yes) \
|
||||
S(write, NeedsBigProcessLock::Yes) \
|
||||
S(writev, NeedsBigProcessLock::Yes) \
|
||||
S(pwritev, NeedsBigProcessLock::Yes) \
|
||||
S(yield, NeedsBigProcessLock::No)
|
||||
|
||||
namespace Syscall {
|
||||
|
|
|
@ -317,7 +317,7 @@ public:
|
|||
ErrorOr<FlatPtr> sys$pread(int fd, Userspace<u8*>, size_t, Userspace<off_t const*>);
|
||||
ErrorOr<FlatPtr> sys$readv(int fd, Userspace<const struct iovec*> iov, int iov_count);
|
||||
ErrorOr<FlatPtr> sys$write(int fd, Userspace<u8 const*>, size_t);
|
||||
ErrorOr<FlatPtr> sys$writev(int fd, Userspace<const struct iovec*> iov, int iov_count);
|
||||
ErrorOr<FlatPtr> sys$pwritev(int fd, Userspace<const struct iovec*> iov, int iov_count, Userspace<off_t const*>);
|
||||
ErrorOr<FlatPtr> sys$fstat(int fd, Userspace<stat*>);
|
||||
ErrorOr<FlatPtr> sys$stat(Userspace<Syscall::SC_stat_params const*>);
|
||||
ErrorOr<FlatPtr> sys$lseek(int fd, Userspace<off_t*>, int whence);
|
||||
|
@ -602,7 +602,7 @@ private:
|
|||
void delete_perf_events_buffer();
|
||||
|
||||
ErrorOr<void> do_exec(NonnullLockRefPtr<OpenFileDescription> main_program_description, NonnullOwnPtrVector<KString> arguments, NonnullOwnPtrVector<KString> environment, LockRefPtr<OpenFileDescription> interpreter_description, Thread*& new_main_thread, u32& prev_flags, const ElfW(Ehdr) & main_program_header);
|
||||
ErrorOr<FlatPtr> do_write(OpenFileDescription&, UserOrKernelBuffer const&, size_t);
|
||||
ErrorOr<FlatPtr> do_write(OpenFileDescription&, UserOrKernelBuffer const&, size_t, Optional<off_t> = {});
|
||||
|
||||
ErrorOr<FlatPtr> do_statvfs(FileSystem const& path, Custody const*, statvfs* buf);
|
||||
|
||||
|
|
|
@ -11,7 +11,9 @@
|
|||
|
||||
namespace Kernel {
|
||||
|
||||
ErrorOr<FlatPtr> Process::sys$writev(int fd, Userspace<const struct iovec*> iov, int iov_count)
|
||||
// NOTE: The offset is passed by pointer because off_t is 64bit,
|
||||
// hence it can't be passed by register on 32bit platforms.
|
||||
ErrorOr<FlatPtr> Process::sys$pwritev(int fd, Userspace<const struct iovec*> iov, int iov_count, Userspace<off_t const*> userspace_offset)
|
||||
{
|
||||
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
|
||||
TRY(require_promise(Pledge::stdio));
|
||||
|
@ -31,26 +33,32 @@ ErrorOr<FlatPtr> Process::sys$writev(int fd, Userspace<const struct iovec*> iov,
|
|||
return EINVAL;
|
||||
}
|
||||
|
||||
// NOTE: Negative offset means "operate like writev" which seeks the file.
|
||||
auto base_offset = TRY(copy_typed_from_user(userspace_offset));
|
||||
auto description = TRY(open_file_description(fd));
|
||||
if (!description->is_writable())
|
||||
return EBADF;
|
||||
if (base_offset >= 0 && !description->file().is_seekable())
|
||||
return EINVAL;
|
||||
|
||||
int nwritten = 0;
|
||||
off_t current_offset = base_offset;
|
||||
for (auto& vec : vecs) {
|
||||
auto buffer = TRY(UserOrKernelBuffer::for_user_buffer((u8*)vec.iov_base, vec.iov_len));
|
||||
auto result = do_write(*description, buffer, vec.iov_len);
|
||||
auto result = do_write(*description, buffer, vec.iov_len, base_offset >= 0 ? current_offset : Optional<off_t> {});
|
||||
if (result.is_error()) {
|
||||
if (nwritten == 0)
|
||||
return result.release_error();
|
||||
return nwritten;
|
||||
}
|
||||
nwritten += result.value();
|
||||
current_offset += result.value();
|
||||
}
|
||||
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
ErrorOr<FlatPtr> Process::do_write(OpenFileDescription& description, UserOrKernelBuffer const& data, size_t data_size)
|
||||
ErrorOr<FlatPtr> Process::do_write(OpenFileDescription& description, UserOrKernelBuffer const& data, size_t data_size, Optional<off_t> offset)
|
||||
{
|
||||
size_t total_nwritten = 0;
|
||||
|
||||
|
@ -72,7 +80,9 @@ ErrorOr<FlatPtr> Process::do_write(OpenFileDescription& description, UserOrKerne
|
|||
}
|
||||
// TODO: handle exceptions in unblock_flags
|
||||
}
|
||||
auto nwritten_or_error = description.write(data.offset(total_nwritten), data_size - total_nwritten);
|
||||
auto nwritten_or_error = offset.has_value()
|
||||
? description.write(offset.value() + total_nwritten, data.offset(total_nwritten), data_size - total_nwritten)
|
||||
: description.write(data.offset(total_nwritten), data_size - total_nwritten);
|
||||
if (nwritten_or_error.is_error()) {
|
||||
if (total_nwritten > 0)
|
||||
return total_nwritten;
|
||||
|
|
|
@ -44,7 +44,7 @@ static bool is_bad_idea(int fn, size_t const* direct_sc_args, size_t const* fake
|
|||
// FIXME: Known bug: https://github.com/SerenityOS/serenity/issues/5328
|
||||
return direct_sc_args[0] == 1;
|
||||
case SC_write:
|
||||
case SC_writev:
|
||||
case SC_pwritev:
|
||||
// FIXME: Known bug: https://github.com/SerenityOS/serenity/issues/5328
|
||||
return direct_sc_args[0] == 0;
|
||||
case SC_pledge:
|
||||
|
|
|
@ -13,10 +13,7 @@ extern "C" {
|
|||
|
||||
ssize_t writev(int fd, const struct iovec* iov, int iov_count)
|
||||
{
|
||||
__pthread_maybe_cancel();
|
||||
|
||||
int rc = syscall(SC_writev, fd, iov, iov_count);
|
||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
return pwritev(fd, iov, iov_count, -1);
|
||||
}
|
||||
|
||||
ssize_t readv(int fd, const struct iovec* iov, int iov_count)
|
||||
|
@ -26,4 +23,12 @@ ssize_t readv(int fd, const struct iovec* iov, int iov_count)
|
|||
int rc = syscall(SC_readv, fd, iov, iov_count);
|
||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
||||
ssize_t pwritev(int fd, struct iovec const* iov, int iov_count, off_t offset)
|
||||
{
|
||||
__pthread_maybe_cancel();
|
||||
|
||||
int rc = syscall(SC_pwritev, fd, iov, iov_count, &offset);
|
||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,5 +13,6 @@ __BEGIN_DECLS
|
|||
|
||||
ssize_t writev(int fd, const struct iovec*, int iov_count);
|
||||
ssize_t readv(int fd, const struct iovec*, int iov_count);
|
||||
ssize_t pwritev(int fd, const struct iovec*, int iov_count, off_t);
|
||||
|
||||
__END_DECLS
|
||||
|
|
Loading…
Add table
Reference in a new issue