summaryrefslogtreecommitdiff
path: root/tools/testing
diff options
context:
space:
mode:
authorThomas Weißschuh <linux@weissschuh.net>2026-05-21 19:31:04 +0200
committerThomas Weißschuh <linux@weissschuh.net>2026-05-24 23:58:04 +0200
commit835fa43a4d36bd66ad0dd052f9fa15f7bd365fa8 (patch)
tree3e0c781168f0d563a73487d5fa1206cbea11e5a2 /tools/testing
parentacbbec15195b40adefd24993661c93022f6de2b7 (diff)
tools/nolibc: add ftruncate()
On architectures with 32-bit longs, call the compat syscall __NR_ftruncate64. As off_t is 64-bit it must be split into 2 registers. Unlike llseek() which passes the high and low parts in explicitly named arguments, the order here is endian independent. Some architectures (arm, mips, ppc) require this pair of registers to be aligned to an even register, so add custom _sys_ftruncate64() wrappers for those. A test case for ftruncate is added which validates negative length or invalid fd return the appropriate error, and checks the length is correct on success. Co-developed-by: Jordan Richards <jordanrichards@google.com> Signed-off-by: Jordan Richards <jordanrichards@google.com> Signed-off-by: Thomas Weißschuh <linux@weissschuh.net> Acked-by: Willy Tarreau <w@1wt.eu> Reviewed-by: Daniel Palmer <daniel@thingy.jp> Link: https://patch.msgid.link/20260521-nolibc-ftruncate-v1-3-5384a83b2402@weissschuh.net
Diffstat (limited to 'tools/testing')
-rw-r--r--tools/testing/selftests/nolibc/nolibc-test.c52
1 files changed, 52 insertions, 0 deletions
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
index c3867cc570c6..7c3b711c125c 100644
--- a/tools/testing/selftests/nolibc/nolibc-test.c
+++ b/tools/testing/selftests/nolibc/nolibc-test.c
@@ -1017,6 +1017,57 @@ int test_fork(enum fork_type type)
}
}
+int test_ftruncate(void)
+{
+ struct stat stat_buf;
+ int ret, fd;
+
+ ret = ftruncate(-1, 0);
+ if (ret != -1 || errno != EBADF) {
+ errno = EINVAL;
+ return __LINE__;
+ }
+
+ fd = memfd_create(__func__, 0);
+ if (fd == -1)
+ return __LINE__;
+
+ /*
+ * This also tests that the high 32-bit half is passed through correctly.
+ * If it gets lost, the kernel will see a positive number and not fail.
+ */
+ ret = ftruncate(fd, -1);
+ if (!(ret == -1 && errno == EINVAL)) {
+ if (ret == 0)
+ errno = EINVAL;
+ ret = __LINE__;
+ goto end;
+ }
+
+ ret = ftruncate(fd, 42);
+ if (ret != 0) {
+ ret = __LINE__;
+ goto end;
+ }
+
+ ret = fstat(fd, &stat_buf);
+ if (ret != 0) {
+ ret = __LINE__;
+ goto end;
+ }
+
+ if (stat_buf.st_size != 42) {
+ errno = EINVAL;
+ ret = __LINE__;
+ goto end;
+ }
+
+end:
+ close(fd);
+
+ return ret;
+}
+
int test_stat_timestamps(void)
{
struct stat st;
@@ -1539,6 +1590,7 @@ int run_syscall(int min, int max)
CASE_TEST(file_stream); EXPECT_SYSZR(1, test_file_stream()); break;
CASE_TEST(file_stream_wsr); EXPECT_SYSZR(1, test_file_stream_wsr()); break;
CASE_TEST(fork); EXPECT_SYSZR(1, test_fork(FORK_STANDARD)); break;
+ CASE_TEST(ftruncate); EXPECT_SYSZR(1, test_ftruncate()); break;
CASE_TEST(getdents64_root); EXPECT_SYSNE(1, test_getdents64("/"), -1); break;
CASE_TEST(getdents64_null); EXPECT_SYSER(1, test_getdents64("/dev/null"), -1, ENOTDIR); break;
CASE_TEST(directories); EXPECT_SYSZR(is_nolibc && proc, test_dirent()); break;