Add support for symbolic links

This patch adds support for symbolic links in libc, libc plugins, file
system servers and Noux.

Fixes #322.
This commit is contained in:
Christian Prochaska 2012-10-08 14:44:31 +02:00 committed by Norman Feske
parent 4017e592f0
commit e9ac4b653b
45 changed files with 1267 additions and 562 deletions

View File

@ -16,6 +16,12 @@
#define _LIBC_PLUGIN__FD_ALLOC_H_
#include <base/allocator_avl.h>
#include <base/printf.h>
#include <os/path.h>
/* libc includes */
#include <stdlib.h>
#include <string.h>
#include <libc-plugin/plugin.h>
@ -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;
}
};

View File

@ -14,6 +14,7 @@
#ifndef _LIBC_PLUGIN__PLUGIN_H_
#define _LIBC_PLUGIN__PLUGIN_H_
#include <os/path.h>
#include <util/list.h>
#include <netdb.h>
@ -28,6 +29,8 @@ namespace Libc {
class File_descriptor;
typedef Genode::Path<PATH_MAX> Absolute_path;
class Plugin : public List<Plugin>::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);
};

View File

@ -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);
};

View File

@ -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 \

View File

@ -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

View File

@ -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)

View File

@ -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<void*>(fdo->libc_fd));
}

View File

@ -15,6 +15,8 @@
/* Genode includes */
#include <base/printf.h>
#include <base/env.h>
#include <os/path.h>
#include <util/token.h>
/* Genode-specific libc interfaces */
#include <libc-plugin/fd_alloc.h>
@ -23,8 +25,10 @@
/* libc includes */
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
@ -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<Scanner_policy_path_element> 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;
}

View File

@ -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*));

View File

@ -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) }

View File

@ -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 <unistd.h>
#include <string.h>
#include <errno.h>
#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;
}

View File

@ -14,6 +14,7 @@
/* Genode includes */
#include <base/env.h>
#include <base/printf.h>
#include <os/path.h>
/* libc includes */
#include <errno.h>
@ -131,7 +132,6 @@ class Plugin : public Libc::Plugin
File_plugin_context *file_plugin_context =
dynamic_cast<File_plugin_context*>(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<Directory_plugin_context*>(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 <path> 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;

View File

@ -15,6 +15,7 @@
#include <base/env.h>
#include <base/printf.h>
#include <file_system_session/connection.h>
#include <os/path.h>
/* libc includes */
#include <errno.h>
@ -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<PATH_MAX_LEN> 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;

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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; }

View File

@ -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<Symlink *>(node);
if (symlink)
return symlink;
node->unlock();
throw Lookup_failed();
}
/**
* Lookup parent directory of the specified path
*

View File

@ -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<Symlink *>(node);
if (symlink) {
s.size = symlink->length();
s.mode = File_system::Status::MODE_SYMLINK;
return s;
}

View File

@ -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; }
};
}

View File

@ -25,6 +25,7 @@
#include <file.h>
#include <lookup.h>
#include <node_handle_registry.h>
#include <symlink.h>
#include <util.h>
@ -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)

View File

@ -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 <node.h>
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_ */

View File

@ -34,9 +34,11 @@ namespace Noux {
bool syscall(Syscall sc)
{
static bool verbose = false;
bool result = call<Rpc_syscall>(sc);
if (result == false)
if ((result == false) && verbose)
PERR("syscall %s failed", syscall_name(sc));
return result;

View File

@ -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)

View File

@ -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; },

View File

@ -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

View File

@ -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());
}

View File

@ -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()) {

View File

@ -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);

View File

@ -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

View File

@ -13,28 +13,20 @@
/* Genode includes */
#include <util/string.h>
#include <util/arg_string.h>
#include <os/attached_ram_dataspace.h>
#include <base/printf.h>
/* Noux includes */
#include <path.h>
#include <pwd.h>
#include <range_checked_index.h>
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());
}
};
}

View File

@ -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<Fs_vfs_handle *>(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;
}

View File

@ -22,7 +22,6 @@
/* Noux includes */
#include <noux_session/sysio.h>
#include <pwd.h>
#include <shared_pointer.h>
#include <wake_up_notifier.h>
@ -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; }

View File

@ -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<Io_channel>
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_env<sizeof(_sysio->execve_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,

View File

@ -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:

View File

@ -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

View File

@ -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; }
};
}

View File

@ -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 <util/string.h>
/* Noux includes */
#include <noux_session/sysio.h>
#include <path.h>
namespace Noux {
struct Pwd
{
typedef Noux::Path<Sysio::MAX_PATH_LEN> 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_ */

View File

@ -22,7 +22,6 @@
/* Noux includes */
#include <noux_session/sysio.h>
#include <pwd.h>
namespace Noux {

View File

@ -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);

View File

@ -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; }
};
}

View File

@ -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; }

View File

@ -18,7 +18,6 @@
#include <io_channel.h>
#include <file_system.h>
#include <dir_file_system.h>
#include <pwd.h>
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

View File

@ -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 **
***************************/