diff --git a/libports/include/libc-plugin/fd_alloc.h b/libports/include/libc-plugin/fd_alloc.h
index 008f3ec9ec..ac153ef3ef 100644
--- a/libports/include/libc-plugin/fd_alloc.h
+++ b/libports/include/libc-plugin/fd_alloc.h
@@ -16,6 +16,12 @@
#define _LIBC_PLUGIN__FD_ALLOC_H_
#include
+#include
+#include
+
+/* libc includes */
+#include
+#include
#include
@@ -28,12 +34,29 @@ namespace Libc {
*/
class Plugin_context { };
+ enum { ANY_FD = -1 };
struct File_descriptor
{
int libc_fd;
+ char *fd_path; /* for 'fchdir()' */
Plugin *plugin;
Plugin_context *context;
+
+ void path(char const *newpath)
+ {
+ if (newpath) {
+ size_t path_size = ::strlen(newpath) + 1;
+ fd_path = (char*)malloc(path_size);
+ if (!fd_path) {
+ PERR("could not allocate path buffer for libc_fd %d%s",
+ libc_fd, libc_fd == ANY_FD ? " (any)" : "");
+ return;
+ }
+ ::memcpy(fd_path, newpath, path_size);
+ } else
+ fd_path = 0;
+ }
};
diff --git a/libports/include/libc-plugin/plugin.h b/libports/include/libc-plugin/plugin.h
index 476946a5d5..7663dc87c1 100644
--- a/libports/include/libc-plugin/plugin.h
+++ b/libports/include/libc-plugin/plugin.h
@@ -14,6 +14,7 @@
#ifndef _LIBC_PLUGIN__PLUGIN_H_
#define _LIBC_PLUGIN__PLUGIN_H_
+#include
#include
#include
@@ -28,6 +29,8 @@ namespace Libc {
class File_descriptor;
+ typedef Genode::Path Absolute_path;
+
class Plugin : public List::Element
{
protected:
@@ -41,7 +44,8 @@ namespace Libc {
virtual int priority();
- virtual bool supports_chdir(const char *path);
+ virtual bool supports_execve(char const *filename, char *const argv[],
+ char *const envp[]);
virtual bool supports_mkdir(const char *path, mode_t mode);
virtual bool supports_freeaddrinfo(struct ::addrinfo *res);
virtual bool supports_getaddrinfo(const char *node, const char *service,
@@ -49,6 +53,7 @@ namespace Libc {
struct ::addrinfo **res);
virtual bool supports_open(const char *pathname, int flags);
virtual bool supports_pipe();
+ virtual bool supports_readlink(const char *path, char *buf, size_t bufsiz);
virtual bool supports_rename(const char *oldpath, const char *newpath);
virtual bool supports_select(int nfds,
fd_set *readfds,
@@ -57,6 +62,7 @@ namespace Libc {
struct timeval *timeout);
virtual bool supports_socket(int domain, int type, int protocol);
virtual bool supports_stat(const char *path);
+ virtual bool supports_symlink(const char *oldpath, const char *newpath);
virtual bool supports_unlink(const char *path);
virtual bool supports_mmap();
@@ -66,14 +72,14 @@ namespace Libc {
virtual int bind(File_descriptor *,
const struct ::sockaddr *addr,
socklen_t addrlen);
- virtual int chdir(const char *path);
virtual int close(File_descriptor *fd);
virtual int connect(File_descriptor *,
const struct ::sockaddr *addr,
socklen_t addrlen);
virtual int dup2(File_descriptor *, File_descriptor *new_fd);
+ virtual int execve(char const *filename, char *const argv[],
+ char *const envp[]);
virtual int fstatfs(File_descriptor *, struct statfs *buf);
- virtual int fchdir(File_descriptor *);
virtual int fcntl(File_descriptor *, int cmd, long arg);
virtual void freeaddrinfo(struct ::addrinfo *res);
virtual int fstat(File_descriptor *, struct stat *buf);
@@ -103,6 +109,7 @@ namespace Libc {
virtual File_descriptor *open(const char *pathname, int flags);
virtual int pipe(File_descriptor *pipefd[2]);
virtual ssize_t read(File_descriptor *, void *buf, ::size_t count);
+ virtual ssize_t readlink(const char *path, char *buf, ::size_t bufsiz);
virtual ssize_t recv(File_descriptor *, void *buf, ::size_t len, int flags);
virtual ssize_t recvfrom(File_descriptor *, void *buf, ::size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
@@ -121,6 +128,7 @@ namespace Libc {
virtual int shutdown(File_descriptor *, int how);
virtual File_descriptor *socket(int domain, int type, int protocol);
virtual int stat(const char *path, struct stat *buf);
+ virtual int symlink(const char *oldpath, const char *newpath);
virtual int unlink(const char *path);
virtual ssize_t write(File_descriptor *, const void *buf, ::size_t count);
};
diff --git a/libports/include/libc-plugin/plugin_registry.h b/libports/include/libc-plugin/plugin_registry.h
index ba2fc7ba44..7096fd1817 100644
--- a/libports/include/libc-plugin/plugin_registry.h
+++ b/libports/include/libc-plugin/plugin_registry.h
@@ -25,7 +25,8 @@ namespace Libc {
{
public:
- Plugin *get_plugin_for_chdir(const char *path);
+ Plugin *get_plugin_for_execve(char const *filename, char *const argv[],
+ char *const envp[]);
Plugin *get_plugin_for_freeaddrinfo(struct addrinfo *res);
Plugin *get_plugin_for_getaddrinfo(const char *node, const char *service,
const struct addrinfo *hints,
@@ -33,9 +34,11 @@ namespace Libc {
Plugin *get_plugin_for_mkdir(const char *path, mode_t mode);
Plugin *get_plugin_for_open(const char *pathname, int flags);
Plugin *get_plugin_for_pipe();
+ Plugin *get_plugin_for_readlink(const char *path, char *buf, size_t bufsiz);
Plugin *get_plugin_for_rename(const char *oldpath, const char *newpath);
Plugin *get_plugin_for_socket(int domain, int type, int protocol);
Plugin *get_plugin_for_stat(const char *path, struct stat *);
+ Plugin *get_plugin_for_symlink(const char *oldpath, const char *newpath);
Plugin *get_plugin_for_unlink(const char *path);
};
diff --git a/libports/lib/mk/libc.mk b/libports/lib/mk/libc.mk
index f357882bde..0e29dc0105 100644
--- a/libports/lib/mk/libc.mk
+++ b/libports/lib/mk/libc.mk
@@ -9,7 +9,7 @@ LIBS += timed_semaphore cxx
#
# Back end
#
-SRC_CC = atexit.cc dummies.cc rlimit.cc sysctl.cc readlink.cc \
+SRC_CC = atexit.cc dummies.cc rlimit.cc sysctl.cc \
issetugid.cc errno.cc gai_strerror.cc clock_gettime.cc \
gettimeofday.cc malloc.cc progname.cc fd_alloc.cc file_operations.cc \
plugin.cc plugin_registry.cc select.cc exit.cc environ.cc nanosleep.cc \
diff --git a/libports/run/libc_fs_tar_fs.run b/libports/run/libc_fs_tar_fs.run
index 5b7498190d..2eb7a8cee7 100644
--- a/libports/run/libc_fs_tar_fs.run
+++ b/libports/run/libc_fs_tar_fs.run
@@ -68,7 +68,12 @@ install_config $config
exec mkdir -p bin/libc_fs_tar_fs/testdir/testdir
exec echo -n "a single line of text" > bin/libc_fs_tar_fs/testdir/testdir/test.tst
-exec tar cfv bin/libc_fs_tar_fs.tar -h -C bin/libc_fs_tar_fs .
+exec mkdir -p bin/libc_fs_tar_fs/testdir/a
+exec mkdir -p bin/libc_fs_tar_fs/testdir/c
+exec ln -sf /a bin/libc_fs_tar_fs/testdir/c/d
+exec ln -sf /c bin/libc_fs_tar_fs/testdir/e
+exec echo -n "a single line of text" > bin/libc_fs_tar_fs/testdir/a/b
+exec tar cfv bin/libc_fs_tar_fs.tar -C bin/libc_fs_tar_fs .
#
# Boot modules
diff --git a/libports/src/lib/libc/dummies.cc b/libports/src/lib/libc/dummies.cc
index d9783cc05d..3abebfc9c8 100644
--- a/libports/src/lib/libc/dummies.cc
+++ b/libports/src/lib/libc/dummies.cc
@@ -37,8 +37,6 @@ DUMMY( 0, __default_hash)
DUMMY(-1, _dup2)
DUMMY(-1, dup2)
DUMMY( 0, endpwent)
-DUMMY(-1, _execve)
-DUMMY(-1, execve)
DUMMY( 0, fchmod)
DUMMY(-1, fchown)
DUMMY(-1, feholdexcept)
@@ -52,7 +50,6 @@ DUMMY(-1, fpathconf)
DUMMY(-1, freebsd7___semctl)
DUMMY(-1, fstatat)
DUMMY(-1, getcontext)
-DUMMY( 0, __getcwd)
DUMMY( 0, getdtablesize)
DUMMY( 0, getegid)
DUMMY( 0, geteuid)
@@ -89,7 +86,6 @@ DUMMY(-1, ksem_trywait)
DUMMY(-1, ksem_unlink)
DUMMY(-1, ksem_wait)
DUMMY(-1, link)
-DUMMY(-1, lstat)
DUMMY(-1, madvise)
DUMMY(-1, mkfifo)
DUMMY(-1, mknod)
@@ -137,7 +133,6 @@ DUMMY(-1, sigsuspend)
DUMMY(-1, socketpair)
DUMMY(-1, stat)
DUMMY(-1, statfs)
-DUMMY(-1, symlink)
DUMMY( 0, sync)
DUMMY(-1, __test_sse)
DUMMY(-1, truncate)
diff --git a/libports/src/lib/libc/fd_alloc.cc b/libports/src/lib/libc/fd_alloc.cc
index 6032566ca0..51d7aa88e3 100644
--- a/libports/src/lib/libc/fd_alloc.cc
+++ b/libports/src/lib/libc/fd_alloc.cc
@@ -40,10 +40,10 @@ File_descriptor_allocator::File_descriptor_allocator()
}
-File_descriptor *File_descriptor_allocator::alloc(Plugin *plugin, Plugin_context *context, int libc_fd)
+File_descriptor *File_descriptor_allocator::alloc(Plugin *plugin,
+ Plugin_context *context,
+ int libc_fd)
{
- enum { ANY_FD = -1 };
-
/* we use addresses returned by the allocator as file descriptors */
addr_t addr = (libc_fd == ANY_FD ? ANY_FD : libc_fd);
@@ -62,6 +62,7 @@ File_descriptor *File_descriptor_allocator::alloc(Plugin *plugin, Plugin_context
File_descriptor *fdo = metadata((void*)addr);
fdo->libc_fd = (int)addr;
+ fdo->fd_path = 0;
fdo->plugin = plugin;
fdo->context = context;
return fdo;
@@ -70,6 +71,7 @@ File_descriptor *File_descriptor_allocator::alloc(Plugin *plugin, Plugin_context
void File_descriptor_allocator::free(File_descriptor *fdo)
{
+ ::free(fdo->fd_path);
Allocator_avl_base::free(reinterpret_cast(fdo->libc_fd));
}
diff --git a/libports/src/lib/libc/file_operations.cc b/libports/src/lib/libc/file_operations.cc
index bece72decb..d72fa10c74 100644
--- a/libports/src/lib/libc/file_operations.cc
+++ b/libports/src/lib/libc/file_operations.cc
@@ -15,6 +15,8 @@
/* Genode includes */
#include
#include
+#include
+#include
/* Genode-specific libc interfaces */
#include
@@ -23,8 +25,10 @@
/* libc includes */
#include
+#include
#include
#include
+#include
#include
#include
@@ -40,6 +44,9 @@ using namespace Libc;
#define PERR(...)
#endif /* GENODE_RELEASE */
+static bool const verbose = false;
+#define PDBGV(...) if (verbose) PDBG(__VA_ARGS__)
+
enum { INVALID_FD = -1 };
@@ -65,7 +72,6 @@ inline File_descriptor *libc_fd_to_fd(int libc_fd, const char *func_name)
File_descriptor *fd = file_descriptor_allocator()->find_by_libc_fd(libc_fd);
if (!fd)
PERR("no plugin found for %s(%d)", func_name, libc_fd);
-
return fd;
}
@@ -74,11 +80,13 @@ inline File_descriptor *libc_fd_to_fd(int libc_fd, const char *func_name)
* Generate body of wrapper function taking a file descriptor as first argument
*/
#define FD_FUNC_WRAPPER_GENERIC(result_stm, func_name, libc_fd, ...) \
- File_descriptor *fd = libc_fd_to_fd(libc_fd, #func_name); \
- if (!fd || !fd->plugin) \
- result_stm INVALID_FD; \
- else \
- result_stm fd->plugin->func_name(fd, ##__VA_ARGS__ );
+{ \
+ File_descriptor *fd = libc_fd_to_fd(libc_fd, #func_name); \
+ if (!fd || !fd->plugin) \
+ result_stm INVALID_FD; \
+ else \
+ result_stm fd->plugin->func_name(fd, ##__VA_ARGS__ ); \
+}
#define FD_FUNC_WRAPPER(func_name, libc_fd, ...) \
FD_FUNC_WRAPPER_GENERIC(return, func_name, libc_fd, ##__VA_ARGS__ )
@@ -86,13 +94,168 @@ inline File_descriptor *libc_fd_to_fd(int libc_fd, const char *func_name)
/**
* Generate body of wrapper function taking a path name as first argument
*/
+#define FNAME_FUNC_WRAPPER_GENERIC(result_stm, func_name, path, ...) \
+{ \
+ Plugin *plugin = plugin_registry()->get_plugin_for_##func_name(path, ##__VA_ARGS__); \
+ if (!plugin) { \
+ PERR("no plugin found for %s(\"%s\")", #func_name, path); \
+ errno = ENOSYS; \
+ result_stm -1; \
+ } else \
+ result_stm plugin->func_name(path, ##__VA_ARGS__); \
+}
+
#define FNAME_FUNC_WRAPPER(func_name, path, ...) \
- Plugin *plugin = plugin_registry()->get_plugin_for_##func_name(path, ##__VA_ARGS__); \
- if (!plugin) { \
- PERR("no plugin found for %s(\"%s\")", #func_name, path); \
- return -1; \
- } \
- return plugin->func_name(path, ##__VA_ARGS__);
+ FNAME_FUNC_WRAPPER_GENERIC(return, func_name, path, ##__VA_ARGS__ )
+
+
+/**
+ * Current working directory
+ */
+static Absolute_path &cwd()
+{
+ static Absolute_path _cwd("/");
+ return _cwd;
+}
+
+/**
+ * path element token
+ */
+
+struct Scanner_policy_path_element
+{
+ static bool identifier_char(char c, unsigned /* i */)
+ {
+ return (c != '/') && (c != 0);
+ }
+};
+
+typedef Genode::Token Path_element_token;
+
+
+/**
+ * Resolve symbolic links in a given absolute path
+ */
+
+/* exception */
+class Symlink_resolve_error { };
+
+static void resolve_symlinks(char const *path, Absolute_path &resolved_path)
+{
+ PDBGV("path = %s", path);
+
+ char path_element[PATH_MAX];
+ char symlink_target[PATH_MAX];
+
+ Absolute_path current_iteration_working_path;
+ Absolute_path next_iteration_working_path(path, cwd().base());
+ PDBGV("absolute_path = %s", next_iteration_working_path.base());
+
+ enum { FOLLOW_LIMIT = 10 };
+ int follow_count = 0;
+ bool symlink_resolved_in_this_iteration;
+ do {
+ PDBGV("new iteration");
+ if (follow_count++ == FOLLOW_LIMIT) {
+ errno = ELOOP;
+ throw Symlink_resolve_error();
+ }
+
+ current_iteration_working_path.import(next_iteration_working_path.base());
+ PDBGV("current_iteration_working_path = %s", current_iteration_working_path.base());
+
+ next_iteration_working_path.import("");
+ symlink_resolved_in_this_iteration = false;
+
+ Path_element_token t(current_iteration_working_path.base());
+
+ while (t) {
+ if (t.type() != Path_element_token::IDENT) {
+ t = t.next();
+ continue;
+ }
+
+ t.string(path_element, sizeof(path_element));
+ PDBGV("path_element = %s", path_element);
+
+ try {
+ next_iteration_working_path.append("/");
+ next_iteration_working_path.append(path_element);
+ } catch (Genode::Path_base::Path_too_long) {
+ errno = ENAMETOOLONG;
+ throw Symlink_resolve_error();
+ }
+
+ PDBGV("working_path_new = %s", next_iteration_working_path.base());
+
+ /*
+ * If a symlink has been resolved in this iteration, the remaining
+ * path elements get added and a new iteration starts.
+ */
+ if (!symlink_resolved_in_this_iteration) {
+ struct stat stat_buf;
+ int res;
+ FNAME_FUNC_WRAPPER_GENERIC(res = , stat, next_iteration_working_path.base(), &stat_buf);
+ if (res == -1) {
+ PDBGV("stat() failed for %s", next_iteration_working_path.base());
+ throw Symlink_resolve_error();
+ }
+ if (S_ISLNK(stat_buf.st_mode)) {
+ PDBGV("found symlink: %s", next_iteration_working_path.base());
+ FNAME_FUNC_WRAPPER_GENERIC(res = , readlink,
+ next_iteration_working_path.base(),
+ symlink_target, sizeof(symlink_target));
+ if (res < 1)
+ throw Symlink_resolve_error();
+
+ if (symlink_target[0] == '/')
+ /* absolute target */
+ next_iteration_working_path.import(symlink_target, cwd().base());
+ else {
+ /* relative target */
+ next_iteration_working_path.strip_last_element();
+ try {
+ next_iteration_working_path.append(symlink_target);
+ } catch (Genode::Path_base::Path_too_long) {
+ errno = ENAMETOOLONG;
+ throw Symlink_resolve_error();
+ }
+ }
+ PDBGV("resolved symlink to: %s", next_iteration_working_path.base());
+ symlink_resolved_in_this_iteration = true;
+ }
+ }
+
+ t = t.next();
+ }
+ PDBGV("token end");
+
+ } while (symlink_resolved_in_this_iteration);
+
+ resolved_path.import(next_iteration_working_path.base());
+ PDBGV("resolved_path = %s", resolved_path.base());
+}
+
+
+static void resolve_symlinks_except_last_element(char const *path, Absolute_path &resolved_path)
+{
+ PDBGV("path = %s", path);
+
+ Absolute_path absolute_path_without_last_element(path, cwd().base());
+ absolute_path_without_last_element.strip_last_element();
+
+ resolve_symlinks(absolute_path_without_last_element.base(), resolved_path);
+
+ /* append last element to resolved path */
+ Absolute_path absolute_path_last_element(path, cwd().base());
+ absolute_path_last_element.keep_only_last_element();
+ try {
+ resolved_path.append(absolute_path_last_element.base());
+ } catch (Genode::Path_base::Path_too_long) {
+ errno = ENAMETOOLONG;
+ throw Symlink_resolve_error();
+ }
+}
/********************
@@ -125,8 +288,17 @@ extern "C" int bind(int libc_fd, const struct sockaddr *addr,
FD_FUNC_WRAPPER(bind, libc_fd, addr, addrlen); }
-extern "C" int chdir(const char *path) {
- FNAME_FUNC_WRAPPER(chdir, path) }
+extern "C" int chdir(const char *path)
+{
+ struct stat stat_buf;
+ if ((stat(path, &stat_buf) == -1) ||
+ (!S_ISDIR(stat_buf.st_mode))) {
+ errno = ENOTDIR;
+ return -1;
+ }
+ cwd().import(path, cwd().base());
+ return 0;
+}
extern "C" int _close(int libc_fd) {
@@ -150,7 +322,6 @@ extern "C" int _connect(int libc_fd, const struct sockaddr *addr,
extern "C" int _dup2(int libc_fd, int new_libc_fd)
{
-
File_descriptor *fd = libc_fd_to_fd(libc_fd, "dup2");
if (!fd || !fd->plugin)
return INVALID_FD;
@@ -163,7 +334,8 @@ extern "C" int _dup2(int libc_fd, int new_libc_fd)
if (new_fd)
close(new_libc_fd);
- new_fd = file_descriptor_allocator()->alloc(fd->plugin, 0, new_libc_fd);
+ new_fd = file_descriptor_allocator()->alloc(fd->plugin, 0, new_libc_fd);
+ new_fd->path(fd->fd_path);
/* new_fd->context must be assigned by the plugin implementing 'dup2' */
return fd->plugin->dup2(fd, new_fd);
}
@@ -175,8 +347,35 @@ extern "C" int dup2(int libc_fd, int new_libc_fd)
}
-extern "C" int fchdir(int libc_fd) {
- FD_FUNC_WRAPPER(fchdir, libc_fd); }
+extern "C" int _execve(char const *filename, char *const argv[],
+ char *const envp[])
+{
+ try {
+ Absolute_path resolved_path;
+ resolve_symlinks(filename, resolved_path);
+ FNAME_FUNC_WRAPPER(execve, resolved_path.base(), argv, envp);
+ } catch (Symlink_resolve_error) {
+ return -1;
+ }
+}
+
+
+extern "C" int execve(char const *filename, char *const argv[],
+ char *const envp[])
+{
+ return _execve(filename, argv, envp);
+}
+
+
+extern "C" int fchdir(int libc_fd)
+{
+ File_descriptor *fd = libc_fd_to_fd(libc_fd, "fchdir");
+
+ if (!fd)
+ return INVALID_FD;
+
+ return chdir(fd->fd_path);
+}
extern "C" int fcntl(int libc_fd, int cmd, ...)
@@ -295,8 +494,28 @@ extern "C" ::off_t lseek(int libc_fd, ::off_t offset, int whence) {
FD_FUNC_WRAPPER(lseek, libc_fd, offset, whence); }
-extern "C" int mkdir(const char *path, mode_t mode) {
- FNAME_FUNC_WRAPPER(mkdir, path, mode) }
+extern "C" int lstat(const char *path, struct stat *buf)
+{
+ try {
+ Absolute_path resolved_path;
+ resolve_symlinks_except_last_element(path, resolved_path);
+ FNAME_FUNC_WRAPPER(stat, resolved_path.base(), buf);
+ } catch (Symlink_resolve_error) {
+ return -1;
+ }
+}
+
+
+extern "C" int mkdir(const char *path, mode_t mode)
+{
+ try {
+ Absolute_path resolved_path;
+ resolve_symlinks_except_last_element(path, resolved_path);
+ FNAME_FUNC_WRAPPER(mkdir, resolved_path.base(), mode);
+ } catch(Symlink_resolve_error) {
+ return -1;
+ }
+}
extern "C" void *mmap(void *addr, ::size_t length, int prot, int flags,
@@ -351,21 +570,47 @@ extern "C" int munmap(void *start, ::size_t length)
extern "C" int _open(const char *pathname, int flags, ::mode_t mode)
{
+ PDBGV("pathname = %s", pathname);
+
+ Absolute_path resolved_path;
+
Plugin *plugin;
File_descriptor *new_fdo;
- plugin = plugin_registry()->get_plugin_for_open(pathname, flags);
+ try {
+ resolve_symlinks_except_last_element(pathname, resolved_path);
+ } catch (Symlink_resolve_error) {
+ return -1;
+ }
+
+ if (!(flags & O_NOFOLLOW)) {
+ /* resolve last element */
+ try {
+ resolve_symlinks(resolved_path.base(), resolved_path);
+ } catch (Symlink_resolve_error) {
+ if (errno == ENOENT) {
+ if (!(flags & O_CREAT))
+ return -1;
+ } else
+ return -1;
+ }
+ }
+
+ PDBGV("resolved path = %s", resolved_path.base());
+
+ plugin = plugin_registry()->get_plugin_for_open(resolved_path.base(), flags);
if (!plugin) {
PERR("no plugin found for open(\"%s\", int)", pathname, flags);
return -1;
}
- new_fdo = plugin->open(pathname, flags);
+ new_fdo = plugin->open(resolved_path.base(), flags);
if (!new_fdo) {
PERR("plugin()->open(\"%s\") failed", pathname);
return -1;
}
+ new_fdo->path(resolved_path.base());
return new_fdo->libc_fd;
}
@@ -415,6 +660,18 @@ extern "C" ssize_t read(int libc_fd, void *buf, ::size_t count)
}
+extern "C" ssize_t readlink(const char *path, char *buf, size_t bufsiz)
+{
+ try {
+ Absolute_path resolved_path;
+ resolve_symlinks_except_last_element(path, resolved_path);
+ FNAME_FUNC_WRAPPER(readlink, resolved_path.base(), buf, bufsiz);
+ } catch(Symlink_resolve_error) {
+ return -1;
+ }
+}
+
+
extern "C" ssize_t recv(int libc_fd, void *buf, ::size_t len, int flags) {
FD_FUNC_WRAPPER(recv, libc_fd, buf, len, flags); }
@@ -435,8 +692,17 @@ extern "C" ssize_t recvmsg(int libc_fd, struct msghdr *msg, int flags) {
FD_FUNC_WRAPPER(recvmsg, libc_fd, msg, flags); }
-extern "C" int rename(const char *oldpath, const char *newpath) {
- FNAME_FUNC_WRAPPER(rename, oldpath, newpath); }
+extern "C" int rename(const char *oldpath, const char *newpath)
+{
+ try {
+ Absolute_path resolved_oldpath, resolved_newpath;
+ resolve_symlinks_except_last_element(oldpath, resolved_oldpath);
+ resolve_symlinks_except_last_element(newpath, resolved_newpath);
+ FNAME_FUNC_WRAPPER(rename, resolved_oldpath.base(), resolved_newpath.base());
+ } catch(Symlink_resolve_error) {
+ return -1;
+ }
+}
extern "C" ssize_t send(int libc_fd, const void *buf, ::size_t len, int flags) {
@@ -510,16 +776,54 @@ extern "C" int _socket(int domain, int type, int protocol)
}
-extern "C" int stat(const char *path, struct stat *buf) {
- FNAME_FUNC_WRAPPER(stat, path, buf) }
+extern "C" int stat(const char *path, struct stat *buf)
+{
+ PDBGV("path = %s", path);
+ try {
+ Absolute_path resolved_path;
+ resolve_symlinks(path, resolved_path);
+ FNAME_FUNC_WRAPPER(stat, resolved_path.base(), buf);
+ } catch(Symlink_resolve_error) {
+ return -1;
+ }
+}
-extern "C" int unlink(const char *path) {
- FNAME_FUNC_WRAPPER(unlink, path) }
+extern "C" int symlink(const char *oldpath, const char *newpath)
+{
+ try {
+ Absolute_path resolved_path;
+ resolve_symlinks_except_last_element(newpath, resolved_path);
+ FNAME_FUNC_WRAPPER(symlink, oldpath, resolved_path.base());
+ } catch(Symlink_resolve_error) {
+ return -1;
+ }
+}
+
+
+extern "C" int unlink(const char *path)
+{
+ try {
+ Absolute_path resolved_path;
+ resolve_symlinks_except_last_element(path, resolved_path);
+ FNAME_FUNC_WRAPPER(unlink, resolved_path.base());
+ } catch(Symlink_resolve_error) {
+ return -1;
+ }
+}
extern "C" ssize_t _write(int libc_fd, const void *buf, ::size_t count) {
FD_FUNC_WRAPPER(write, libc_fd, buf, count); }
+
extern "C" ssize_t write(int libc_fd, const void *buf, ::size_t count) {
return _write(libc_fd, buf, count); }
+
+
+extern "C" int __getcwd(char *dst, ::size_t dst_size)
+{
+ Genode::strncpy(dst, cwd().base(), dst_size);
+ PDBGV("cwd = %s", dst);
+ return 0;
+}
diff --git a/libports/src/lib/libc/plugin.cc b/libports/src/lib/libc/plugin.cc
index 5b99fbb79e..9642e5c6b8 100644
--- a/libports/src/lib/libc/plugin.cc
+++ b/libports/src/lib/libc/plugin.cc
@@ -42,7 +42,8 @@ int Plugin::priority()
}
-bool Plugin::supports_chdir(const char *path)
+bool Plugin::supports_execve(char const *filename, char *const argv[],
+ char *const envp[])
{
return false;
}
@@ -80,6 +81,12 @@ bool Plugin::supports_pipe()
}
+bool Plugin::supports_readlink(const char *path, char *buf, size_t bufsiz)
+{
+ return false;
+}
+
+
bool Plugin::supports_rename(const char *, const char *)
{
return false;
@@ -105,6 +112,12 @@ bool Plugin::supports_stat(const char*)
}
+bool Plugin::supports_symlink(const char*, const char *)
+{
+ return false;
+}
+
+
bool Plugin::supports_unlink(const char*)
{
return false;
@@ -117,19 +130,6 @@ bool Plugin::supports_mmap()
}
-/**
- * Default implementations
- */
-
-int Plugin::chdir(const char *path)
-{
- Libc::File_descriptor *fd = open(path, 0 /* no rights necessary */);
- bool success = ((fd != NULL)
- and (fchdir(fd) == 0)
- and (close(fd) == 0));
- return success ? 0 : -1;
-}
-
/**
* Generate dummy member function of Plugin class
*/
@@ -157,7 +157,6 @@ DUMMY(int, -1, close, (File_descriptor *));
DUMMY(int, -1, connect, (File_descriptor *, const struct sockaddr *, socklen_t));
DUMMY(int, -1, dup2, (File_descriptor *, File_descriptor *new_fd));
DUMMY(int, -1, fstatfs, (File_descriptor *, struct statfs *));
-DUMMY(int, -1, fchdir, (File_descriptor *));
DUMMY(int, -1, fcntl, (File_descriptor *, int cmd, long arg));
DUMMY(int, -1, fstat, (File_descriptor *, struct stat *));
DUMMY(int, -1, fsync, (File_descriptor *));
@@ -183,6 +182,7 @@ DUMMY(ssize_t, -1, write, (File_descriptor *, const void *, ::size_t));
/*
* Misc
*/
+DUMMY(int, -1, execve, (char const *, char *const[], char *const[]));
DUMMY(void, , freeaddrinfo, (struct ::addrinfo *));
DUMMY(int, -1, getaddrinfo, (const char *, const char *, const struct ::addrinfo *, struct ::addrinfo **));
DUMMY(int, -1, mkdir, (const char*, mode_t));
@@ -190,7 +190,9 @@ DUMMY(void *, (void *)(-1), mmap, (void *addr, ::size_t length, int prot, int fl
File_descriptor *, ::off_t offset));
DUMMY(int, -1, munmap, (void *, ::size_t));
DUMMY(int, -1, pipe, (File_descriptor*[2]));
+DUMMY(ssize_t, -1, readlink, (const char *, char *, size_t));
DUMMY(int, -1, rename, (const char *, const char *));
DUMMY(int, -1, select, (int, fd_set *, fd_set *, fd_set *, struct timeval *));
DUMMY(int, -1, stat, (const char*, struct stat*));
+DUMMY(int, -1, symlink, (const char*, const char*));
DUMMY(int, -1, unlink, (const char*));
diff --git a/libports/src/lib/libc/plugin_registry.cc b/libports/src/lib/libc/plugin_registry.cc
index 79a46e7b08..eea97e46e0 100644
--- a/libports/src/lib/libc/plugin_registry.cc
+++ b/libports/src/lib/libc/plugin_registry.cc
@@ -37,9 +37,9 @@ using namespace Libc;
} \
return result;
-
-Plugin *Plugin_registry::get_plugin_for_chdir(const char *path) {
- GET_PLUGIN_FOR(chdir, path) }
+Plugin *Plugin_registry::get_plugin_for_execve(char const *filename, char *const argv[],
+ char *const envp[]) {
+ GET_PLUGIN_FOR(execve, filename, argv, envp) }
Plugin *Plugin_registry::get_plugin_for_freeaddrinfo(struct addrinfo *res) {
@@ -64,6 +64,10 @@ Plugin *Plugin_registry::get_plugin_for_pipe() {
GET_PLUGIN_FOR(pipe) }
+Plugin *Plugin_registry::get_plugin_for_readlink(const char *path, char *buf, size_t bufsiz) {
+ GET_PLUGIN_FOR(readlink, path, buf, bufsiz) }
+
+
Plugin *Plugin_registry::get_plugin_for_rename(const char *oldpath, const char *newpath) {
GET_PLUGIN_FOR(rename, oldpath, newpath) }
@@ -76,5 +80,9 @@ Plugin *Plugin_registry::get_plugin_for_stat(const char *path, struct stat *) {
GET_PLUGIN_FOR(stat, path) }
+Plugin *Plugin_registry::get_plugin_for_symlink(const char *oldpath, const char *newpath) {
+ GET_PLUGIN_FOR(symlink, oldpath, newpath) }
+
+
Plugin *Plugin_registry::get_plugin_for_unlink(const char *path) {
GET_PLUGIN_FOR(unlink, path) }
diff --git a/libports/src/lib/libc/readlink.cc b/libports/src/lib/libc/readlink.cc
deleted file mode 100644
index e6ef9dd9db..0000000000
--- a/libports/src/lib/libc/readlink.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * \brief C-library back end
- * \author Norman Feske
- * \date 2008-11-11
- */
-
-/*
- * Copyright (C) 2008-2012 Genode Labs GmbH
- *
- * This file is part of the Genode OS framework, which is distributed
- * under the terms of the GNU General Public License version 2.
- */
-
-#include
-#include
-#include
-
-#include "libc_debug.h"
-
-extern "C" ssize_t readlink(const char *path, char *buf, size_t bufsiz)
-{
- /*
- * During malloc, readlink is called with the path argument "/etc/malloc.conf"
- */
- if (strcmp("/etc/malloc.conf", path) == 0)
- return -1;
-
- raw_write_str("readlink called path=\n");
- raw_write_str(path);
- raw_write_str("\n");
- return -1;
-}
-
diff --git a/libports/src/lib/libc_ffat/plugin.cc b/libports/src/lib/libc_ffat/plugin.cc
index 280f158514..e21fd0bca4 100644
--- a/libports/src/lib/libc_ffat/plugin.cc
+++ b/libports/src/lib/libc_ffat/plugin.cc
@@ -14,6 +14,7 @@
/* Genode includes */
#include
#include
+#include
/* libc includes */
#include
@@ -131,7 +132,6 @@ class Plugin : public Libc::Plugin
File_plugin_context *file_plugin_context =
dynamic_cast(context(fd));
if (!file_plugin_context) {
- PERR("_get_ffat_file() called for a directory");
return 0;
}
return file_plugin_context->ffat_file();
@@ -142,7 +142,6 @@ class Plugin : public Libc::Plugin
Directory_plugin_context *directory_plugin_context =
dynamic_cast(context(fd));
if (!directory_plugin_context) {
- PERR("_get_ffat_dir() called for a regular file");
return 0;
}
return directory_plugin_context->ffat_dir();
@@ -174,13 +173,6 @@ class Plugin : public Libc::Plugin
* TODO: decide if the file named shall be handled by this plugin
*/
- bool supports_chdir(const char *path)
- {
- if (verbose)
- PDBG("path = %s", path);
- return true;
- }
-
bool supports_mkdir(const char *path, mode_t)
{
if (verbose)
@@ -216,39 +208,20 @@ class Plugin : public Libc::Plugin
return true;
}
- int chdir(const char *path)
- {
- using namespace Ffat;
-
- FRESULT res = f_chdir(path);
-
- switch(res) {
- case FR_OK:
- return 0;
- case FR_NO_PATH:
- case FR_INVALID_NAME:
- case FR_INVALID_DRIVE:
- errno = ENOENT;
- return -1;
- case FR_NOT_READY:
- case FR_DISK_ERR:
- case FR_INT_ERR:
- case FR_NOT_ENABLED:
- case FR_NO_FILESYSTEM:
- errno = EIO;
- return -1;
- default:
- /* not supposed to occur according to the libffat documentation */
- PERR("f_chdir() returned an unexpected error code");
- return -1;
- }
- }
-
int close(Libc::File_descriptor *fd)
{
using namespace Ffat;
- FRESULT res = f_close(_get_ffat_file(fd));
+ FIL *ffat_file = _get_ffat_file(fd);
+
+ if (!ffat_file){
+ /* directory */
+ Genode::destroy(Genode::env()->heap(), context(fd));
+ Libc::file_descriptor_allocator()->free(fd);
+ return 0;
+ }
+
+ FRESULT res = f_close(ffat_file);
Genode::destroy(Genode::env()->heap(), context(fd));
Libc::file_descriptor_allocator()->free(fd);
@@ -646,6 +619,14 @@ class Plugin : public Libc::Plugin
file_info.lfname = 0;
file_info.lfsize = 0;
+ ::memset(buf, 0, sizeof(struct stat));
+
+ /* 'f_stat()' does not work for the '/' directory */
+ if (strcmp(path, "/") == 0) {
+ buf->st_mode |= S_IFDIR;
+ return 0;
+ }
+
FRESULT res = f_stat(path, &file_info);
switch(res) {
@@ -670,8 +651,6 @@ class Plugin : public Libc::Plugin
return -1;
}
- ::memset(buf, 0, sizeof(struct stat));
-
/* convert FILINFO to struct stat */
buf->st_size = file_info.fsize;
diff --git a/libports/src/lib/libc_fs/plugin.cc b/libports/src/lib/libc_fs/plugin.cc
index 9bfc2fe58f..488d130403 100644
--- a/libports/src/lib/libc_fs/plugin.cc
+++ b/libports/src/lib/libc_fs/plugin.cc
@@ -15,6 +15,7 @@
#include
#include
#include
+#include
/* libc includes */
#include
@@ -43,44 +44,7 @@ namespace {
enum { PATH_MAX_LEN = 256 };
-
-/**
- * Current working directory
- */
-struct Cwd
-{
- char path[PATH_MAX_LEN];
-
- Cwd() { Genode::strncpy(path, "/", sizeof(path)); }
-};
-
-
-static Cwd *cwd()
-{
- static Cwd cwd_inst;
- return &cwd_inst;
-}
-
-
-struct Canonical_path
-{
- char str[PATH_MAX_LEN];
-
- Canonical_path(char const *pathname)
- {
- /*
- * If pathname is a relative path, prepend the current working
- * directory.
- *
- * XXX we might consider using Noux' 'Path' class here
- */
- if (pathname[0] != '/') {
- snprintf(str, sizeof(str), "%s/%s", cwd()->path, pathname);
- } else {
- strncpy(str, pathname, sizeof(str));
- }
- }
-};
+typedef Genode::Path Canonical_path;
static File_system::Session *file_system()
@@ -252,13 +216,6 @@ class Plugin : public Libc::Plugin
~Plugin() { }
- bool supports_chdir(const char *path)
- {
- if (verbose)
- PDBG("path = %s", path);
- return true;
- }
-
bool supports_mkdir(const char *path, mode_t)
{
if (verbose)
@@ -273,6 +230,13 @@ class Plugin : public Libc::Plugin
return true;
}
+ bool supports_readlink(const char *path, char *, size_t)
+ {
+ if (verbose)
+ PDBG("path = %s", path);
+ return true;
+ }
+
bool supports_rename(const char *oldpath, const char *newpath)
{
if (verbose)
@@ -287,6 +251,13 @@ class Plugin : public Libc::Plugin
return true;
}
+ bool supports_symlink(const char *oldpath, const char *newpath)
+ {
+ if (verbose)
+ PDBG("oldpath = %s, newpath = %s", oldpath, newpath);
+ return true;
+ }
+
bool supports_unlink(const char *path)
{
if (verbose)
@@ -296,25 +267,6 @@ class Plugin : public Libc::Plugin
bool supports_mmap() { return true; }
- int chdir(const char *path)
- {
- if (*path != '/') {
- PERR("chdir: relative path names not yet supported");
- errno = ENOENT;
- return -1;
- }
-
- Genode::strncpy(cwd()->path, path, sizeof(cwd()->path));
-
- /* strip trailing slash if needed */
- char *s = cwd()->path;
- for (; s[0] && s[1]; s++);
- if (s[0] == '/')
- s[0] = 0;
-
- return 0;
- }
-
int close(Libc::File_descriptor *fd)
{
/* wait for the completion of all operations of the context */
@@ -468,7 +420,7 @@ class Plugin : public Libc::Plugin
try {
File_system::Dir_handle const handle =
- file_system()->dir(canonical_path.str, true);
+ file_system()->dir(canonical_path.base(), true);
file_system()->close(handle);
return 0;
}
@@ -498,9 +450,9 @@ class Plugin : public Libc::Plugin
*/
try {
if (verbose)
- PDBG("open dir '%s'", path.str);
+ PDBG("open dir '%s'", path.base());
File_system::Dir_handle const handle =
- file_system()->dir(path.str, false);
+ file_system()->dir(path.base(), false);
Plugin_context *context = new (Genode::env()->heap())
Plugin_context(handle);
@@ -511,27 +463,18 @@ class Plugin : public Libc::Plugin
/*
* Determine directory path that contains the node to open
*/
- unsigned last_slash = 0;
- for (unsigned i = 0; path.str[i]; i++)
- if (path.str[i] == '/')
- last_slash = i;
+ Canonical_path dir_path(pathname);
+ dir_path.strip_last_element();
- char dir_path[256] = "/";
- if (last_slash > 0)
- Genode::strncpy(dir_path, path.str,
- Genode::min(sizeof(dir_path), last_slash + 1));
-
- /*
- * Determine base name
- */
- char const *basename = path.str + last_slash + 1;
+ Canonical_path basename(pathname);
+ basename.keep_only_last_element();
try {
/*
* Open directory that contains the file to be opened/created
*/
File_system::Dir_handle const dir_handle =
- file_system()->dir(dir_path, false);
+ file_system()->dir(dir_path.base(), false);
Node_handle_guard guard(dir_handle);
@@ -545,14 +488,14 @@ class Plugin : public Libc::Plugin
bool opened = false;
while (!opened) {
try {
- handle = file_system()->file(dir_handle, basename, mode, create);
+ handle = file_system()->file(dir_handle, basename.base() + 1, mode, create);
opened = true;
} catch (File_system::Node_already_exists) {
if (flags & O_EXCL)
throw File_system::Node_already_exists();
/* try to open the existing file */
try {
- handle = file_system()->file(dir_handle, basename, mode, false);
+ handle = file_system()->file(dir_handle, basename.base() + 1, mode, false);
opened = true;
} catch (File_system::Lookup_failed) {
/* the file got deleted in the meantime */
@@ -649,27 +592,114 @@ class Plugin : public Libc::Plugin
return count - remaining_count;
}
+ ssize_t readlink(const char *path, char *buf, size_t bufsiz)
+ {
+ if (verbose)
+ PDBG("path = %s, bufsiz = %zu", path, bufsiz);
+
+ Canonical_path abs_path(path);
+ abs_path.strip_last_element();
+
+ Canonical_path symlink_name(path);
+ symlink_name.keep_only_last_element();
+
+ try {
+ ::File_system::Dir_handle dir_handle = file_system()->dir(abs_path.base(), false);
+
+ ::File_system::Symlink_handle symlink_handle =
+ file_system()->symlink(dir_handle, symlink_name.base() + 1, false);
+
+ if (symlink_handle.value == -1) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ Plugin_context *context = new (Genode::env()->heap())
+ Plugin_context(symlink_handle);
+
+ Libc::File_descriptor *fd = Libc::file_descriptor_allocator()->alloc(this, context);
+
+ ssize_t result = read(fd, buf, bufsiz);
+ if (verbose)
+ PDBG("result = %zd, buf = %s", result, buf);
+ close(fd);
+
+ return result;
+ } catch (...) { }
+
+ errno = ENOENT;
+ return -1;
+ }
+
int stat(const char *pathname, struct stat *buf)
{
if (verbose)
PDBG("stat %s", pathname);
+
Canonical_path path(pathname);
try {
File_system::Node_handle const node_handle =
- file_system()->node(path.str);
+ file_system()->node(path.base());
Node_handle_guard guard(node_handle);
obtain_stat_for_node(node_handle, buf);
return 0;
}
catch (File_system::Lookup_failed) {
- PERR("lookup failed");
+ PERR("stat(%s): lookup failed", pathname);
errno = ENOENT;
}
return -1;
}
+ int symlink(const char *oldpath, const char *newpath)
+ {
+ Canonical_path abs_path(newpath);
+ abs_path.strip_last_element();
+
+ Canonical_path symlink_name(newpath);
+ symlink_name.keep_only_last_element();
+
+ try {
+ /*
+ * Open directory that contains the file to be opened/created
+ */
+ File_system::Dir_handle const dir_handle =
+ file_system()->dir(abs_path.base(), false);
+
+ Node_handle_guard guard(dir_handle);
+
+ File_system::Symlink_handle symlink_handle =
+ file_system()->symlink(dir_handle, symlink_name.base() + 1, true);
+
+ if (symlink_handle.value == -1) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ Plugin_context *context = new (Genode::env()->heap())
+ Plugin_context(symlink_handle);
+
+ Libc::File_descriptor *fd =
+ Libc::file_descriptor_allocator()->alloc(this, context);
+
+ if (write(fd, oldpath, strlen(oldpath) + 1) == -1) {
+ errno = EIO;
+ return -1;
+ }
+
+ close(fd);
+
+ return 0;
+ }
+ catch (File_system::Lookup_failed) {
+ PERR("symlink(%s) lookup failed", newpath); }
+
+ errno = ENOENT;
+ return -1;
+ }
+
int unlink(const char *path)
{
return -1;
diff --git a/libports/src/lib/libc_rom/plugin.cc b/libports/src/lib/libc_rom/plugin.cc
index 6be47eeb23..14736d2408 100644
--- a/libports/src/lib/libc_rom/plugin.cc
+++ b/libports/src/lib/libc_rom/plugin.cc
@@ -77,13 +77,18 @@ namespace {
bool supports_open(const char *path, int flags)
{
- return _probe_rom(path);
+ return _probe_rom(&path[1]);
+ }
+
+ bool supports_stat(const char *path)
+ {
+ return _probe_rom(&path[1]);
}
Libc::File_descriptor *open(const char *pathname, int flags)
{
Plugin_context *context = new (Genode::env()->heap())
- Plugin_context(pathname);
+ Plugin_context(&pathname[1]);
return Libc::file_descriptor_allocator()->alloc(this, context);
}
@@ -94,6 +99,16 @@ namespace {
return 0;
}
+ int stat(const char *path, struct stat *buf)
+ {
+ Genode::Rom_connection rom(&path[1]);
+
+ memset(buf, 0, sizeof(struct stat));
+ buf->st_mode = S_IFREG;
+ buf->st_size = Genode::Dataspace_client(rom.dataspace()).size();
+ return 0;
+ }
+
ssize_t read(Libc::File_descriptor *fd, void *buf, ::size_t count)
{
Plugin_context *rom = context(fd);
@@ -140,7 +155,7 @@ namespace {
case SEEK_SET:
- if (offset > rom->size()) {
+ if (offset > (::off_t)rom->size()) {
errno = EINVAL;
return (::off_t)(-1);
}
diff --git a/libports/src/lib/libc_terminal/plugin.cc b/libports/src/lib/libc_terminal/plugin.cc
index 6811e86647..33dea5eef0 100644
--- a/libports/src/lib/libc_terminal/plugin.cc
+++ b/libports/src/lib/libc_terminal/plugin.cc
@@ -133,7 +133,8 @@ namespace {
bool supports_stat(const char *path)
{
- return (Genode::strcmp(path, _dev_name()) == 0);
+ return (Genode::strcmp(path, "/dev") == 0) ||
+ (Genode::strcmp(path, _dev_name()) == 0);
}
bool supports_open(const char *path, int flags)
@@ -164,7 +165,14 @@ namespace {
*/
if (buf) {
Genode::memset(buf, 0, sizeof(struct stat));
- buf->st_mode = S_IFCHR;
+ if (Genode::strcmp(path, "/dev") == 0)
+ buf->st_mode = S_IFDIR;
+ else if (Genode::strcmp(path, _dev_name()) == 0)
+ buf->st_mode = S_IFCHR;
+ else {
+ errno = ENOENT;
+ return -1;
+ }
}
return 0;
}
diff --git a/libports/src/test/libc_ffat/main.cc b/libports/src/test/libc_ffat/main.cc
index 424ddd9cf1..56f71315c8 100644
--- a/libports/src/test/libc_ffat/main.cc
+++ b/libports/src/test/libc_ffat/main.cc
@@ -101,13 +101,13 @@ int main(int argc, char *argv[])
}
/* test 'pread()' and 'pwrite()' */
- CALL_AND_CHECK(fd, open(file_name2, O_CREAT | O_WRONLY), fd >= 0, "file_name=%s", file_name);
+ CALL_AND_CHECK(fd, open(file_name2, O_CREAT | O_WRONLY), fd >= 0, "file_name=%s", file_name2);
/* write "a single line of" */
CALL_AND_CHECK(count, pwrite(fd, pattern, (pattern_size - 6), 0), (size_t)count == (pattern_size - 6), "");
/* write "line of text" at offset 9 */
CALL_AND_CHECK(count, pwrite(fd, &pattern[9], (pattern_size - 9), 9), (size_t)count == (pattern_size - 9), "");
CALL_AND_CHECK(ret, close(fd), ret == 0, "");
- CALL_AND_CHECK(fd, open(file_name2, O_RDONLY), fd >= 0, "file_name=%s", file_name);
+ CALL_AND_CHECK(fd, open(file_name2, O_RDONLY), fd >= 0, "file_name=%s", file_name2);
memset(buf, 0, sizeof(buf));
/* read "single line of text" from offset 2 */
CALL_AND_CHECK(count, pread(fd, buf, sizeof(buf), 2), (size_t)count == (pattern_size - 2), "");
@@ -121,7 +121,7 @@ int main(int argc, char *argv[])
}
/* test 'readv()' and 'writev()' */
- CALL_AND_CHECK(fd, open(file_name3, O_CREAT | O_WRONLY), fd >= 0, "file_name=%s", file_name);
+ CALL_AND_CHECK(fd, open(file_name3, O_CREAT | O_WRONLY), fd >= 0, "file_name=%s", file_name3);
struct iovec iov[2];
/* write "a single line" */
iov[0].iov_base = (void*)pattern;
@@ -131,7 +131,7 @@ int main(int argc, char *argv[])
iov[1].iov_len = pattern_size - 8;
CALL_AND_CHECK(count, writev(fd, iov, 2), (size_t)count == (pattern_size + 5), "");
CALL_AND_CHECK(ret, close(fd), ret == 0, "");
- CALL_AND_CHECK(fd, open(file_name3, O_RDONLY), fd >= 0, "file_name=%s", file_name);
+ CALL_AND_CHECK(fd, open(file_name3, O_RDONLY), fd >= 0, "file_name=%s", file_name3);
memset(buf, 0, sizeof(buf));
/* read "a single line" */
iov[0].iov_base = buf;
@@ -187,6 +187,37 @@ int main(int argc, char *argv[])
(ret == 0) && (stat_buf.st_size == 0),
"file_name=%s", file_name4);
+ /* test 'fchdir()' */
+ CALL_AND_CHECK(ret, chdir("/"), ret == 0, "");
+ CALL_AND_CHECK(fd, open(dir_name, O_RDONLY), fd >= 0, "dir_name=%s", dir_name);
+ CALL_AND_CHECK(ret, fchdir(fd), ret == 0, "");
+ CALL_AND_CHECK(ret, close(fd), ret == 0, "");
+ CALL_AND_CHECK(ret, stat(file_name, &stat_buf), ret == 0, "file_name=%s", file_name);
+
+ /* test symbolic links */
+ if ((symlink("/", "/symlinks_supported") == 0) || (errno != ENOSYS)) {
+ CALL_AND_CHECK(ret, mkdir("/a", 0777), ((ret == 0) || (errno == EEXIST)), "dir_name=%s", "/a");
+ CALL_AND_CHECK(ret, mkdir("/c", 0777), ((ret == 0) || (errno == EEXIST)), "dir_name=%s", "/c");
+ CALL_AND_CHECK(ret, symlink("/a", "/c/d"),
+ ((ret == 0) || (errno == EEXIST)), "dir_name=%s", "/c/d");
+ CALL_AND_CHECK(ret, symlink("/c", "/e"), ((ret == 0) || (errno == EEXIST)), "dir_name=%s", "/e");
+
+ CALL_AND_CHECK(fd, open("/a/b", O_CREAT | O_WRONLY), fd >= 0, "file_name=%s", "/a/b");
+ CALL_AND_CHECK(count, write(fd, pattern, pattern_size), (size_t)count == pattern_size, "");
+ CALL_AND_CHECK(ret, close(fd), ret == 0, "");
+
+ CALL_AND_CHECK(fd, open("/e/d/b", O_RDONLY), fd >= 0, "file_name=%s", "/e/d/b");
+ CALL_AND_CHECK(count, read(fd, buf, sizeof(buf)), (size_t)count == pattern_size, "");
+ CALL_AND_CHECK(ret, close(fd), ret == 0, "");
+ printf("content of file: \"%s\"\n", buf);
+ if (strcmp(buf, pattern) != 0) {
+ printf("unexpected content of file\n");
+ return -1;
+ } else {
+ printf("file content is correct\n");
+ }
+ }
+
if (i < (iterations - 1))
sleep(2);
}
diff --git a/libports/src/test/libc_fs_tar_fs/main.cc b/libports/src/test/libc_fs_tar_fs/main.cc
index 04716a4674..b5a083b6bb 100644
--- a/libports/src/test/libc_fs_tar_fs/main.cc
+++ b/libports/src/test/libc_fs_tar_fs/main.cc
@@ -98,6 +98,18 @@ int main(int argc, char *argv[])
}
}
+ /* test symbolic links */
+ CALL_AND_CHECK(fd, open("/e/d/b", O_RDONLY), fd >= 0, "file_name=%s", "/e/d/b");
+ CALL_AND_CHECK(count, read(fd, buf, sizeof(buf)), (size_t)count == pattern_size, "");
+ CALL_AND_CHECK(ret, close(fd), ret == 0, "");
+ printf("content of file: \"%s\"\n", buf);
+ if (strcmp(buf, pattern) != 0) {
+ printf("unexpected content of file\n");
+ return -1;
+ } else {
+ printf("file content is correct\n");
+ }
+
if (i < (iterations - 1))
sleep(2);
}
diff --git a/os/include/os/path.h b/os/include/os/path.h
index b9ba16392b..7fdc57bb40 100644
--- a/os/include/os/path.h
+++ b/os/include/os/path.h
@@ -227,7 +227,7 @@ namespace Genode {
_import(path, pwd);
}
- void import(char const *path) { _import(path); }
+ void import(char const *path, char const *pwd = 0) { _import(path, pwd); }
char *base() { return _path; }
size_t max_len() { return _path_max_len; }
diff --git a/os/src/server/ram_fs/directory.h b/os/src/server/ram_fs/directory.h
index 592edcbfdd..1e9afea327 100644
--- a/os/src/server/ram_fs/directory.h
+++ b/os/src/server/ram_fs/directory.h
@@ -83,7 +83,8 @@ namespace File_system {
/* try to find entry that matches the first path element */
Node *sub_node = _entries.first();
for (; sub_node; sub_node = sub_node->next())
- if (strcmp(sub_node->name(), path, i) == 0)
+ if ((strlen(sub_node->name()) == i) &&
+ (strcmp(sub_node->name(), path, i) == 0))
break;
if (!sub_node)
@@ -141,6 +142,18 @@ namespace File_system {
throw Lookup_failed();
}
+ Symlink *lookup_and_lock_symlink(char const *path)
+ {
+ Node *node = lookup_and_lock(path);
+
+ Symlink *symlink = dynamic_cast(node);
+ if (symlink)
+ return symlink;
+
+ node->unlock();
+ throw Lookup_failed();
+ }
+
/**
* Lookup parent directory of the specified path
*
diff --git a/os/src/server/ram_fs/main.cc b/os/src/server/ram_fs/main.cc
index 415ca32448..8162887e33 100644
--- a/os/src/server/ram_fs/main.cc
+++ b/os/src/server/ram_fs/main.cc
@@ -261,9 +261,34 @@ namespace File_system {
return _handle_registry.alloc(file);
}
- Symlink_handle symlink(Dir_handle, Name const &name, bool create)
+ Symlink_handle symlink(Dir_handle dir_handle, Name const &name, bool create)
{
- return Symlink_handle(-1);
+ if (!valid_name(name.string()))
+ throw Invalid_name();
+
+ Directory *dir = _handle_registry.lookup_and_lock(dir_handle);
+ Node_lock_guard dir_guard(*dir);
+
+ if (create) {
+
+ if (!_writable)
+ throw Permission_denied();
+
+ if (dir->has_sub_node_unsynchronized(name.string()))
+ throw Node_already_exists();
+
+ try {
+ Symlink * const symlink = new (env()->heap())
+ Symlink(name.string());
+
+ dir->adopt_unsynchronized(symlink);
+ }
+ catch (Allocator::Out_of_memory) { throw No_space(); }
+ }
+
+ Symlink *symlink = dir->lookup_and_lock_symlink(name.string());
+ Node_lock_guard file_guard(*symlink);
+ return _handle_registry.alloc(symlink);
}
Dir_handle dir(Path const &path, bool create)
@@ -343,6 +368,7 @@ namespace File_system {
}
Symlink *symlink = dynamic_cast(node);
if (symlink) {
+ s.size = symlink->length();
s.mode = File_system::Status::MODE_SYMLINK;
return s;
}
diff --git a/os/src/server/ram_fs/symlink.h b/os/src/server/ram_fs/symlink.h
index 07dacd3850..c74164e9f7 100644
--- a/os/src/server/ram_fs/symlink.h
+++ b/os/src/server/ram_fs/symlink.h
@@ -16,21 +16,27 @@ namespace File_system {
{
private:
- Name _link_to;
+ char _link_to[MAX_PATH_LEN];
public:
+ Symlink(char const *name) { Node::name(name); }
+
size_t read(char *dst, size_t len, seek_off_t seek_offset)
{
- PDBG("not implemented");
- return 0;
+ size_t count = min(len, sizeof(_link_to) + 1);
+ Genode::strncpy(dst, _link_to, count);
+ return count;
}
size_t write(char const *src, size_t len, seek_off_t seek_offset)
{
- PDBG("not implemented");
- return 0;
+ size_t count = min(len, sizeof(_link_to) + 1);
+ Genode::strncpy(_link_to, src, count);
+ return count;
}
+
+ file_size_t length() const { return strlen(_link_to) + 1; }
};
}
diff --git a/os/src/server/tar_fs/main.cc b/os/src/server/tar_fs/main.cc
index dbe5d26a34..3c48570797 100644
--- a/os/src/server/tar_fs/main.cc
+++ b/os/src/server/tar_fs/main.cc
@@ -25,6 +25,7 @@
#include
#include
#include
+#include
#include
@@ -278,10 +279,45 @@ namespace File_system {
return _handle_registry.alloc(file_node);
}
- Symlink_handle symlink(Dir_handle, Name const &name, bool create)
+ Symlink_handle symlink(Dir_handle dir_handle, Name const &name, bool create)
{
- /* not supported */
- return Symlink_handle(-1);
+ PDBGV("_root = %s, dir_name = %s, name = %s, create = %d",
+ _root.record()->name(),
+ _handle_registry.lookup(dir_handle)->record()->name(),
+ name.string(),
+ create);
+
+ if (!valid_filename(name.string()))
+ throw Lookup_failed();
+
+ if (create)
+ throw Permission_denied();
+
+ Directory *dir = _handle_registry.lookup(dir_handle);
+
+ Absolute_path abs_path(dir->record()->name());
+ try {
+ abs_path.append("/");
+ abs_path.append(name.base());
+ } catch (Path_base::Path_too_long) {
+ throw Name_too_long();
+ }
+
+ PDBGV("abs_path = %s", abs_path.base());
+
+ Lookup_exact lookup_criterion(abs_path.base());
+ Record *record = _lookup(&lookup_criterion);
+
+ if (!record) {
+ PERR("Could not find record for %s", abs_path.base());
+ throw Lookup_failed();
+ }
+
+ if (record->type() != Record::TYPE_SYMLINK)
+ throw Lookup_failed();
+
+ Symlink *symlink_node = new (env()->heap()) Symlink(record);
+ return _handle_registry.alloc(symlink_node);
}
Dir_handle dir(Path const &path, bool create)
diff --git a/os/src/server/tar_fs/symlink.h b/os/src/server/tar_fs/symlink.h
new file mode 100644
index 0000000000..78a6a4f8f8
--- /dev/null
+++ b/os/src/server/tar_fs/symlink.h
@@ -0,0 +1,54 @@
+/*
+ * \brief TAR file-system symlink node
+ * \author Christian Prochaska
+ * \date 2012-08-24
+ */
+
+/*
+ * Copyright (C) 2012 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU General Public License version 2.
+ */
+
+#ifndef _SYMLINK_H_
+#define _SYMLINK_H_
+
+/* local includes */
+#include
+
+
+namespace File_system {
+
+ class Symlink : public Node
+ {
+ public:
+
+ Symlink(Record *record) : Node(record) { }
+
+ size_t read(char *dst, size_t len, seek_off_t seek_offset)
+ {
+ bool verbose = false;
+
+ if (verbose)
+ PDBG("len = %zu, seek_offset = %llu", len, seek_offset);
+
+ size_t count = min(len, (size_t)100);
+ memcpy(dst, _record->linked_name(), count);
+ return count;
+ }
+
+ size_t write(char const *src, size_t len, seek_off_t seek_offset)
+ {
+ bool verbose = false;
+
+ if (verbose)
+ PDBG("len = %zu, seek_offset = %llu", len, seek_offset);
+
+ return -1;
+ }
+
+ };
+}
+
+#endif /* _SYMLINK_H_ */
diff --git a/ports/include/noux_session/client.h b/ports/include/noux_session/client.h
index 7779799c93..5e87e3208a 100644
--- a/ports/include/noux_session/client.h
+++ b/ports/include/noux_session/client.h
@@ -34,9 +34,11 @@ namespace Noux {
bool syscall(Syscall sc)
{
+ static bool verbose = false;
+
bool result = call(sc);
- if (result == false)
+ if ((result == false) && verbose)
PERR("syscall %s failed", syscall_name(sc));
return result;
diff --git a/ports/include/noux_session/noux_session.h b/ports/include/noux_session/noux_session.h
index 31c96cfd57..b59e0455e0 100644
--- a/ports/include/noux_session/noux_session.h
+++ b/ports/include/noux_session/noux_session.h
@@ -34,7 +34,6 @@ namespace Noux {
virtual Dataspace_capability sysio_dataspace() = 0;
enum Syscall {
- SYSCALL_GETCWD,
SYSCALL_WRITE,
SYSCALL_READ,
SYSCALL_STAT,
@@ -47,7 +46,6 @@ namespace Noux {
SYSCALL_IOCTL,
SYSCALL_LSEEK,
SYSCALL_DIRENT,
- SYSCALL_FCHDIR,
SYSCALL_EXECVE,
SYSCALL_SELECT,
SYSCALL_FORK,
@@ -56,8 +54,10 @@ namespace Noux {
SYSCALL_PIPE,
SYSCALL_DUP2,
SYSCALL_UNLINK,
+ SYSCALL_READLINK,
SYSCALL_RENAME,
SYSCALL_MKDIR,
+ SYSCALL_SYMLINK,
SYSCALL_SOCKET,
SYSCALL_GETSOCKOPT,
SYSCALL_SETSOCKOPT,
@@ -78,7 +78,6 @@ namespace Noux {
static char const *syscall_name(Syscall sc)
{
switch (sc) {
- NOUX_DECL_SYSCALL_NAME(GETCWD)
NOUX_DECL_SYSCALL_NAME(WRITE)
NOUX_DECL_SYSCALL_NAME(READ)
NOUX_DECL_SYSCALL_NAME(STAT)
@@ -91,7 +90,6 @@ namespace Noux {
NOUX_DECL_SYSCALL_NAME(IOCTL)
NOUX_DECL_SYSCALL_NAME(LSEEK)
NOUX_DECL_SYSCALL_NAME(DIRENT)
- NOUX_DECL_SYSCALL_NAME(FCHDIR)
NOUX_DECL_SYSCALL_NAME(EXECVE)
NOUX_DECL_SYSCALL_NAME(SELECT)
NOUX_DECL_SYSCALL_NAME(FORK)
@@ -100,8 +98,10 @@ namespace Noux {
NOUX_DECL_SYSCALL_NAME(PIPE)
NOUX_DECL_SYSCALL_NAME(DUP2)
NOUX_DECL_SYSCALL_NAME(UNLINK)
+ NOUX_DECL_SYSCALL_NAME(READLINK)
NOUX_DECL_SYSCALL_NAME(RENAME)
NOUX_DECL_SYSCALL_NAME(MKDIR)
+ NOUX_DECL_SYSCALL_NAME(SYMLINK)
NOUX_DECL_SYSCALL_NAME(SOCKET)
NOUX_DECL_SYSCALL_NAME(GETSOCKOPT)
NOUX_DECL_SYSCALL_NAME(SETSOCKOPT)
diff --git a/ports/include/noux_session/sysio.h b/ports/include/noux_session/sysio.h
index 1cdd65d5fb..82deebd345 100644
--- a/ports/include/noux_session/sysio.h
+++ b/ports/include/noux_session/sysio.h
@@ -286,18 +286,20 @@ namespace Noux {
enum General_error { ERR_FD_INVALID, NUM_GENERAL_ERRORS };
enum Stat_error { STAT_ERR_NO_ENTRY = NUM_GENERAL_ERRORS };
- enum Fchdir_error { FCHDIR_ERR_NOT_DIR = NUM_GENERAL_ERRORS };
enum Fcntl_error { FCNTL_ERR_CMD_INVALID = NUM_GENERAL_ERRORS };
enum Ftruncate_error { FTRUNCATE_ERR_NO_PERM = NUM_GENERAL_ERRORS };
enum Open_error { OPEN_ERR_UNACCESSIBLE, OPEN_ERR_NO_PERM,
OPEN_ERR_EXISTS };
enum Execve_error { EXECVE_NONEXISTENT = NUM_GENERAL_ERRORS };
enum Unlink_error { UNLINK_ERR_NO_ENTRY, UNLINK_ERR_NO_PERM };
+ enum Readlink_error { READLINK_ERR_NO_ENTRY };
enum Rename_error { RENAME_ERR_NO_ENTRY, RENAME_ERR_CROSS_FS,
RENAME_ERR_NO_PERM };
enum Mkdir_error { MKDIR_ERR_EXISTS, MKDIR_ERR_NO_ENTRY,
MKDIR_ERR_NO_SPACE, MKDIR_ERR_NO_PERM,
MKDIR_ERR_NAME_TOO_LONG};
+ enum Symlink_error { SYMLINK_ERR_EXISTS, SYMLINK_ERR_NO_ENTRY,
+ SYMLINK_ERR_NAME_TOO_LONG};
enum Read_error { READ_ERR_AGAIN, READ_ERR_WOULD_BLOCK,
READ_ERR_INVALID, READ_ERR_IO };
@@ -338,14 +340,15 @@ namespace Noux {
union {
General_error general;
Stat_error stat;
- Fchdir_error fchdir;
Fcntl_error fcntl;
Ftruncate_error ftruncate;
Open_error open;
Execve_error execve;
Unlink_error unlink;
+ Readlink_error readlink;
Rename_error rename;
Mkdir_error mkdir;
+ Symlink_error symlink;
Read_error read;
Write_error write;
Accept_error accept;
@@ -360,13 +363,13 @@ namespace Noux {
union {
- SYSIO_DECL(getcwd, { }, { Path path; });
-
SYSIO_DECL(write, { int fd; size_t count; Chunk chunk; },
{ size_t count; });
SYSIO_DECL(stat, { Path path; }, { Stat st; });
+ SYSIO_DECL(symlink, { Path oldpath; Path newpath; }, { });
+
SYSIO_DECL(fstat, { int fd; }, { Stat st; });
SYSIO_DECL(ftruncate, { int fd; off_t length; }, { });
@@ -385,11 +388,12 @@ namespace Noux {
SYSIO_DECL(dirent, { int fd; }, { Dirent entry; });
- SYSIO_DECL(fchdir, { int fd; }, { });
-
SYSIO_DECL(read, { int fd; size_t count; },
{ Chunk chunk; size_t count; });
+ SYSIO_DECL(readlink, { Path path; size_t bufsiz; },
+ { Chunk chunk; ssize_t count; });
+
SYSIO_DECL(execve, { Path filename; Args args; Env env; }, { });
SYSIO_DECL(select, { Select_fds fds; Select_timeout timeout; },
diff --git a/ports/run/noux_gdb.run b/ports/run/noux_gdb.run
index dae672968e..9a0252c765 100644
--- a/ports/run/noux_gdb.run
+++ b/ports/run/noux_gdb.run
@@ -51,13 +51,20 @@ foreach test_binary $test_binaries {
}
# tar archive for the source code of the GDB monitor test
+# currently, directories need to have their own tar records
+exec mkdir -p bin/test-gdb_monitor-src
foreach test_binary $test_binaries {
set source_files [ exec [cross_dev_prefix]objdump -dl bin/$test_binary | grep "^/.*:.*" | sed -e "s/:.*//" | uniq ]
foreach source_file $source_files {
- if [file exists $source_file] { exec tar ufvhP bin/test-gdb_monitor-src.tar $source_file }
+ if [file exists $source_file] {
+ set dirname [ exec dirname $source_file]
+ exec mkdir -p bin/test-gdb_monitor-src$dirname
+ exec ln -sf $source_file bin/test-gdb_monitor-src$source_file
+ }
}
}
+exec tar chf bin/test-gdb_monitor-src.tar -C bin/test-gdb_monitor-src .
create_boot_directory
diff --git a/ports/src/lib/libc_noux/plugin.cc b/ports/src/lib/libc_noux/plugin.cc
index d7df5ee851..5c54dd30e1 100644
--- a/ports/src/lib/libc_noux/plugin.cc
+++ b/ports/src/lib/libc_noux/plugin.cc
@@ -176,19 +176,6 @@ extern "C" uid_t geteuid()
}
-extern "C" int __getcwd(char *dst, Genode::size_t dst_size)
-{
- noux()->syscall(Noux::Session::SYSCALL_GETCWD);
- Genode::size_t path_size = Genode::strlen(sysio()->getcwd_out.path);
-
- if (dst_size < path_size + 1)
- return -ERANGE;
-
- Genode::strncpy(dst, sysio()->getcwd_out.path, dst_size);
- return 0;
-}
-
-
/**
* Utility to copy-out syscall results to buf struct
*
@@ -208,31 +195,6 @@ static void _sysio_to_stat_struct(Noux::Sysio const *sysio, struct stat *buf)
}
-static int _stat(char const *path, struct stat *buf, bool lstat = false)
-{
- if ((path == NULL) or (buf == NULL)) {
- errno = EFAULT;
- return -1;
- }
-
- Genode::strncpy(sysio()->stat_in.path, path, sizeof(sysio()->stat_in.path));
-
- if (!noux()->syscall(Noux::Session::SYSCALL_STAT)) {
- PWRN("stat syscall failed for path \"%s\"", path);
- switch (sysio()->error.stat) {
- case Noux::Sysio::STAT_ERR_NO_ENTRY: errno = ENOENT; break;
- }
- return -1;
- }
-
- _sysio_to_stat_struct(sysio(), buf);
- return 0;
-}
-
-
-extern "C" int lstat(char const *path, struct stat *buf) { return _stat(path, buf, true); }
-
-
static bool serialize_string_array(char const * const * array, char *dst, Genode::size_t dst_len)
{
for (unsigned i = 0; array[i]; i++)
@@ -251,61 +213,6 @@ static bool serialize_string_array(char const * const * array, char *dst, Genode
}
-extern "C" int execve(char const *filename, char *const argv[],
- char *const envp[])
-{
- if (verbose) {
- PDBG("filename=%s", filename);
-
- for (int i = 0; argv[i]; i++)
- PDBG("argv[%d]='%s'", i, argv[i]);
-
- for (int i = 0; envp[i]; i++)
- PDBG("envp[%d]='%s'", i, envp[i]);
- }
-
- Genode::strncpy(sysio()->execve_in.filename, filename, sizeof(sysio()->execve_in.filename));
- if (!serialize_string_array(argv, sysio()->execve_in.args,
- sizeof(sysio()->execve_in.args))) {
- PERR("execve: argument buffer exceeded");
- errno = E2BIG;
- return -1;
- }
-
- if (!serialize_string_array(envp, sysio()->execve_in.env,
- sizeof(sysio()->execve_in.env))) {
- PERR("execve: environment buffer exceeded");
- errno = E2BIG;
- return -1;
- }
-
- if (!noux()->syscall(Noux::Session::SYSCALL_EXECVE)) {
- PWRN("exec syscall failed for path \"%s\"", filename);
- switch (sysio()->error.execve) {
- case Noux::Sysio::EXECVE_NONEXISTENT: errno = ENOENT; break;
- }
- return -1;
- }
-
- /*
- * In the success case, we never return from execve, the execution is
- * resumed in the new program.
- */
- Genode::sleep_forever();
- return 0;
-}
-
-
-/**
- * Called by execvp
- */
-extern "C" int _execve(char const *filename, char *const argv[],
- char *const envp[])
-{
- return execve(filename, argv, envp);
-}
-
-
/**
* Return number of marhalled file descriptors into select argument buffer
*
@@ -640,20 +547,25 @@ namespace {
_stderr(Libc::file_descriptor_allocator()->alloc(this, noux_context(2), 2))
{ }
- bool supports_chdir(char const *) { return true; }
- bool supports_open(char const *, int) { return true; }
- bool supports_stat(char const *) { return true; }
- bool supports_pipe() { return true; }
- bool supports_unlink(char const *) { return true; }
- bool supports_rename(const char *, const char *) { return true; }
- bool supports_mkdir(const char *, mode_t) { return true; }
- bool supports_socket(int, int, int) { return true; }
- bool supports_mmap() { return true; }
+ bool supports_execve(char const *, char *const[],
+ char *const[]) { return true; }
+ bool supports_open(char const *, int) { return true; }
+ bool supports_stat(char const *) { return true; }
+ bool supports_symlink(char const *, char const*) { return true; }
+ bool supports_pipe() { return true; }
+ bool supports_unlink(char const *) { return true; }
+ bool supports_readlink(const char *, char *, size_t) { return true; }
+ bool supports_rename(const char *, const char *) { return true; }
+ bool supports_mkdir(const char *, mode_t) { return true; }
+ bool supports_socket(int, int, int) { return true; }
+ bool supports_mmap() { return true; }
Libc::File_descriptor *open(char const *, int);
ssize_t write(Libc::File_descriptor *, const void *, ::size_t);
int close(Libc::File_descriptor *);
int dup2(Libc::File_descriptor *, Libc::File_descriptor *);
+ int execve(char const *filename, char *const argv[],
+ char *const envp[]);
int fstat(Libc::File_descriptor *, struct stat *);
int fsync(Libc::File_descriptor *);
int fstatfs(Libc::File_descriptor *, struct statfs *);
@@ -661,9 +573,10 @@ namespace {
int fcntl(Libc::File_descriptor *, int, long);
ssize_t getdirentries(Libc::File_descriptor *, char *, ::size_t, ::off_t *);
::off_t lseek(Libc::File_descriptor *, ::off_t offset, int whence);
- int fchdir(Libc::File_descriptor *);
ssize_t read(Libc::File_descriptor *, void *, ::size_t);
+ ssize_t readlink(const char *path, char *buf, size_t bufsiz);
int stat(char const *, struct stat *);
+ int symlink(const char *, const char *);
int ioctl(Libc::File_descriptor *, int request, char *argp);
int pipe(Libc::File_descriptor *pipefd[2]);
int unlink(char const *path);
@@ -699,9 +612,89 @@ namespace {
};
+ int Plugin::execve(char const *filename, char *const argv[],
+ char *const envp[])
+ {
+ if (verbose) {
+ PDBG("filename=%s", filename);
+
+ for (int i = 0; argv[i]; i++)
+ PDBG("argv[%d]='%s'", i, argv[i]);
+
+ for (int i = 0; envp[i]; i++)
+ PDBG("envp[%d]='%s'", i, envp[i]);
+ }
+
+ Genode::strncpy(sysio()->execve_in.filename, filename, sizeof(sysio()->execve_in.filename));
+ if (!serialize_string_array(argv, sysio()->execve_in.args,
+ sizeof(sysio()->execve_in.args))) {
+ PERR("execve: argument buffer exceeded");
+ errno = E2BIG;
+ return -1;
+ }
+
+ /* communicate the current working directory as environment variable */
+
+ size_t noux_cwd_len = Genode::snprintf(sysio()->execve_in.env,
+ sizeof(sysio()->execve_in.env),
+ "NOUX_CWD=");
+
+ if (!getcwd(&(sysio()->execve_in.env[noux_cwd_len]),
+ sizeof(sysio()->execve_in.env) - noux_cwd_len)) {
+ PERR("execve: environment buffer exceeded");
+ errno = E2BIG;
+ return -1;
+ }
+
+ noux_cwd_len = strlen(sysio()->execve_in.env) + 1;
+
+ if (!serialize_string_array(envp, &(sysio()->execve_in.env[noux_cwd_len]),
+ sizeof(sysio()->execve_in.env) - noux_cwd_len)) {
+ PERR("execve: environment buffer exceeded");
+ errno = E2BIG;
+ return -1;
+ }
+
+ if (!noux()->syscall(Noux::Session::SYSCALL_EXECVE)) {
+ PWRN("exec syscall failed for path \"%s\"", filename);
+ switch (sysio()->error.execve) {
+ case Noux::Sysio::EXECVE_NONEXISTENT: errno = ENOENT; break;
+ }
+ return -1;
+ }
+
+ /*
+ * In the success case, we never return from execve, the execution is
+ * resumed in the new program.
+ */
+ Genode::sleep_forever();
+ return 0;
+ }
+
+
int Plugin::stat(char const *path, struct stat *buf)
{
- return _stat(path, buf, false);
+ if (verbose)
+ PDBG("path = %s", path);
+
+ if ((path == NULL) or (buf == NULL)) {
+ errno = EFAULT;
+ return -1;
+ }
+
+ Genode::strncpy(sysio()->stat_in.path, path, sizeof(sysio()->stat_in.path));
+
+ if (!noux()->syscall(Noux::Session::SYSCALL_STAT)) {
+ if (verbose)
+ PWRN("stat syscall failed for path \"%s\"", path);
+ switch (sysio()->error.stat) {
+ case Noux::Sysio::STAT_ERR_NO_ENTRY: errno = ENOENT; break;
+ }
+ return -1;
+ }
+
+ _sysio_to_stat_struct(sysio(), buf);
+ return 0;
}
@@ -755,6 +748,30 @@ namespace {
}
+ int Plugin::symlink(const char *oldpath, const char *newpath)
+ {
+ if (verbose)
+ PDBG("%s -> %s", newpath, oldpath);
+
+ if ((Genode::strlen(oldpath) + 1 > sizeof(sysio()->symlink_in.oldpath)) ||
+ (Genode::strlen(newpath) + 1 > sizeof(sysio()->symlink_in.newpath))) {
+ PDBG("ENAMETOOLONG");
+ errno = ENAMETOOLONG;
+ return 0;
+ }
+
+ Genode::strncpy(sysio()->symlink_in.oldpath, oldpath, sizeof(sysio()->symlink_in.oldpath));
+ Genode::strncpy(sysio()->symlink_in.newpath, newpath, sizeof(sysio()->symlink_in.newpath));
+ if (!noux()->syscall(Noux::Session::SYSCALL_SYMLINK)) {
+ PERR("symlink error");
+ /* XXX set errno */
+ return -1;
+ }
+
+ return 0;
+ }
+
+
int Plugin::fstatfs(Libc::File_descriptor *, struct statfs *buf)
{
buf->f_flags = MNT_UNION;
@@ -1027,8 +1044,7 @@ namespace {
*/
Libc::File_descriptor *new_fd =
Libc::file_descriptor_allocator()->alloc(this, 0);
-
- new_fd->context = noux_context(new_fd->libc_fd);
+ new_fd->path(fd->fd_path);
/*
* Use new allocated number as name of file descriptor
@@ -1163,21 +1179,6 @@ namespace {
}
- int Plugin::fchdir(Libc::File_descriptor *fd)
- {
- sysio()->fchdir_in.fd = noux_fd(fd->context);
- if (!noux()->syscall(Noux::Session::SYSCALL_FCHDIR)) {
- switch (sysio()->error.fchdir) {
- case Noux::Sysio::FCHDIR_ERR_NOT_DIR: errno = ENOTDIR; break;
- default: errno = EPERM; break;
- }
- return -1;
- }
-
- return 0;
- }
-
-
int Plugin::unlink(char const *path)
{
Genode::strncpy(sysio()->unlink_in.path, path, sizeof(sysio()->unlink_in.path));
@@ -1195,6 +1196,31 @@ namespace {
}
+ ssize_t Plugin::readlink(const char *path, char *buf, size_t bufsiz)
+ {
+ if (verbose)
+ PDBG("path = %s, bufsiz = %zu", path, bufsiz);
+
+ Genode::strncpy(sysio()->readlink_in.path, path, sizeof(sysio()->readlink_in.path));
+ sysio()->readlink_in.bufsiz = bufsiz;
+
+ if (!noux()->syscall(Noux::Session::SYSCALL_READLINK)) {
+ PWRN("readlink syscall failed for \"%s\"", path);
+ /* XXX set errno */
+ return -1;
+ }
+
+ ssize_t size = Genode::min((size_t)sysio()->readlink_out.count, bufsiz);
+
+ Genode::memcpy(buf, sysio()->readlink_out.chunk, size);
+
+ if (verbose)
+ PDBG("result = %s", buf);
+
+ return size;
+ }
+
+
int Plugin::rename(char const *from_path, char const *to_path)
{
Genode::strncpy(sysio()->rename_in.from_path, from_path, sizeof(sysio()->rename_in.from_path));
@@ -1706,8 +1732,15 @@ void init_libc_noux(void)
unsigned num_entries = 0; /* index within 'env_array' */
+ static Libc::Absolute_path noux_cwd("/");
+
while (*env_string && (num_entries < ENV_MAX_ENTRIES - 1)) {
- env_array[num_entries++] = env_string;
+ if ((strlen(env_string) >= strlen("NOUX_CWD=")) &&
+ (strncmp(env_string, "NOUX_CWD=", strlen("NOUX_CWD=")) == 0)) {
+ noux_cwd.import(&env_string[strlen("NOUX_CWD=")]);
+ } else {
+ env_array[num_entries++] = env_string;
+ }
env_string += (strlen(env_string) + 1);
}
env_array[num_entries] = 0;
@@ -1720,6 +1753,8 @@ void init_libc_noux(void)
/* initialize noux libc plugin */
static Plugin noux_plugin;
+
+ chdir(noux_cwd.base());
}
diff --git a/ports/src/noux/child.h b/ports/src/noux/child.h
index 8932b72695..0c038b2500 100644
--- a/ports/src/noux/child.h
+++ b/ports/src/noux/child.h
@@ -296,7 +296,6 @@ namespace Noux {
Dir_file_system *root_dir,
Args const &args,
Sysio::Env const &env,
- char const *pwd,
Cap_session *cap_session,
Service_registry &parent_services,
Rpc_entrypoint &resources_ep,
@@ -329,7 +328,6 @@ namespace Noux {
_child(_binary_ds, _resources.ram.cap(), _resources.cpu.cap(),
_resources.rm.cap(), &_entrypoint, &_child_policy)
{
- _env.pwd(pwd);
_args.dump();
if (!forked && !_binary_ds.valid()) {
diff --git a/ports/src/noux/dir_file_system.h b/ports/src/noux/dir_file_system.h
index a0e63e003d..72b665b906 100644
--- a/ports/src/noux/dir_file_system.h
+++ b/ports/src/noux/dir_file_system.h
@@ -466,6 +466,39 @@ namespace Noux {
return false;
}
+ bool readlink(Sysio *sysio, char const *path)
+ {
+ path = _sub_path(path);
+
+ sysio->error.readlink = Sysio::READLINK_ERR_NO_ENTRY;
+
+ /* path does not match directory name */
+ if (!path) {
+ return false;
+ }
+
+ /* path refers to any of our sub file systems */
+ for (File_system *fs = _first_file_system; fs; fs = fs->next) {
+ if (fs->readlink(sysio, path)) {
+ return true;
+ } else {
+ /*
+ * Keep the most meaningful error code. When using
+ * stacked file systems, most child file systems will
+ * eventually return 'READLINK_ERR_NO_ENTRY' (or leave
+ * the error code unchanged). If any of those file
+ * systems has anything more interesting to tell,
+ * return this information.
+ */
+ if (sysio->error.readlink != Sysio::READLINK_ERR_NO_ENTRY)
+ return false;
+ }
+ }
+
+ /* none of our file systems could read the link */
+ return false;
+ }
+
bool rename(Sysio *sysio, char const *from_path, char const *to_path)
{
from_path = _sub_path(from_path);
@@ -518,6 +551,48 @@ namespace Noux {
return false;
}
+ bool symlink(Sysio *sysio, char const *path)
+ {
+ path = _sub_path(path);
+
+ sysio->error.symlink = Sysio::SYMLINK_ERR_NO_ENTRY;
+
+ /* path does not match directory name */
+ if (!path) {
+ return false;
+ }
+
+ /*
+ * Prevent symlink of path that equals directory name defined
+ * via the static fstab configuration.
+ */
+ if (strlen(path) == 0) {
+ sysio->error.symlink = Sysio::SYMLINK_ERR_EXISTS;
+ return false;
+ }
+
+ /* path refers to any of our sub file systems */
+ for (File_system *fs = _first_file_system; fs; fs = fs->next) {
+ if (fs->symlink(sysio, path)) {
+ return true;
+ } else {
+ /*
+ * Keep the most meaningful error code. When using
+ * stacked file systems, most child file systems will
+ * eventually return 'SYMLINK_ERR_NO_ENTRY' (or leave
+ * the error code unchanged). If any of those file
+ * systems has anything more interesting to tell,
+ * return this information.
+ */
+ if (sysio->error.symlink != Sysio::SYMLINK_ERR_NO_ENTRY)
+ return false;
+ }
+ }
+
+ /* none of our file systems could create the symlink */
+ return false;
+ }
+
bool mkdir(Sysio *sysio, char const *path)
{
path = _sub_path(path);
diff --git a/ports/src/noux/directory_service.h b/ports/src/noux/directory_service.h
index 62771340e4..bfee517c5d 100644
--- a/ports/src/noux/directory_service.h
+++ b/ports/src/noux/directory_service.h
@@ -34,12 +34,14 @@ namespace Noux {
virtual Vfs_handle *open(Sysio *sysio, char const *path) = 0;
- virtual bool stat(Sysio *sysio, char const *path) = 0;
- virtual bool dirent(Sysio *sysio, char const *path, off_t index) = 0;
- virtual bool unlink(Sysio *sysio, char const *path) = 0;
- virtual bool rename(Sysio *sysio, char const *from_path,
+ virtual bool stat(Sysio *sysio, char const *path) = 0;
+ virtual bool dirent(Sysio *sysio, char const *path, off_t index) = 0;
+ virtual bool unlink(Sysio *sysio, char const *path) = 0;
+ virtual bool readlink(Sysio *sysio, char const *path) = 0;
+ virtual bool rename(Sysio *sysio, char const *from_path,
char const *to_path) = 0;
- virtual bool mkdir(Sysio *sysio, char const *path) = 0;
+ virtual bool mkdir(Sysio *sysio, char const *path) = 0;
+ virtual bool symlink(Sysio *sysio, char const *path) = 0;
/**
* Return number of directory entries located at given path
diff --git a/ports/src/noux/environment.h b/ports/src/noux/environment.h
index 7c06b984f5..25920ffee8 100644
--- a/ports/src/noux/environment.h
+++ b/ports/src/noux/environment.h
@@ -13,28 +13,20 @@
/* Genode includes */
#include
-#include
#include
#include
/* Noux includes */
#include
-#include
-#include
namespace Noux {
- /**
- * Front-end for PWD environment variable
- */
- class Environment : private Attached_ram_dataspace, public Pwd
+ class Environment : private Attached_ram_dataspace
{
private:
Sysio::Env *_env;
- Pwd::Path _pwd_path;
-
public:
/**
@@ -53,19 +45,5 @@ namespace Noux {
* Return list of environment variables as zero-separated list
*/
Sysio::Env const &env() { return *_env; }
-
-
- /*******************
- ** Pwd interface **
- *******************/
-
- char const *pwd() { return _pwd_path.base(); }
-
- void pwd(char const *pwd)
- {
- _pwd_path.import(pwd);
- _pwd_path.remove_trailing('/');
- PINF("changed current work directory to %s", _pwd_path.base());
- }
};
}
diff --git a/ports/src/noux/fs_file_system.h b/ports/src/noux/fs_file_system.h
index ef3cdf1fc8..b05007afde 100644
--- a/ports/src/noux/fs_file_system.h
+++ b/ports/src/noux/fs_file_system.h
@@ -26,6 +26,8 @@ namespace Noux {
class Fs_file_system : public File_system
{
+ enum { verbose = false };
+
private:
Lock _lock;
@@ -84,6 +86,70 @@ namespace Noux {
~Fs_handle_guard() { _fs.close(_handle); }
};
+ size_t _read(::File_system::Node_handle node_handle, void *buf,
+ size_t count, size_t seek_offset)
+ {
+ ::File_system::Session::Tx::Source &source = *_fs.tx();
+
+ size_t const max_packet_size = source.bulk_buffer_size() / 2;
+ count = min(max_packet_size, count);
+
+ ::File_system::Packet_descriptor
+ packet(source.alloc_packet(count),
+ 0,
+ node_handle,
+ ::File_system::Packet_descriptor::READ,
+ count,
+ seek_offset);
+
+ /* pass packet to server side */
+ source.submit_packet(packet);
+ source.get_acked_packet();
+
+ memcpy(buf, source.packet_content(packet), count);
+
+ /*
+ * XXX check if acked packet belongs to request,
+ * needed for thread safety
+ */
+
+ source.release_packet(packet);
+
+ return count;
+ }
+
+ size_t _write(::File_system::Node_handle node_handle,
+ const char *buf, size_t count, size_t seek_offset)
+ {
+ ::File_system::Session::Tx::Source &source = *_fs.tx();
+
+ size_t const max_packet_size = source.bulk_buffer_size() / 2;
+ count = min(max_packet_size, count);
+
+ ::File_system::Packet_descriptor
+ packet(source.alloc_packet(count),
+ 0,
+ node_handle,
+ ::File_system::Packet_descriptor::WRITE,
+ count,
+ seek_offset);
+
+ memcpy(source.packet_content(packet), buf, count);
+
+ /* pass packet to server side */
+ source.submit_packet(packet);
+ source.get_acked_packet();
+
+ /*
+ * XXX check if acked packet belongs to request,
+ * needed for thread safety
+ */
+
+ source.release_packet(packet);
+
+ return count;
+ }
+
public:
/*
@@ -185,7 +251,8 @@ namespace Noux {
Fs_handle_guard node_guard(_fs, node);
status = _fs.status(node);
} catch (...) {
- PWRN("stat failed for path '%s'", path);
+ if (verbose)
+ PDBG("stat failed for path '%s'", path);
return false;
}
@@ -284,6 +351,40 @@ namespace Noux {
return true;
}
+ bool readlink(Sysio *sysio, char const *path)
+ {
+ /*
+ * Canonicalize path (i.e., path must start with '/')
+ */
+ Absolute_path abs_path(path);
+ abs_path.strip_last_element();
+
+ Absolute_path symlink_name(path);
+ symlink_name.keep_only_last_element();
+
+ Sysio::Readlink_error error = Sysio::READLINK_ERR_NO_ENTRY;
+ try {
+ ::File_system::Dir_handle dir_handle = _fs.dir(abs_path.base(), false);
+ Fs_handle_guard from_dir_guard(_fs, dir_handle);
+
+ ::File_system::Symlink_handle symlink_handle =
+ _fs.symlink(dir_handle, symlink_name.base() + 1, false);
+ Fs_handle_guard symlink_guard(_fs, symlink_handle);
+
+ sysio->readlink_out.count = _read(symlink_handle,
+ sysio->readlink_out.chunk,
+ min(sysio->readlink_in.bufsiz,
+ sizeof(sysio->readlink_out.chunk)),
+ 0);
+
+ return true;
+ } catch (...) { }
+
+ sysio->error.readlink = error;
+
+ return false;
+ }
+
bool rename(Sysio *sysio, char const *from_path, char const *to_path)
{
Absolute_path from_dir_path(from_path);
@@ -337,6 +438,40 @@ namespace Noux {
return false;
}
+ bool symlink(Sysio *sysio, char const *path)
+ {
+ /*
+ * Canonicalize path (i.e., path must start with '/')
+ */
+ Absolute_path abs_path(path);
+ abs_path.strip_last_element();
+
+ Absolute_path symlink_name(path);
+ symlink_name.keep_only_last_element();
+
+ Sysio::Symlink_error error = Sysio::SYMLINK_ERR_NO_ENTRY;
+ try {
+ ::File_system::Dir_handle dir_handle = _fs.dir(abs_path.base(), false);
+ Fs_handle_guard from_dir_guard(_fs, dir_handle);
+
+ ::File_system::Symlink_handle symlink_handle =
+ _fs.symlink(dir_handle, symlink_name.base() + 1, true);
+ Fs_handle_guard symlink_guard(_fs, symlink_handle);
+
+ _write(symlink_handle, sysio->symlink_in.oldpath,
+ strlen(sysio->symlink_in.oldpath) + 1, 0);
+ return true;
+ }
+ catch (::File_system::Invalid_handle) { error = Sysio::SYMLINK_ERR_NO_ENTRY; }
+ catch (::File_system::Node_already_exists) { error = Sysio::SYMLINK_ERR_EXISTS; }
+ catch (::File_system::Invalid_name) { error = Sysio::SYMLINK_ERR_NAME_TOO_LONG; }
+ catch (::File_system::Lookup_failed) { error = Sysio::SYMLINK_ERR_NO_ENTRY; }
+
+ sysio->error.symlink = error;
+
+ return false;
+ }
+
size_t num_dirent(char const *path)
{
if (strcmp(path, "") == 0)
@@ -401,7 +536,8 @@ namespace Noux {
bool const create = sysio->open_in.mode & Sysio::OPEN_MODE_CREATE;
if (create)
- PDBG("creation of file %s requested", file_name.base() + 1);
+ if (verbose)
+ PDBG("creation of file %s requested", file_name.base() + 1);
Sysio::Open_error error = Sysio::OPEN_ERR_UNACCESSIBLE;
@@ -443,35 +579,12 @@ namespace Noux {
{
Fs_vfs_handle const *handle = static_cast(vfs_handle);
- ::File_system::Session::Tx::Source &source = *_fs.tx();
+ size_t const count = min(sizeof(sysio->write_in.chunk),
+ sysio->write_in.count);
- size_t const max_packet_size = source.bulk_buffer_size() / 2;
- size_t const count = min(max_packet_size,
- min(sizeof(sysio->write_in.chunk),
- sysio->write_in.count));
-
- ::File_system::Packet_descriptor
- packet(source.alloc_packet(count),
- 0,
- handle->file_handle(),
- ::File_system::Packet_descriptor::WRITE,
- count,
- handle->seek());
-
- memcpy(source.packet_content(packet), sysio->write_in.chunk, count);
-
- /* pass packet to server side */
- source.submit_packet(packet);
- source.get_acked_packet();
-
- sysio->write_out.count = count;
-
- /*
- * XXX check if acked packet belongs to request,
- * needed for thread safety
- */
-
- source.release_packet(packet);
+ sysio->write_out.count = _write(handle->file_handle(),
+ sysio->write_in.chunk, count,
+ handle->seek());
return true;
}
@@ -486,36 +599,14 @@ namespace Noux {
size_t const file_bytes_left = file_size >= handle->seek()
? file_size - handle->seek() : 0;
- ::File_system::Session::Tx::Source &source = *_fs.tx();
+ size_t const count = min(file_bytes_left,
+ min(sizeof(sysio->read_out.chunk),
+ sysio->read_in.count));
- size_t const max_packet_size = source.bulk_buffer_size() / 2;
- size_t const count = min(max_packet_size,
- min(file_bytes_left,
- min(sizeof(sysio->read_out.chunk),
- sysio->read_in.count)));
+ sysio->read_out.count = _read(handle->file_handle(),
+ sysio->read_out.chunk,
+ count, handle->seek());
- ::File_system::Packet_descriptor
- packet(source.alloc_packet(count),
- 0,
- handle->file_handle(),
- ::File_system::Packet_descriptor::READ,
- count,
- handle->seek());
-
- /* pass packet to server side */
- source.submit_packet(packet);
- source.get_acked_packet();
-
- memcpy(sysio->read_out.chunk, source.packet_content(packet), count);
-
- sysio->read_out.count = count;
-
- /*
- * XXX check if acked packet belongs to request,
- * needed for thread safety
- */
-
- source.release_packet(packet);
return true;
}
diff --git a/ports/src/noux/io_channel.h b/ports/src/noux/io_channel.h
index c947eab449..db2820579c 100644
--- a/ports/src/noux/io_channel.h
+++ b/ports/src/noux/io_channel.h
@@ -22,7 +22,6 @@
/* Noux includes */
#include
-#include
#include
#include
@@ -55,7 +54,6 @@ namespace Noux {
virtual bool fstat(Sysio *sysio) { return false; }
virtual bool ftruncate(Sysio *sysio) { return false; }
virtual bool fcntl(Sysio *sysio) { return false; }
- virtual bool fchdir(Sysio *sysio, Pwd *pwd) { return false; }
virtual bool dirent(Sysio *sysio) { return false; }
virtual bool ioctl(Sysio *sysio) { return false; }
virtual bool lseek(Sysio *sysio) { return false; }
diff --git a/ports/src/noux/main.cc b/ports/src/noux/main.cc
index 2bf9fe0f35..37db82b2e1 100644
--- a/ports/src/noux/main.cc
+++ b/ports/src/noux/main.cc
@@ -127,12 +127,6 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
try {
switch (sc) {
- case SYSCALL_GETCWD:
-
- Genode::strncpy(_sysio->getcwd_out.path, _env.pwd(),
- sizeof(_sysio->getcwd_out.path));
- return true;
-
case SYSCALL_WRITE:
{
size_t const count_in = _sysio->write_in.count;
@@ -178,8 +172,7 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
case SYSCALL_STAT:
case SYSCALL_LSTAT: /* XXX implement difference between 'lstat' and 'stat' */
{
- bool result = _root_dir->stat(_sysio, Absolute_path(_sysio->stat_in.path,
- _env.pwd()).base());
+ bool result = _root_dir->stat(_sysio, _sysio->stat_in.path);
/**
* Instead of using the uid/gid given by the actual file system
@@ -211,13 +204,11 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
case SYSCALL_OPEN:
{
- Absolute_path absolute_path(_sysio->open_in.path, _env.pwd());
-
- Vfs_handle *vfs_handle = _root_dir->open(_sysio, absolute_path.base());
+ Vfs_handle *vfs_handle = _root_dir->open(_sysio, _sysio->open_in.path);
if (!vfs_handle)
return false;
- char const *leaf_path = _root_dir->leaf_path(absolute_path.base());
+ char const *leaf_path = _root_dir->leaf_path(_sysio->open_in.path);
/*
* File descriptors of opened directories are handled by
@@ -226,10 +217,10 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
* root.
*/
if (vfs_handle->ds() == _root_dir)
- leaf_path = absolute_path.base();
+ leaf_path = _sysio->open_in.path;
Shared_pointer
- channel(new Vfs_io_channel(absolute_path.base(),
+ channel(new Vfs_io_channel(_sysio->open_in.path,
leaf_path, _root_dir, vfs_handle),
Genode::env()->heap());
@@ -262,24 +253,18 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
return _lookup_channel(_sysio->dirent_in.fd)->dirent(_sysio);
- case SYSCALL_FCHDIR:
-
- return _lookup_channel(_sysio->fchdir_in.fd)->fchdir(_sysio, &_env);
-
case SYSCALL_EXECVE:
{
- Absolute_path absolute_path(_sysio->execve_in.filename, _env.pwd());
-
- Dataspace_capability binary_ds = _root_dir->dataspace(absolute_path.base());
+ Dataspace_capability binary_ds = _root_dir->dataspace(_sysio->execve_in.filename);
if (!binary_ds.valid())
throw Child::Binary_does_not_exist();
Child_envexecve_in.args)> child_env(
- absolute_path.base(), binary_ds, _sysio->execve_in.args,
+ _sysio->execve_in.filename, binary_ds, _sysio->execve_in.args,
_sysio->execve_in.env);
- _root_dir->release(absolute_path.base(), binary_ds);
+ _root_dir->release(_sysio->execve_in.filename, binary_ds);
try {
Child *child = new Child(child_env.binary_name(),
@@ -289,7 +274,6 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
_root_dir,
child_env.args(),
child_env.env(),
- _env.pwd(),
_cap_session,
_parent_services,
_resources.ep,
@@ -490,7 +474,6 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
_root_dir,
_args,
_env.env(),
- _env.pwd(),
_cap_session,
_parent_services,
_resources.ep,
@@ -564,20 +547,25 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
case SYSCALL_UNLINK:
- return _root_dir->unlink(_sysio, Absolute_path(_sysio->unlink_in.path,
- _env.pwd()).base());
+ return _root_dir->unlink(_sysio, _sysio->unlink_in.path);
+
+ case SYSCALL_READLINK:
+
+ return _root_dir->readlink(_sysio, _sysio->readlink_in.path);
+
case SYSCALL_RENAME:
- return _root_dir->rename(_sysio, Absolute_path(_sysio->rename_in.from_path,
- _env.pwd()).base(),
- Absolute_path(_sysio->rename_in.to_path,
- _env.pwd()).base());
+ return _root_dir->rename(_sysio, _sysio->rename_in.from_path,
+ _sysio->rename_in.to_path);
case SYSCALL_MKDIR:
- return _root_dir->mkdir(_sysio, Absolute_path(_sysio->mkdir_in.path,
- _env.pwd()).base());
+ return _root_dir->mkdir(_sysio, _sysio->mkdir_in.path);
+
+ case SYSCALL_SYMLINK:
+
+ return _root_dir->symlink(_sysio, _sysio->symlink_in.newpath);
case SYSCALL_USERINFO:
{
@@ -793,7 +781,6 @@ int main(int argc, char **argv)
&root_dir,
args_of_init_process(),
env_string_of_init_process(),
- "/",
&cap,
parent_services,
resources_ep,
diff --git a/ports/src/noux/net/net.cc b/ports/src/noux/net/net.cc
index d76786fc88..a2ca5c5e72 100644
--- a/ports/src/noux/net/net.cc
+++ b/ports/src/noux/net/net.cc
@@ -150,7 +150,6 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc)
/**
* Keep compiler from complaining
*/
- case SYSCALL_GETCWD:
case SYSCALL_WRITE:
case SYSCALL_READ:
case SYSCALL_STAT:
@@ -162,7 +161,6 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc)
case SYSCALL_IOCTL:
case SYSCALL_LSEEK:
case SYSCALL_DIRENT:
- case SYSCALL_FCHDIR:
case SYSCALL_EXECVE:
case SYSCALL_SELECT:
case SYSCALL_FORK:
@@ -175,6 +173,8 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc)
case SYSCALL_RENAME:
case SYSCALL_MKDIR:
case SYSCALL_FTRUNCATE:
+ case SYSCALL_READLINK:
+ case SYSCALL_SYMLINK:
case SYSCALL_USERINFO:
break;
case SYSCALL_SOCKET:
diff --git a/ports/src/noux/net/socket_io_channel.h b/ports/src/noux/net/socket_io_channel.h
index 6fcef63337..ba3acc15e4 100644
--- a/ports/src/noux/net/socket_io_channel.h
+++ b/ports/src/noux/net/socket_io_channel.h
@@ -103,7 +103,6 @@ namespace Noux {
}
}
- bool fchdir(Sysio *sysio, Pwd *pwd) { return false; }
bool dirent(Sysio *sysio) { return false; }
bool check_unblock(bool rd, bool wr, bool ex) const
diff --git a/ports/src/noux/null_file_system.h b/ports/src/noux/null_file_system.h
index ef30b9b57b..c86dbdbd8c 100644
--- a/ports/src/noux/null_file_system.h
+++ b/ports/src/noux/null_file_system.h
@@ -134,6 +134,12 @@ namespace Noux {
return false;
}
+ bool readlink(Sysio *sysio, char const *path)
+ {
+ /* not supported */
+ return false;
+ }
+
bool rename(Sysio *sysio, char const *from_path, char const *to_path)
{
/* not supported */
@@ -146,6 +152,12 @@ namespace Noux {
return false;
}
+ bool symlink(Sysio *sysio, char const *path)
+ {
+ /* not supported */
+ return false;
+ }
+
/***************************
** File_system interface **
***************************/
@@ -171,7 +183,7 @@ namespace Noux {
return true;
}
- bool ftruncate(Sysio *sysio, Vfs_handle *vfs_handle) { return false; }
+ bool ftruncate(Sysio *sysio, Vfs_handle *vfs_handle) { return true; }
};
}
diff --git a/ports/src/noux/pwd.h b/ports/src/noux/pwd.h
deleted file mode 100644
index 9a161ca8be..0000000000
--- a/ports/src/noux/pwd.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * \brief Interface to 'PWD' environment variable
- * \author Norman Feske
- * \date 2011-02-17
- */
-
-/*
- * Copyright (C) 2011-2012 Genode Labs GmbH
- *
- * This file is part of the Genode OS framework, which is distributed
- * under the terms of the GNU General Public License version 2.
- */
-
-#ifndef _NOUX__PWD_H_
-#define _NOUX__PWD_H_
-
-/* Genode includes */
-#include
-
-/* Noux includes */
-#include
-#include
-
-namespace Noux {
-
- struct Pwd
- {
- typedef Noux::Path Path;
-
- /**
- * Lookup process work directory from environment
- */
- virtual char const *pwd() = 0;
-
- /**
- * Set current work directory
- */
- virtual void pwd(char const *pwd) = 0;
- };
-}
-
-#endif /* _NOUX__PWD_H_ */
diff --git a/ports/src/noux/shared_pointer.h b/ports/src/noux/shared_pointer.h
index 85aedb6560..f86680b793 100644
--- a/ports/src/noux/shared_pointer.h
+++ b/ports/src/noux/shared_pointer.h
@@ -22,7 +22,6 @@
/* Noux includes */
#include
-#include
namespace Noux {
diff --git a/ports/src/noux/tar_file_system.h b/ports/src/noux/tar_file_system.h
index ac7833bfd2..52ed82f66d 100644
--- a/ports/src/noux/tar_file_system.h
+++ b/ports/src/noux/tar_file_system.h
@@ -389,10 +389,34 @@ namespace Noux {
bool unlink(Sysio *, char const *) { return false; }
+ bool readlink(Sysio *sysio, char const *path)
+ {
+ Lookup_exact lookup_criterion(path);
+
+ Record *record = _lookup(&lookup_criterion);
+
+ if (!record || (record->type() != Record::TYPE_SYMLINK)) {
+ sysio->error.readlink = Sysio::READLINK_ERR_NO_ENTRY;
+ return false;
+ }
+
+ size_t const count = min(sysio->readlink_in.bufsiz,
+ min(sizeof(sysio->readlink_out.chunk),
+ (size_t)100));
+
+ memcpy(sysio->readlink_out.chunk, record->linked_name(), count);
+
+ sysio->readlink_out.count = count;
+
+ return true;
+ }
+
bool rename(Sysio *, char const *, char const *) { return false; }
bool mkdir(Sysio *, char const *) { return false; }
+ bool symlink(Sysio *, char const *) { return false; }
+
size_t num_dirent(char const *path)
{
return _cached_num_dirent.num_dirent(path);
diff --git a/ports/src/noux/terminal_file_system.h b/ports/src/noux/terminal_file_system.h
index 36b5008324..6b5f3e51da 100644
--- a/ports/src/noux/terminal_file_system.h
+++ b/ports/src/noux/terminal_file_system.h
@@ -169,6 +169,12 @@ namespace Noux {
return false;
}
+ bool readlink(Sysio *sysio, char const *path)
+ {
+ /* not supported */
+ return false;
+ }
+
bool rename(Sysio *sysio, char const *from_path, char const *to_path)
{
/* not supported */
@@ -181,6 +187,12 @@ namespace Noux {
return false;
}
+ bool symlink(Sysio *sysio, char const *path)
+ {
+ /* not supported */
+ return false;
+ }
+
/***************************
** File_system interface **
***************************/
@@ -205,7 +217,7 @@ namespace Noux {
return true;
}
- bool ftruncate(Sysio *sysio, Vfs_handle *vfs_handle) { return false; }
+ bool ftruncate(Sysio *sysio, Vfs_handle *vfs_handle) { return true; }
};
}
diff --git a/ports/src/noux/vfs_handle.h b/ports/src/noux/vfs_handle.h
index 5ac9dcae53..0c655291f0 100644
--- a/ports/src/noux/vfs_handle.h
+++ b/ports/src/noux/vfs_handle.h
@@ -57,8 +57,10 @@ namespace Noux {
Vfs_handle *open(Sysio *, char const *) { _msg("open"); return 0; }
bool dirent(Sysio *, char const *, off_t) { return _msg("dirent"); }
bool unlink(Sysio *, char const *) { return _msg("unlink"); }
+ bool readlink(Sysio *, char const *) { return _msg("readlink"); }
bool rename(Sysio *, char const *, char const *) { return _msg("rename"); }
bool mkdir(Sysio *, char const *) { return _msg("mkdir"); }
+ bool symlink(Sysio *, char const *) { return _msg("symlink"); }
size_t num_dirent(char const *) { return 0; }
bool is_directory(char const *) { return false; }
char const *leaf_path(char const *path) { return 0; }
diff --git a/ports/src/noux/vfs_io_channel.h b/ports/src/noux/vfs_io_channel.h
index 46225b7f22..1161b1820c 100644
--- a/ports/src/noux/vfs_io_channel.h
+++ b/ports/src/noux/vfs_io_channel.h
@@ -18,7 +18,6 @@
#include
#include
#include
-#include
namespace Noux {
@@ -87,22 +86,6 @@ namespace Noux {
};
}
- bool fchdir(Sysio *sysio, Pwd *pwd)
- {
- sysio->fstat_in.fd = sysio->fchdir_in.fd;
-
- fstat(sysio);
-
- if ((sysio->fstat_out.st.mode & Sysio::STAT_MODE_DIRECTORY) !=
- Sysio::STAT_MODE_DIRECTORY) {
- sysio->error.fchdir = Sysio::FCHDIR_ERR_NOT_DIR;
- return false;
- }
-
- pwd->pwd(_path.base());
- return true;
- }
-
/*
* The 'dirent' function for the root directory only (the
* 'Dir_file_system::open()' function handles all requests referring
diff --git a/ports/src/noux/zero_file_system.h b/ports/src/noux/zero_file_system.h
index 5979c10e4f..65ba21f65d 100644
--- a/ports/src/noux/zero_file_system.h
+++ b/ports/src/noux/zero_file_system.h
@@ -134,6 +134,12 @@ namespace Noux {
return false;
}
+ bool readlink(Sysio *sysio, char const *path)
+ {
+ /* not supported */
+ return false;
+ }
+
bool rename(Sysio *sysio, char const *from_path, char const *to_path)
{
/* not supported */
@@ -146,6 +152,12 @@ namespace Noux {
return false;
}
+ bool symlink(Sysio *sysio, char const *path)
+ {
+ /* not supported */
+ return false;
+ }
+
/***************************
** File_system interface **
***************************/