diff --git a/libc/Makefile b/libc/Makefile
index 207d662b..ff9e2702 100644
--- a/libc/Makefile
+++ b/libc/Makefile
@@ -197,6 +197,7 @@ stat.o \
stdio.o \
tfork.o \
time.o \
+truncateat.o \
truncate.o \
umask.o \
unlinkat.o \
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index db0e1a58..916a263d 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -176,6 +176,7 @@ ssize_t read(int, void*, size_t);
int rmdir(const char*);
unsigned sleep(unsigned);
int truncate(const char*, off_t);
+int truncateat(int dirfd, const char*, off_t);
#if __POSIX_OBSOLETE <= 200112 || defined(_SORTIX_SOURCE)
int usleep(useconds_t useconds);
#endif
diff --git a/libc/truncateat.cpp b/libc/truncateat.cpp
new file mode 100644
index 00000000..c65b447e
--- /dev/null
+++ b/libc/truncateat.cpp
@@ -0,0 +1,34 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2012.
+
+ This file is part of the Sortix C Library.
+
+ The Sortix C Library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or (at your
+ option) any later version.
+
+ The Sortix C Library is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with the Sortix C Library. If not, see .
+
+ truncateat.cpp
+ Truncates a file to a specific size.
+
+*******************************************************************************/
+
+#include
+#include
+#include
+
+DEFN_SYSCALL3(int, sys_truncateat, SYSCALL_TRUNCATEAT, int, const char*, off_t);
+
+extern "C" int truncateat(int dirfd, const char* pathname, off_t length)
+{
+ return sys_truncateat(dirfd, pathname, length);
+}
diff --git a/sortix/include/sortix/syscallnum.h b/sortix/include/sortix/syscallnum.h
index c3a9d310..7707658a 100644
--- a/sortix/include/sortix/syscallnum.h
+++ b/sortix/include/sortix/syscallnum.h
@@ -86,6 +86,7 @@
#define SYSCALL_FACCESSAT 62
#define SYSCALL_MKDIRAT 63
#define SYSCALL_FCHDIR 64
-#define SYSCALL_MAX_NUM 65 /* index of highest constant + 1 */
+#define SYSCALL_TRUNCATEAT 65
+#define SYSCALL_MAX_NUM 66 /* index of highest constant + 1 */
#endif
diff --git a/sortix/io.cpp b/sortix/io.cpp
index d2b35ebd..d4034e3e 100644
--- a/sortix/io.cpp
+++ b/sortix/io.cpp
@@ -226,14 +226,15 @@ static int sys_rmdir(const char* path)
return sys_unlinkat(AT_FDCWD, path, AT_REMOVEDIR);
}
-static int sys_truncate(const char* path, off_t length)
+static int sys_truncateat(int dirfd, const char* path, off_t length)
{
char* pathcopy = GetStringFromUser(path);
if ( !pathcopy )
return -1;
ioctx_t ctx; SetupUserIOCtx(&ctx);
const char* relpath = pathcopy;
- Ref from = PrepareLookup(&relpath);
+ Ref from = PrepareLookup(&relpath, dirfd);
+ if ( !from ) { delete[] pathcopy; return -1; }
Ref desc = from->open(&ctx, relpath, O_WRONLY);
delete[] pathcopy;
if ( !desc )
@@ -241,6 +242,11 @@ static int sys_truncate(const char* path, off_t length)
return desc->truncate(&ctx, length);
}
+static int sys_truncate(const char* path, off_t length)
+{
+ return sys_truncateat(AT_FDCWD, path, length);
+}
+
static int sys_ftruncate(int fd, off_t length)
{
Ref desc = CurrentProcess()->GetDescriptor(fd);
@@ -475,6 +481,7 @@ void Init()
Syscall::Register(SYSCALL_SETTERMMODE, (void*) sys_settermmode);
Syscall::Register(SYSCALL_STAT, (void*) sys_stat);
Syscall::Register(SYSCALL_TCGETWINSIZE, (void*) sys_tcgetwinsize);
+ Syscall::Register(SYSCALL_TRUNCATEAT, (void*) sys_truncateat);
Syscall::Register(SYSCALL_TRUNCATE, (void*) sys_truncate);
Syscall::Register(SYSCALL_UNLINKAT, (void*) sys_unlinkat);
Syscall::Register(SYSCALL_UNLINK, (void*) sys_unlink);