diff --git a/libc/Makefile b/libc/Makefile
index 684fc0f8..0f2dc966 100644
--- a/libc/Makefile
+++ b/libc/Makefile
@@ -212,6 +212,8 @@ putc.o \
raise.o \
rand.o \
readdirents.o \
+readlinkat.o \
+readlink.o \
read.o \
realpath.o \
removeat.o \
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index fc789ae5..8a9d2715 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -111,8 +111,6 @@ int lockf(int, int, off_t);
int nice(int);
long pathconf(const char*, int);
int pause(void);
-ssize_t readlink(const char* restrict, char* restrict, size_t);
-ssize_t readlinkat(int, const char* restrict, char* restrict, size_t);
int setegid(gid_t);
int seteuid(uid_t);
int setgid(gid_t);
@@ -170,6 +168,8 @@ off_t lseek(int, off_t, int);
int pipe(int [2]);
ssize_t pread(int, void*, size_t, off_t);
ssize_t pwrite(int, const void*, size_t, off_t);
+ssize_t readlink(const char* restrict, char* restrict, size_t);
+ssize_t readlinkat(int, const char* restrict, char* restrict, size_t);
ssize_t read(int, void*, size_t);
int rmdir(const char*);
unsigned sleep(unsigned);
diff --git a/libc/readlink.cpp b/libc/readlink.cpp
new file mode 100644
index 00000000..da193b25
--- /dev/null
+++ b/libc/readlink.cpp
@@ -0,0 +1,32 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2013.
+
+ 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 .
+
+ readlink.cpp
+ Read contents of symbolic link.
+
+*******************************************************************************/
+
+#include
+#include
+
+extern "C" ssize_t readlink(const char* restrict path, char* restrict buf,
+ size_t size)
+{
+ return readlinkat(AT_FDCWD, path, buf, size);
+}
diff --git a/libc/readlinkat.cpp b/libc/readlinkat.cpp
new file mode 100644
index 00000000..b7ecdcab
--- /dev/null
+++ b/libc/readlinkat.cpp
@@ -0,0 +1,37 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2013.
+
+ 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 .
+
+ readlinkat.cpp
+ Read contents of symbolic link.
+
+*******************************************************************************/
+
+#include
+
+#include
+#include
+
+DEFN_SYSCALL4(ssize_t, sys_readlinkat, SYSCALL_READLINKAT, int,
+ const char* restrict, char* restrict, size_t);
+
+extern "C" ssize_t readlinkat(int dirfd, const char* restrict path,
+ char* restrict buf, size_t size)
+{
+ return sys_readlinkat(dirfd, path, buf, size);
+}
diff --git a/sortix/descriptor.cpp b/sortix/descriptor.cpp
index f83b5b6a..2c56c51d 100644
--- a/sortix/descriptor.cpp
+++ b/sortix/descriptor.cpp
@@ -420,6 +420,8 @@ int Descriptor::rename_here(ioctx_t* ctx, Ref from,
ssize_t Descriptor::readlink(ioctx_t* ctx, char* buf, size_t bufsize)
{
+ if ( (size_t) SSIZE_MAX < bufsize )
+ bufsize = (size_t) SSIZE_MAX;
return vnode->readlink(ctx, buf, bufsize);
}
diff --git a/sortix/include/sortix/syscallnum.h b/sortix/include/sortix/syscallnum.h
index 67ceee96..3f18848c 100644
--- a/sortix/include/sortix/syscallnum.h
+++ b/sortix/include/sortix/syscallnum.h
@@ -95,6 +95,7 @@
#define SYSCALL_FSM_FSBIND 71
#define SYSCALL_PPOLL 72
#define SYSCALL_RENAMEAT 73
-#define SYSCALL_MAX_NUM 74 /* index of highest constant + 1 */
+#define SYSCALL_READLINKAT 74
+#define SYSCALL_MAX_NUM 75 /* index of highest constant + 1 */
#endif
diff --git a/sortix/io.cpp b/sortix/io.cpp
index b4460700..58f6270d 100644
--- a/sortix/io.cpp
+++ b/sortix/io.cpp
@@ -540,6 +540,25 @@ static int sys_renameat(int olddirfd, const char* oldpath,
return ret;
}
+// TODO: This should probably be moved into user-space. It'd be nice if
+// user-space could just open the symlink and read/write it like a regular file.
+static ssize_t sys_readlinkat(int dirfd, const char* path, char* buf, size_t size)
+{
+ char* pathcopy = GetStringFromUser(path);
+ if ( !pathcopy )
+ return -1;
+ ioctx_t ctx; SetupUserIOCtx(&ctx);
+ const char* relpath = pathcopy;
+ Ref from = PrepareLookup(&relpath, dirfd);
+ if ( !from ) { delete[] pathcopy; return -1; }
+ // TODO: Open the symbolic link, instead of what it points to!
+ Ref desc = from->open(&ctx, relpath, O_RDONLY);
+ delete[] pathcopy;
+ if ( !desc )
+ return -1;
+ return (int) desc->readlink(&ctx, buf, size);
+}
+
void Init()
{
Syscall::Register(SYSCALL_ACCESS, (void*) sys_access);
@@ -570,6 +589,7 @@ void Init()
Syscall::Register(SYSCALL_PREAD, (void*) sys_pread);
Syscall::Register(SYSCALL_PWRITE, (void*) sys_pwrite);
Syscall::Register(SYSCALL_READDIRENTS, (void*) sys_readdirents);
+ Syscall::Register(SYSCALL_READLINKAT, (void*) sys_readlinkat);
Syscall::Register(SYSCALL_READ, (void*) sys_read);
Syscall::Register(SYSCALL_RENAMEAT, (void*) sys_renameat);
Syscall::Register(SYSCALL_RMDIR, (void*) sys_rmdir);