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


Reply via email to