mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-19 13:47:56 +00:00
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:
parent
4017e592f0
commit
e9ac4b653b
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
@ -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 \
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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__ );
|
||||
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(func_name, path, ...) \
|
||||
#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); \
|
||||
return -1; \
|
||||
} \
|
||||
return plugin->func_name(path, ##__VA_ARGS__);
|
||||
errno = ENOSYS; \
|
||||
result_stm -1; \
|
||||
} else \
|
||||
result_stm plugin->func_name(path, ##__VA_ARGS__); \
|
||||
}
|
||||
|
||||
#define FNAME_FUNC_WRAPPER(func_name, path, ...) \
|
||||
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;
|
||||
@ -164,6 +335,7 @@ extern "C" int _dup2(int libc_fd, int new_libc_fd)
|
||||
close(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;
|
||||
}
|
||||
|
@ -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*));
|
||||
|
@ -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) }
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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));
|
||||
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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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; }
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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; }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
54
os/src/server/tar_fs/symlink.h
Normal file
54
os/src/server/tar_fs/symlink.h
Normal 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_ */
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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; },
|
||||
|
@ -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
|
||||
|
||||
|
@ -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,11 +547,14 @@ namespace {
|
||||
_stderr(Libc::file_descriptor_allocator()->alloc(this, noux_context(2), 2))
|
||||
{ }
|
||||
|
||||
bool supports_chdir(char const *) { 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; }
|
||||
@ -654,6 +564,8 @@ namespace {
|
||||
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)) {
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
|
@ -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()) {
|
||||
|
@ -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);
|
||||
|
@ -37,9 +37,11 @@ namespace Noux {
|
||||
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 symlink(Sysio *sysio, char const *path) = 0;
|
||||
|
||||
/**
|
||||
* Return number of directory entries located at given path
|
||||
|
@ -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());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -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,6 +536,7 @@ namespace Noux {
|
||||
bool const create = sysio->open_in.mode & Sysio::OPEN_MODE_CREATE;
|
||||
|
||||
if (create)
|
||||
if (verbose)
|
||||
PDBG("creation of file %s requested", file_name.base() + 1);
|
||||
|
||||
Sysio::Open_error error = Sysio::OPEN_ERR_UNACCESSIBLE;
|
||||
@ -443,36 +579,13 @@ 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,
|
||||
sysio->write_out.count = _write(handle->file_handle(),
|
||||
sysio->write_in.chunk, 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);
|
||||
|
||||
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 max_packet_size = source.bulk_buffer_size() / 2;
|
||||
size_t const count = min(max_packet_size,
|
||||
min(file_bytes_left,
|
||||
size_t const count = min(file_bytes_left,
|
||||
min(sizeof(sysio->read_out.chunk),
|
||||
sysio->read_in.count)));
|
||||
sysio->read_in.count));
|
||||
|
||||
::File_system::Packet_descriptor
|
||||
packet(source.alloc_packet(count),
|
||||
0,
|
||||
handle->file_handle(),
|
||||
::File_system::Packet_descriptor::READ,
|
||||
count,
|
||||
handle->seek());
|
||||
sysio->read_out.count = _read(handle->file_handle(),
|
||||
sysio->read_out.chunk,
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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; }
|
||||
|
@ -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,
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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; }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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_ */
|
@ -22,7 +22,6 @@
|
||||
|
||||
/* Noux includes */
|
||||
#include <noux_session/sysio.h>
|
||||
#include <pwd.h>
|
||||
|
||||
namespace Noux {
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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; }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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; }
|
||||
|
@ -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
|
||||
|
@ -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 **
|
||||
***************************/
|
||||
|
Loading…
Reference in New Issue
Block a user