These are standard function to interact with a file descriptor without touching its internal file offset.
Signed-off-by: Thomas Weißschuh <[email protected]> --- tools/include/nolibc/arch-sh.h | 18 ++++++++++ tools/include/nolibc/sys.h | 50 ++++++++++++++++++++++++++++ tools/testing/selftests/nolibc/nolibc-test.c | 46 +++++++++++++++++++++++++ 3 files changed, 114 insertions(+) diff --git a/tools/include/nolibc/arch-sh.h b/tools/include/nolibc/arch-sh.h index a32378fd621f..996cfbe1bee3 100644 --- a/tools/include/nolibc/arch-sh.h +++ b/tools/include/nolibc/arch-sh.h @@ -10,6 +10,8 @@ #include "compiler.h" #include "crt.h" +#include <linux/unistd.h> + /* * Syscalls for SuperH: * - registers are 32bit wide @@ -161,4 +163,20 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_prote } #endif /* NOLIBC_NO_RUNTIME */ +static __attribute__((unused)) +ssize_t _sys_pread(int fd, void *buf, size_t count, off_t offset) +{ + return __nolibc_syscall6(__NR_pread64, fd, buf, count, 0, + __NOLIBC_LLARGPART(offset, 0), __NOLIBC_LLARGPART(offset, 1)); +} +#define _sys_pread _sys_pread + +static __attribute__((unused)) +ssize_t _sys_pwrite(int fd, const void *buf, size_t count, off_t offset) +{ + return __nolibc_syscall6(__NR_pwrite64, fd, buf, count, 0, + __NOLIBC_LLARGPART(offset, 0), __NOLIBC_LLARGPART(offset, 1)); +} +#define _sys_pwrite _sys_pwrite + #endif /* _NOLIBC_ARCH_SH_H */ diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index 7f06d27da612..b63fa6c618c5 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -745,6 +745,56 @@ int pivot_root(const char *new, const char *old) } +/* + * ssize_t pread(int fd, void *buf, size_t count, off_t offset); + * ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset); + */ + +#ifndef _sys_pread +static __attribute__((unused)) +ssize_t _sys_pread(int fd, void *buf, size_t count, off_t offset) +{ +#if __NOLIBC_BITS_PER_SYSCALL_ARG == 64 + return __nolibc_syscall4(__NR_pread64, fd, buf, count, offset); +#elif defined(__NOLIBC_PAD_64BIT_SYSCALL_ARGUMENT_PAIR) + return __nolibc_syscall6(__NR_pread64, fd, buf, count, 0, + __NOLIBC_LLARGPART(offset, 0), __NOLIBC_LLARGPART(offset, 1)); +#else + return __nolibc_syscall5(__NR_pread64, fd, buf, count, + __NOLIBC_LLARGPART(offset, 0), __NOLIBC_LLARGPART(offset, 1)); +#endif +} +#endif /* _sys_pread */ + +static __attribute__((unused)) +ssize_t pread(int fd, void *buf, size_t count, off_t offset) +{ + return __sysret(_sys_pread(fd, buf, count, offset)); +} + +#ifndef _sys_pwrite +static __attribute__((unused)) +ssize_t _sys_pwrite(int fd, const void *buf, size_t count, off_t offset) +{ +#if __NOLIBC_BITS_PER_SYSCALL_ARG == 64 + return __nolibc_syscall4(__NR_pwrite64, fd, buf, count, offset); +#elif defined(__NOLIBC_PAD_64BIT_SYSCALL_ARGUMENT_PAIR) + return __nolibc_syscall6(__NR_pwrite64, fd, buf, count, 0, + __NOLIBC_LLARGPART(offset, 0), __NOLIBC_LLARGPART(offset, 1)); +#else + return __nolibc_syscall5(__NR_pwrite64, fd, buf, count, + __NOLIBC_LLARGPART(offset, 0), __NOLIBC_LLARGPART(offset, 1)); +#endif +} +#endif /* _sys_pwrite */ + +static __attribute__((unused)) +ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset) +{ + return __sysret(_sys_pwrite(fd, buf, count, offset)); +} + + /* * ssize_t read(int fd, void *buf, size_t count); */ diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index c344675ad0c9..f3d0d27cdbe1 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1369,6 +1369,51 @@ int test_pipe(void) return !!memcmp(buf, msg, len); } +int test_pwrite_pread(void) +{ + const off_t offset = (0x12ULL << 32) | 0x34; + ssize_t ret; + char buf[2]; + int fd, err; + off_t offs; + + fd = open("/tmp", O_TMPFILE | O_RDWR, 0644); + if (fd == -1) + return __LINE__; + + /* Write into the middle of the file. */ + ret = pwrite(fd, "abc", 3, offset); + if (ret != 3) { + err = __LINE__; + goto out; + } + + /* Make sure the file offset points somewhere else before pread(). */ + offs = lseek(fd, 0, SEEK_END); + if (offs != offset + 3) { + err = __LINE__; + goto out; + } + + ret = pread(fd, buf, 2, offset + 1); + if (ret != 2) { + err = __LINE__; + goto out; + } + + if (buf[0] != 'b' || buf[1] != 'c') { + err = __LINE__; + goto out; + } + + err = 0; + +out: + close(fd); + + return err; +} + int test_rlimit(void) { struct rlimit rlim = { @@ -1746,6 +1791,7 @@ int run_syscall(int min, int max) CASE_TEST(poll_stdout); EXPECT_SYSNE(1, ({ struct pollfd fds = { 1, POLLOUT, 0}; poll(&fds, 1, 0); }), -1); break; CASE_TEST(poll_fault); EXPECT_SYSER(1, poll(NULL, 1, 0), -1, EFAULT); break; CASE_TEST(prctl); EXPECT_SYSER(1, prctl(PR_SET_NAME, (unsigned long)NULL, 0, 0, 0), -1, EFAULT); break; + CASE_TEST(pwrite_pread); EXPECT_SYSZR(has_working_64bit_syscall_arg, test_pwrite_pread()); break; CASE_TEST(read_badf); EXPECT_SYSER(1, read(-1, &tmp, 1), -1, EBADF); break; CASE_TEST(rlimit); EXPECT_SYSZR(1, test_rlimit()); break; CASE_TEST(rmdir_blah); EXPECT_SYSER(1, rmdir("/blah"), -1, ENOENT); break; -- 2.55.0

