mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-21 08:29:41 +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:
committed by
Norman Feske
parent
4017e592f0
commit
e9ac4b653b
@ -16,6 +16,12 @@
|
|||||||
#define _LIBC_PLUGIN__FD_ALLOC_H_
|
#define _LIBC_PLUGIN__FD_ALLOC_H_
|
||||||
|
|
||||||
#include <base/allocator_avl.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>
|
#include <libc-plugin/plugin.h>
|
||||||
|
|
||||||
@ -28,12 +34,29 @@ namespace Libc {
|
|||||||
*/
|
*/
|
||||||
class Plugin_context { };
|
class Plugin_context { };
|
||||||
|
|
||||||
|
enum { ANY_FD = -1 };
|
||||||
|
|
||||||
struct File_descriptor
|
struct File_descriptor
|
||||||
{
|
{
|
||||||
int libc_fd;
|
int libc_fd;
|
||||||
|
char *fd_path; /* for 'fchdir()' */
|
||||||
Plugin *plugin;
|
Plugin *plugin;
|
||||||
Plugin_context *context;
|
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_
|
#ifndef _LIBC_PLUGIN__PLUGIN_H_
|
||||||
#define _LIBC_PLUGIN__PLUGIN_H_
|
#define _LIBC_PLUGIN__PLUGIN_H_
|
||||||
|
|
||||||
|
#include <os/path.h>
|
||||||
#include <util/list.h>
|
#include <util/list.h>
|
||||||
|
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
@ -28,6 +29,8 @@ namespace Libc {
|
|||||||
|
|
||||||
class File_descriptor;
|
class File_descriptor;
|
||||||
|
|
||||||
|
typedef Genode::Path<PATH_MAX> Absolute_path;
|
||||||
|
|
||||||
class Plugin : public List<Plugin>::Element
|
class Plugin : public List<Plugin>::Element
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
@ -41,7 +44,8 @@ namespace Libc {
|
|||||||
|
|
||||||
virtual int priority();
|
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_mkdir(const char *path, mode_t mode);
|
||||||
virtual bool supports_freeaddrinfo(struct ::addrinfo *res);
|
virtual bool supports_freeaddrinfo(struct ::addrinfo *res);
|
||||||
virtual bool supports_getaddrinfo(const char *node, const char *service,
|
virtual bool supports_getaddrinfo(const char *node, const char *service,
|
||||||
@ -49,6 +53,7 @@ namespace Libc {
|
|||||||
struct ::addrinfo **res);
|
struct ::addrinfo **res);
|
||||||
virtual bool supports_open(const char *pathname, int flags);
|
virtual bool supports_open(const char *pathname, int flags);
|
||||||
virtual bool supports_pipe();
|
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_rename(const char *oldpath, const char *newpath);
|
||||||
virtual bool supports_select(int nfds,
|
virtual bool supports_select(int nfds,
|
||||||
fd_set *readfds,
|
fd_set *readfds,
|
||||||
@ -57,6 +62,7 @@ namespace Libc {
|
|||||||
struct timeval *timeout);
|
struct timeval *timeout);
|
||||||
virtual bool supports_socket(int domain, int type, int protocol);
|
virtual bool supports_socket(int domain, int type, int protocol);
|
||||||
virtual bool supports_stat(const char *path);
|
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_unlink(const char *path);
|
||||||
virtual bool supports_mmap();
|
virtual bool supports_mmap();
|
||||||
|
|
||||||
@ -66,14 +72,14 @@ namespace Libc {
|
|||||||
virtual int bind(File_descriptor *,
|
virtual int bind(File_descriptor *,
|
||||||
const struct ::sockaddr *addr,
|
const struct ::sockaddr *addr,
|
||||||
socklen_t addrlen);
|
socklen_t addrlen);
|
||||||
virtual int chdir(const char *path);
|
|
||||||
virtual int close(File_descriptor *fd);
|
virtual int close(File_descriptor *fd);
|
||||||
virtual int connect(File_descriptor *,
|
virtual int connect(File_descriptor *,
|
||||||
const struct ::sockaddr *addr,
|
const struct ::sockaddr *addr,
|
||||||
socklen_t addrlen);
|
socklen_t addrlen);
|
||||||
virtual int dup2(File_descriptor *, File_descriptor *new_fd);
|
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 fstatfs(File_descriptor *, struct statfs *buf);
|
||||||
virtual int fchdir(File_descriptor *);
|
|
||||||
virtual int fcntl(File_descriptor *, int cmd, long arg);
|
virtual int fcntl(File_descriptor *, int cmd, long arg);
|
||||||
virtual void freeaddrinfo(struct ::addrinfo *res);
|
virtual void freeaddrinfo(struct ::addrinfo *res);
|
||||||
virtual int fstat(File_descriptor *, struct stat *buf);
|
virtual int fstat(File_descriptor *, struct stat *buf);
|
||||||
@ -103,6 +109,7 @@ namespace Libc {
|
|||||||
virtual File_descriptor *open(const char *pathname, int flags);
|
virtual File_descriptor *open(const char *pathname, int flags);
|
||||||
virtual int pipe(File_descriptor *pipefd[2]);
|
virtual int pipe(File_descriptor *pipefd[2]);
|
||||||
virtual ssize_t read(File_descriptor *, void *buf, ::size_t count);
|
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 recv(File_descriptor *, void *buf, ::size_t len, int flags);
|
||||||
virtual ssize_t recvfrom(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);
|
struct sockaddr *src_addr, socklen_t *addrlen);
|
||||||
@ -121,6 +128,7 @@ namespace Libc {
|
|||||||
virtual int shutdown(File_descriptor *, int how);
|
virtual int shutdown(File_descriptor *, int how);
|
||||||
virtual File_descriptor *socket(int domain, int type, int protocol);
|
virtual File_descriptor *socket(int domain, int type, int protocol);
|
||||||
virtual int stat(const char *path, struct stat *buf);
|
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 int unlink(const char *path);
|
||||||
virtual ssize_t write(File_descriptor *, const void *buf, ::size_t count);
|
virtual ssize_t write(File_descriptor *, const void *buf, ::size_t count);
|
||||||
};
|
};
|
||||||
|
@ -25,7 +25,8 @@ namespace Libc {
|
|||||||
{
|
{
|
||||||
public:
|
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_freeaddrinfo(struct addrinfo *res);
|
||||||
Plugin *get_plugin_for_getaddrinfo(const char *node, const char *service,
|
Plugin *get_plugin_for_getaddrinfo(const char *node, const char *service,
|
||||||
const struct addrinfo *hints,
|
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_mkdir(const char *path, mode_t mode);
|
||||||
Plugin *get_plugin_for_open(const char *pathname, int flags);
|
Plugin *get_plugin_for_open(const char *pathname, int flags);
|
||||||
Plugin *get_plugin_for_pipe();
|
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_rename(const char *oldpath, const char *newpath);
|
||||||
Plugin *get_plugin_for_socket(int domain, int type, int protocol);
|
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_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);
|
Plugin *get_plugin_for_unlink(const char *path);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ LIBS += timed_semaphore cxx
|
|||||||
#
|
#
|
||||||
# Back end
|
# 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 \
|
issetugid.cc errno.cc gai_strerror.cc clock_gettime.cc \
|
||||||
gettimeofday.cc malloc.cc progname.cc fd_alloc.cc file_operations.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 \
|
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 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 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
|
# Boot modules
|
||||||
|
@ -37,8 +37,6 @@ DUMMY( 0, __default_hash)
|
|||||||
DUMMY(-1, _dup2)
|
DUMMY(-1, _dup2)
|
||||||
DUMMY(-1, dup2)
|
DUMMY(-1, dup2)
|
||||||
DUMMY( 0, endpwent)
|
DUMMY( 0, endpwent)
|
||||||
DUMMY(-1, _execve)
|
|
||||||
DUMMY(-1, execve)
|
|
||||||
DUMMY( 0, fchmod)
|
DUMMY( 0, fchmod)
|
||||||
DUMMY(-1, fchown)
|
DUMMY(-1, fchown)
|
||||||
DUMMY(-1, feholdexcept)
|
DUMMY(-1, feholdexcept)
|
||||||
@ -52,7 +50,6 @@ DUMMY(-1, fpathconf)
|
|||||||
DUMMY(-1, freebsd7___semctl)
|
DUMMY(-1, freebsd7___semctl)
|
||||||
DUMMY(-1, fstatat)
|
DUMMY(-1, fstatat)
|
||||||
DUMMY(-1, getcontext)
|
DUMMY(-1, getcontext)
|
||||||
DUMMY( 0, __getcwd)
|
|
||||||
DUMMY( 0, getdtablesize)
|
DUMMY( 0, getdtablesize)
|
||||||
DUMMY( 0, getegid)
|
DUMMY( 0, getegid)
|
||||||
DUMMY( 0, geteuid)
|
DUMMY( 0, geteuid)
|
||||||
@ -89,7 +86,6 @@ DUMMY(-1, ksem_trywait)
|
|||||||
DUMMY(-1, ksem_unlink)
|
DUMMY(-1, ksem_unlink)
|
||||||
DUMMY(-1, ksem_wait)
|
DUMMY(-1, ksem_wait)
|
||||||
DUMMY(-1, link)
|
DUMMY(-1, link)
|
||||||
DUMMY(-1, lstat)
|
|
||||||
DUMMY(-1, madvise)
|
DUMMY(-1, madvise)
|
||||||
DUMMY(-1, mkfifo)
|
DUMMY(-1, mkfifo)
|
||||||
DUMMY(-1, mknod)
|
DUMMY(-1, mknod)
|
||||||
@ -137,7 +133,6 @@ DUMMY(-1, sigsuspend)
|
|||||||
DUMMY(-1, socketpair)
|
DUMMY(-1, socketpair)
|
||||||
DUMMY(-1, stat)
|
DUMMY(-1, stat)
|
||||||
DUMMY(-1, statfs)
|
DUMMY(-1, statfs)
|
||||||
DUMMY(-1, symlink)
|
|
||||||
DUMMY( 0, sync)
|
DUMMY( 0, sync)
|
||||||
DUMMY(-1, __test_sse)
|
DUMMY(-1, __test_sse)
|
||||||
DUMMY(-1, truncate)
|
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 */
|
/* we use addresses returned by the allocator as file descriptors */
|
||||||
addr_t addr = (libc_fd == ANY_FD ? ANY_FD : libc_fd);
|
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);
|
File_descriptor *fdo = metadata((void*)addr);
|
||||||
fdo->libc_fd = (int)addr;
|
fdo->libc_fd = (int)addr;
|
||||||
|
fdo->fd_path = 0;
|
||||||
fdo->plugin = plugin;
|
fdo->plugin = plugin;
|
||||||
fdo->context = context;
|
fdo->context = context;
|
||||||
return fdo;
|
return fdo;
|
||||||
@ -70,6 +71,7 @@ File_descriptor *File_descriptor_allocator::alloc(Plugin *plugin, Plugin_context
|
|||||||
|
|
||||||
void File_descriptor_allocator::free(File_descriptor *fdo)
|
void File_descriptor_allocator::free(File_descriptor *fdo)
|
||||||
{
|
{
|
||||||
|
::free(fdo->fd_path);
|
||||||
Allocator_avl_base::free(reinterpret_cast<void*>(fdo->libc_fd));
|
Allocator_avl_base::free(reinterpret_cast<void*>(fdo->libc_fd));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <base/printf.h>
|
#include <base/printf.h>
|
||||||
#include <base/env.h>
|
#include <base/env.h>
|
||||||
|
#include <os/path.h>
|
||||||
|
#include <util/token.h>
|
||||||
|
|
||||||
/* Genode-specific libc interfaces */
|
/* Genode-specific libc interfaces */
|
||||||
#include <libc-plugin/fd_alloc.h>
|
#include <libc-plugin/fd_alloc.h>
|
||||||
@ -23,8 +25,10 @@
|
|||||||
|
|
||||||
/* libc includes */
|
/* libc includes */
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
@ -40,6 +44,9 @@ using namespace Libc;
|
|||||||
#define PERR(...)
|
#define PERR(...)
|
||||||
#endif /* GENODE_RELEASE */
|
#endif /* GENODE_RELEASE */
|
||||||
|
|
||||||
|
static bool const verbose = false;
|
||||||
|
#define PDBGV(...) if (verbose) PDBG(__VA_ARGS__)
|
||||||
|
|
||||||
|
|
||||||
enum { INVALID_FD = -1 };
|
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);
|
File_descriptor *fd = file_descriptor_allocator()->find_by_libc_fd(libc_fd);
|
||||||
if (!fd)
|
if (!fd)
|
||||||
PERR("no plugin found for %s(%d)", func_name, libc_fd);
|
PERR("no plugin found for %s(%d)", func_name, libc_fd);
|
||||||
|
|
||||||
return 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
|
* Generate body of wrapper function taking a file descriptor as first argument
|
||||||
*/
|
*/
|
||||||
#define FD_FUNC_WRAPPER_GENERIC(result_stm, func_name, libc_fd, ...) \
|
#define FD_FUNC_WRAPPER_GENERIC(result_stm, func_name, libc_fd, ...) \
|
||||||
|
{ \
|
||||||
File_descriptor *fd = libc_fd_to_fd(libc_fd, #func_name); \
|
File_descriptor *fd = libc_fd_to_fd(libc_fd, #func_name); \
|
||||||
if (!fd || !fd->plugin) \
|
if (!fd || !fd->plugin) \
|
||||||
result_stm INVALID_FD; \
|
result_stm INVALID_FD; \
|
||||||
else \
|
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, ...) \
|
#define FD_FUNC_WRAPPER(func_name, libc_fd, ...) \
|
||||||
FD_FUNC_WRAPPER_GENERIC(return, func_name, libc_fd, ##__VA_ARGS__ )
|
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
|
* 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__); \
|
Plugin *plugin = plugin_registry()->get_plugin_for_##func_name(path, ##__VA_ARGS__); \
|
||||||
if (!plugin) { \
|
if (!plugin) { \
|
||||||
PERR("no plugin found for %s(\"%s\")", #func_name, path); \
|
PERR("no plugin found for %s(\"%s\")", #func_name, path); \
|
||||||
return -1; \
|
errno = ENOSYS; \
|
||||||
} \
|
result_stm -1; \
|
||||||
return plugin->func_name(path, ##__VA_ARGS__);
|
} 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); }
|
FD_FUNC_WRAPPER(bind, libc_fd, addr, addrlen); }
|
||||||
|
|
||||||
|
|
||||||
extern "C" int chdir(const char *path) {
|
extern "C" int chdir(const char *path)
|
||||||
FNAME_FUNC_WRAPPER(chdir, 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) {
|
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)
|
extern "C" int _dup2(int libc_fd, int new_libc_fd)
|
||||||
{
|
{
|
||||||
|
|
||||||
File_descriptor *fd = libc_fd_to_fd(libc_fd, "dup2");
|
File_descriptor *fd = libc_fd_to_fd(libc_fd, "dup2");
|
||||||
if (!fd || !fd->plugin)
|
if (!fd || !fd->plugin)
|
||||||
return INVALID_FD;
|
return INVALID_FD;
|
||||||
@ -164,6 +335,7 @@ extern "C" int _dup2(int libc_fd, int new_libc_fd)
|
|||||||
close(new_libc_fd);
|
close(new_libc_fd);
|
||||||
|
|
||||||
new_fd = file_descriptor_allocator()->alloc(fd->plugin, 0, new_libc_fd);
|
new_fd = file_descriptor_allocator()->alloc(fd->plugin, 0, new_libc_fd);
|
||||||
|
new_fd->path(fd->fd_path);
|
||||||
/* new_fd->context must be assigned by the plugin implementing 'dup2' */
|
/* new_fd->context must be assigned by the plugin implementing 'dup2' */
|
||||||
return fd->plugin->dup2(fd, new_fd);
|
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) {
|
extern "C" int _execve(char const *filename, char *const argv[],
|
||||||
FD_FUNC_WRAPPER(fchdir, libc_fd); }
|
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, ...)
|
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); }
|
FD_FUNC_WRAPPER(lseek, libc_fd, offset, whence); }
|
||||||
|
|
||||||
|
|
||||||
extern "C" int mkdir(const char *path, mode_t mode) {
|
extern "C" int lstat(const char *path, struct stat *buf)
|
||||||
FNAME_FUNC_WRAPPER(mkdir, path, mode) }
|
{
|
||||||
|
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,
|
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)
|
extern "C" int _open(const char *pathname, int flags, ::mode_t mode)
|
||||||
{
|
{
|
||||||
|
PDBGV("pathname = %s", pathname);
|
||||||
|
|
||||||
|
Absolute_path resolved_path;
|
||||||
|
|
||||||
Plugin *plugin;
|
Plugin *plugin;
|
||||||
File_descriptor *new_fdo;
|
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) {
|
if (!plugin) {
|
||||||
PERR("no plugin found for open(\"%s\", int)", pathname, flags);
|
PERR("no plugin found for open(\"%s\", int)", pathname, flags);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
new_fdo = plugin->open(pathname, flags);
|
new_fdo = plugin->open(resolved_path.base(), flags);
|
||||||
if (!new_fdo) {
|
if (!new_fdo) {
|
||||||
PERR("plugin()->open(\"%s\") failed", pathname);
|
PERR("plugin()->open(\"%s\") failed", pathname);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
new_fdo->path(resolved_path.base());
|
||||||
|
|
||||||
return new_fdo->libc_fd;
|
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) {
|
extern "C" ssize_t recv(int libc_fd, void *buf, ::size_t len, int flags) {
|
||||||
FD_FUNC_WRAPPER(recv, libc_fd, buf, len, 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); }
|
FD_FUNC_WRAPPER(recvmsg, libc_fd, msg, flags); }
|
||||||
|
|
||||||
|
|
||||||
extern "C" int rename(const char *oldpath, const char *newpath) {
|
extern "C" int rename(const char *oldpath, const char *newpath)
|
||||||
FNAME_FUNC_WRAPPER(rename, oldpath, 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) {
|
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) {
|
extern "C" int stat(const char *path, struct stat *buf)
|
||||||
FNAME_FUNC_WRAPPER(stat, path, 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) {
|
extern "C" int symlink(const char *oldpath, const char *newpath)
|
||||||
FNAME_FUNC_WRAPPER(unlink, path) }
|
{
|
||||||
|
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) {
|
extern "C" ssize_t _write(int libc_fd, const void *buf, ::size_t count) {
|
||||||
FD_FUNC_WRAPPER(write, libc_fd, buf, count); }
|
FD_FUNC_WRAPPER(write, libc_fd, buf, count); }
|
||||||
|
|
||||||
|
|
||||||
extern "C" ssize_t write(int libc_fd, const void *buf, ::size_t count) {
|
extern "C" ssize_t write(int libc_fd, const void *buf, ::size_t count) {
|
||||||
return _write(libc_fd, buf, 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;
|
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 *)
|
bool Plugin::supports_rename(const char *, const char *)
|
||||||
{
|
{
|
||||||
return false;
|
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*)
|
bool Plugin::supports_unlink(const char*)
|
||||||
{
|
{
|
||||||
return false;
|
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
|
* 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, connect, (File_descriptor *, const struct sockaddr *, socklen_t));
|
||||||
DUMMY(int, -1, dup2, (File_descriptor *, File_descriptor *new_fd));
|
DUMMY(int, -1, dup2, (File_descriptor *, File_descriptor *new_fd));
|
||||||
DUMMY(int, -1, fstatfs, (File_descriptor *, struct statfs *));
|
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, fcntl, (File_descriptor *, int cmd, long arg));
|
||||||
DUMMY(int, -1, fstat, (File_descriptor *, struct stat *));
|
DUMMY(int, -1, fstat, (File_descriptor *, struct stat *));
|
||||||
DUMMY(int, -1, fsync, (File_descriptor *));
|
DUMMY(int, -1, fsync, (File_descriptor *));
|
||||||
@ -183,6 +182,7 @@ DUMMY(ssize_t, -1, write, (File_descriptor *, const void *, ::size_t));
|
|||||||
/*
|
/*
|
||||||
* Misc
|
* Misc
|
||||||
*/
|
*/
|
||||||
|
DUMMY(int, -1, execve, (char const *, char *const[], char *const[]));
|
||||||
DUMMY(void, , freeaddrinfo, (struct ::addrinfo *));
|
DUMMY(void, , freeaddrinfo, (struct ::addrinfo *));
|
||||||
DUMMY(int, -1, getaddrinfo, (const char *, const char *, const struct ::addrinfo *, struct ::addrinfo **));
|
DUMMY(int, -1, getaddrinfo, (const char *, const char *, const struct ::addrinfo *, struct ::addrinfo **));
|
||||||
DUMMY(int, -1, mkdir, (const char*, mode_t));
|
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));
|
File_descriptor *, ::off_t offset));
|
||||||
DUMMY(int, -1, munmap, (void *, ::size_t));
|
DUMMY(int, -1, munmap, (void *, ::size_t));
|
||||||
DUMMY(int, -1, pipe, (File_descriptor*[2]));
|
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, rename, (const char *, const char *));
|
||||||
DUMMY(int, -1, select, (int, fd_set *, fd_set *, fd_set *, struct timeval *));
|
DUMMY(int, -1, select, (int, fd_set *, fd_set *, fd_set *, struct timeval *));
|
||||||
DUMMY(int, -1, stat, (const char*, struct stat*));
|
DUMMY(int, -1, stat, (const char*, struct stat*));
|
||||||
|
DUMMY(int, -1, symlink, (const char*, const char*));
|
||||||
DUMMY(int, -1, unlink, (const char*));
|
DUMMY(int, -1, unlink, (const char*));
|
||||||
|
@ -37,9 +37,9 @@ using namespace Libc;
|
|||||||
} \
|
} \
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
Plugin *Plugin_registry::get_plugin_for_execve(char const *filename, char *const argv[],
|
||||||
Plugin *Plugin_registry::get_plugin_for_chdir(const char *path) {
|
char *const envp[]) {
|
||||||
GET_PLUGIN_FOR(chdir, path) }
|
GET_PLUGIN_FOR(execve, filename, argv, envp) }
|
||||||
|
|
||||||
|
|
||||||
Plugin *Plugin_registry::get_plugin_for_freeaddrinfo(struct addrinfo *res) {
|
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) }
|
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) {
|
Plugin *Plugin_registry::get_plugin_for_rename(const char *oldpath, const char *newpath) {
|
||||||
GET_PLUGIN_FOR(rename, oldpath, 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) }
|
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) {
|
Plugin *Plugin_registry::get_plugin_for_unlink(const char *path) {
|
||||||
GET_PLUGIN_FOR(unlink, 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 */
|
/* Genode includes */
|
||||||
#include <base/env.h>
|
#include <base/env.h>
|
||||||
#include <base/printf.h>
|
#include <base/printf.h>
|
||||||
|
#include <os/path.h>
|
||||||
|
|
||||||
/* libc includes */
|
/* libc includes */
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@ -131,7 +132,6 @@ class Plugin : public Libc::Plugin
|
|||||||
File_plugin_context *file_plugin_context =
|
File_plugin_context *file_plugin_context =
|
||||||
dynamic_cast<File_plugin_context*>(context(fd));
|
dynamic_cast<File_plugin_context*>(context(fd));
|
||||||
if (!file_plugin_context) {
|
if (!file_plugin_context) {
|
||||||
PERR("_get_ffat_file() called for a directory");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return file_plugin_context->ffat_file();
|
return file_plugin_context->ffat_file();
|
||||||
@ -142,7 +142,6 @@ class Plugin : public Libc::Plugin
|
|||||||
Directory_plugin_context *directory_plugin_context =
|
Directory_plugin_context *directory_plugin_context =
|
||||||
dynamic_cast<Directory_plugin_context*>(context(fd));
|
dynamic_cast<Directory_plugin_context*>(context(fd));
|
||||||
if (!directory_plugin_context) {
|
if (!directory_plugin_context) {
|
||||||
PERR("_get_ffat_dir() called for a regular file");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return directory_plugin_context->ffat_dir();
|
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
|
* 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)
|
bool supports_mkdir(const char *path, mode_t)
|
||||||
{
|
{
|
||||||
if (verbose)
|
if (verbose)
|
||||||
@ -216,39 +208,20 @@ class Plugin : public Libc::Plugin
|
|||||||
return true;
|
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)
|
int close(Libc::File_descriptor *fd)
|
||||||
{
|
{
|
||||||
using namespace Ffat;
|
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));
|
Genode::destroy(Genode::env()->heap(), context(fd));
|
||||||
Libc::file_descriptor_allocator()->free(fd);
|
Libc::file_descriptor_allocator()->free(fd);
|
||||||
@ -646,6 +619,14 @@ class Plugin : public Libc::Plugin
|
|||||||
file_info.lfname = 0;
|
file_info.lfname = 0;
|
||||||
file_info.lfsize = 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);
|
FRESULT res = f_stat(path, &file_info);
|
||||||
|
|
||||||
switch(res) {
|
switch(res) {
|
||||||
@ -670,8 +651,6 @@ class Plugin : public Libc::Plugin
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
::memset(buf, 0, sizeof(struct stat));
|
|
||||||
|
|
||||||
/* convert FILINFO to struct stat */
|
/* convert FILINFO to struct stat */
|
||||||
buf->st_size = file_info.fsize;
|
buf->st_size = file_info.fsize;
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include <base/env.h>
|
#include <base/env.h>
|
||||||
#include <base/printf.h>
|
#include <base/printf.h>
|
||||||
#include <file_system_session/connection.h>
|
#include <file_system_session/connection.h>
|
||||||
|
#include <os/path.h>
|
||||||
|
|
||||||
/* libc includes */
|
/* libc includes */
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@ -43,44 +44,7 @@ namespace {
|
|||||||
|
|
||||||
enum { PATH_MAX_LEN = 256 };
|
enum { PATH_MAX_LEN = 256 };
|
||||||
|
|
||||||
|
typedef Genode::Path<PATH_MAX_LEN> Canonical_path;
|
||||||
/**
|
|
||||||
* 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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static File_system::Session *file_system()
|
static File_system::Session *file_system()
|
||||||
@ -252,13 +216,6 @@ class Plugin : public Libc::Plugin
|
|||||||
|
|
||||||
~Plugin() { }
|
~Plugin() { }
|
||||||
|
|
||||||
bool supports_chdir(const char *path)
|
|
||||||
{
|
|
||||||
if (verbose)
|
|
||||||
PDBG("path = %s", path);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool supports_mkdir(const char *path, mode_t)
|
bool supports_mkdir(const char *path, mode_t)
|
||||||
{
|
{
|
||||||
if (verbose)
|
if (verbose)
|
||||||
@ -273,6 +230,13 @@ class Plugin : public Libc::Plugin
|
|||||||
return true;
|
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)
|
bool supports_rename(const char *oldpath, const char *newpath)
|
||||||
{
|
{
|
||||||
if (verbose)
|
if (verbose)
|
||||||
@ -287,6 +251,13 @@ class Plugin : public Libc::Plugin
|
|||||||
return true;
|
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)
|
bool supports_unlink(const char *path)
|
||||||
{
|
{
|
||||||
if (verbose)
|
if (verbose)
|
||||||
@ -296,25 +267,6 @@ class Plugin : public Libc::Plugin
|
|||||||
|
|
||||||
bool supports_mmap() { return true; }
|
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)
|
int close(Libc::File_descriptor *fd)
|
||||||
{
|
{
|
||||||
/* wait for the completion of all operations of the context */
|
/* wait for the completion of all operations of the context */
|
||||||
@ -468,7 +420,7 @@ class Plugin : public Libc::Plugin
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
File_system::Dir_handle const handle =
|
File_system::Dir_handle const handle =
|
||||||
file_system()->dir(canonical_path.str, true);
|
file_system()->dir(canonical_path.base(), true);
|
||||||
file_system()->close(handle);
|
file_system()->close(handle);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -498,9 +450,9 @@ class Plugin : public Libc::Plugin
|
|||||||
*/
|
*/
|
||||||
try {
|
try {
|
||||||
if (verbose)
|
if (verbose)
|
||||||
PDBG("open dir '%s'", path.str);
|
PDBG("open dir '%s'", path.base());
|
||||||
File_system::Dir_handle const handle =
|
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 *context = new (Genode::env()->heap())
|
||||||
Plugin_context(handle);
|
Plugin_context(handle);
|
||||||
@ -511,27 +463,18 @@ class Plugin : public Libc::Plugin
|
|||||||
/*
|
/*
|
||||||
* Determine directory path that contains the node to open
|
* Determine directory path that contains the node to open
|
||||||
*/
|
*/
|
||||||
unsigned last_slash = 0;
|
Canonical_path dir_path(pathname);
|
||||||
for (unsigned i = 0; path.str[i]; i++)
|
dir_path.strip_last_element();
|
||||||
if (path.str[i] == '/')
|
|
||||||
last_slash = i;
|
|
||||||
|
|
||||||
char dir_path[256] = "/";
|
Canonical_path basename(pathname);
|
||||||
if (last_slash > 0)
|
basename.keep_only_last_element();
|
||||||
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;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
/*
|
/*
|
||||||
* Open directory that contains the file to be opened/created
|
* Open directory that contains the file to be opened/created
|
||||||
*/
|
*/
|
||||||
File_system::Dir_handle const dir_handle =
|
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);
|
Node_handle_guard guard(dir_handle);
|
||||||
|
|
||||||
@ -545,14 +488,14 @@ class Plugin : public Libc::Plugin
|
|||||||
bool opened = false;
|
bool opened = false;
|
||||||
while (!opened) {
|
while (!opened) {
|
||||||
try {
|
try {
|
||||||
handle = file_system()->file(dir_handle, basename, mode, create);
|
handle = file_system()->file(dir_handle, basename.base() + 1, mode, create);
|
||||||
opened = true;
|
opened = true;
|
||||||
} catch (File_system::Node_already_exists) {
|
} catch (File_system::Node_already_exists) {
|
||||||
if (flags & O_EXCL)
|
if (flags & O_EXCL)
|
||||||
throw File_system::Node_already_exists();
|
throw File_system::Node_already_exists();
|
||||||
/* try to open the existing file */
|
/* try to open the existing file */
|
||||||
try {
|
try {
|
||||||
handle = file_system()->file(dir_handle, basename, mode, false);
|
handle = file_system()->file(dir_handle, basename.base() + 1, mode, false);
|
||||||
opened = true;
|
opened = true;
|
||||||
} catch (File_system::Lookup_failed) {
|
} catch (File_system::Lookup_failed) {
|
||||||
/* the file got deleted in the meantime */
|
/* the file got deleted in the meantime */
|
||||||
@ -649,27 +592,114 @@ class Plugin : public Libc::Plugin
|
|||||||
return count - remaining_count;
|
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)
|
int stat(const char *pathname, struct stat *buf)
|
||||||
{
|
{
|
||||||
if (verbose)
|
if (verbose)
|
||||||
PDBG("stat %s", pathname);
|
PDBG("stat %s", pathname);
|
||||||
|
|
||||||
Canonical_path path(pathname);
|
Canonical_path path(pathname);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
File_system::Node_handle const node_handle =
|
File_system::Node_handle const node_handle =
|
||||||
file_system()->node(path.str);
|
file_system()->node(path.base());
|
||||||
Node_handle_guard guard(node_handle);
|
Node_handle_guard guard(node_handle);
|
||||||
|
|
||||||
obtain_stat_for_node(node_handle, buf);
|
obtain_stat_for_node(node_handle, buf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
catch (File_system::Lookup_failed) {
|
catch (File_system::Lookup_failed) {
|
||||||
PERR("lookup failed");
|
PERR("stat(%s): lookup failed", pathname);
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
}
|
}
|
||||||
return -1;
|
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)
|
int unlink(const char *path)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -77,13 +77,18 @@ namespace {
|
|||||||
|
|
||||||
bool supports_open(const char *path, int flags)
|
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)
|
Libc::File_descriptor *open(const char *pathname, int flags)
|
||||||
{
|
{
|
||||||
Plugin_context *context = new (Genode::env()->heap())
|
Plugin_context *context = new (Genode::env()->heap())
|
||||||
Plugin_context(pathname);
|
Plugin_context(&pathname[1]);
|
||||||
return Libc::file_descriptor_allocator()->alloc(this, context);
|
return Libc::file_descriptor_allocator()->alloc(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,6 +99,16 @@ namespace {
|
|||||||
return 0;
|
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)
|
ssize_t read(Libc::File_descriptor *fd, void *buf, ::size_t count)
|
||||||
{
|
{
|
||||||
Plugin_context *rom = context(fd);
|
Plugin_context *rom = context(fd);
|
||||||
@ -140,7 +155,7 @@ namespace {
|
|||||||
|
|
||||||
case SEEK_SET:
|
case SEEK_SET:
|
||||||
|
|
||||||
if (offset > rom->size()) {
|
if (offset > (::off_t)rom->size()) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return (::off_t)(-1);
|
return (::off_t)(-1);
|
||||||
}
|
}
|
||||||
|
@ -133,7 +133,8 @@ namespace {
|
|||||||
|
|
||||||
bool supports_stat(const char *path)
|
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)
|
bool supports_open(const char *path, int flags)
|
||||||
@ -164,7 +165,14 @@ namespace {
|
|||||||
*/
|
*/
|
||||||
if (buf) {
|
if (buf) {
|
||||||
Genode::memset(buf, 0, sizeof(struct stat));
|
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;
|
buf->st_mode = S_IFCHR;
|
||||||
|
else {
|
||||||
|
errno = ENOENT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -101,13 +101,13 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* test 'pread()' and 'pwrite()' */
|
/* 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" */
|
/* write "a single line of" */
|
||||||
CALL_AND_CHECK(count, pwrite(fd, pattern, (pattern_size - 6), 0), (size_t)count == (pattern_size - 6), "");
|
CALL_AND_CHECK(count, pwrite(fd, pattern, (pattern_size - 6), 0), (size_t)count == (pattern_size - 6), "");
|
||||||
/* write "line of text" at offset 9 */
|
/* 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(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(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));
|
memset(buf, 0, sizeof(buf));
|
||||||
/* read "single line of text" from offset 2 */
|
/* read "single line of text" from offset 2 */
|
||||||
CALL_AND_CHECK(count, pread(fd, buf, sizeof(buf), 2), (size_t)count == (pattern_size - 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()' */
|
/* 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];
|
struct iovec iov[2];
|
||||||
/* write "a single line" */
|
/* write "a single line" */
|
||||||
iov[0].iov_base = (void*)pattern;
|
iov[0].iov_base = (void*)pattern;
|
||||||
@ -131,7 +131,7 @@ int main(int argc, char *argv[])
|
|||||||
iov[1].iov_len = pattern_size - 8;
|
iov[1].iov_len = pattern_size - 8;
|
||||||
CALL_AND_CHECK(count, writev(fd, iov, 2), (size_t)count == (pattern_size + 5), "");
|
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(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));
|
memset(buf, 0, sizeof(buf));
|
||||||
/* read "a single line" */
|
/* read "a single line" */
|
||||||
iov[0].iov_base = buf;
|
iov[0].iov_base = buf;
|
||||||
@ -187,6 +187,37 @@ int main(int argc, char *argv[])
|
|||||||
(ret == 0) && (stat_buf.st_size == 0),
|
(ret == 0) && (stat_buf.st_size == 0),
|
||||||
"file_name=%s", file_name4);
|
"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))
|
if (i < (iterations - 1))
|
||||||
sleep(2);
|
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))
|
if (i < (iterations - 1))
|
||||||
sleep(2);
|
sleep(2);
|
||||||
}
|
}
|
||||||
|
@ -227,7 +227,7 @@ namespace Genode {
|
|||||||
_import(path, pwd);
|
_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; }
|
char *base() { return _path; }
|
||||||
size_t max_len() { return _path_max_len; }
|
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 */
|
/* try to find entry that matches the first path element */
|
||||||
Node *sub_node = _entries.first();
|
Node *sub_node = _entries.first();
|
||||||
for (; sub_node; sub_node = sub_node->next())
|
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;
|
break;
|
||||||
|
|
||||||
if (!sub_node)
|
if (!sub_node)
|
||||||
@ -141,6 +142,18 @@ namespace File_system {
|
|||||||
throw Lookup_failed();
|
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
|
* Lookup parent directory of the specified path
|
||||||
*
|
*
|
||||||
|
@ -261,9 +261,34 @@ namespace File_system {
|
|||||||
return _handle_registry.alloc(file);
|
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)
|
Dir_handle dir(Path const &path, bool create)
|
||||||
@ -343,6 +368,7 @@ namespace File_system {
|
|||||||
}
|
}
|
||||||
Symlink *symlink = dynamic_cast<Symlink *>(node);
|
Symlink *symlink = dynamic_cast<Symlink *>(node);
|
||||||
if (symlink) {
|
if (symlink) {
|
||||||
|
s.size = symlink->length();
|
||||||
s.mode = File_system::Status::MODE_SYMLINK;
|
s.mode = File_system::Status::MODE_SYMLINK;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
@ -16,21 +16,27 @@ namespace File_system {
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Name _link_to;
|
char _link_to[MAX_PATH_LEN];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
Symlink(char const *name) { Node::name(name); }
|
||||||
|
|
||||||
size_t read(char *dst, size_t len, seek_off_t seek_offset)
|
size_t read(char *dst, size_t len, seek_off_t seek_offset)
|
||||||
{
|
{
|
||||||
PDBG("not implemented");
|
size_t count = min(len, sizeof(_link_to) + 1);
|
||||||
return 0;
|
Genode::strncpy(dst, _link_to, count);
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t write(char const *src, size_t len, seek_off_t seek_offset)
|
size_t write(char const *src, size_t len, seek_off_t seek_offset)
|
||||||
{
|
{
|
||||||
PDBG("not implemented");
|
size_t count = min(len, sizeof(_link_to) + 1);
|
||||||
return 0;
|
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 <file.h>
|
||||||
#include <lookup.h>
|
#include <lookup.h>
|
||||||
#include <node_handle_registry.h>
|
#include <node_handle_registry.h>
|
||||||
|
#include <symlink.h>
|
||||||
#include <util.h>
|
#include <util.h>
|
||||||
|
|
||||||
|
|
||||||
@ -278,10 +279,45 @@ namespace File_system {
|
|||||||
return _handle_registry.alloc(file_node);
|
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 */
|
PDBGV("_root = %s, dir_name = %s, name = %s, create = %d",
|
||||||
return Symlink_handle(-1);
|
_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)
|
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)
|
bool syscall(Syscall sc)
|
||||||
{
|
{
|
||||||
|
static bool verbose = false;
|
||||||
|
|
||||||
bool result = call<Rpc_syscall>(sc);
|
bool result = call<Rpc_syscall>(sc);
|
||||||
|
|
||||||
if (result == false)
|
if ((result == false) && verbose)
|
||||||
PERR("syscall %s failed", syscall_name(sc));
|
PERR("syscall %s failed", syscall_name(sc));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -34,7 +34,6 @@ namespace Noux {
|
|||||||
virtual Dataspace_capability sysio_dataspace() = 0;
|
virtual Dataspace_capability sysio_dataspace() = 0;
|
||||||
|
|
||||||
enum Syscall {
|
enum Syscall {
|
||||||
SYSCALL_GETCWD,
|
|
||||||
SYSCALL_WRITE,
|
SYSCALL_WRITE,
|
||||||
SYSCALL_READ,
|
SYSCALL_READ,
|
||||||
SYSCALL_STAT,
|
SYSCALL_STAT,
|
||||||
@ -47,7 +46,6 @@ namespace Noux {
|
|||||||
SYSCALL_IOCTL,
|
SYSCALL_IOCTL,
|
||||||
SYSCALL_LSEEK,
|
SYSCALL_LSEEK,
|
||||||
SYSCALL_DIRENT,
|
SYSCALL_DIRENT,
|
||||||
SYSCALL_FCHDIR,
|
|
||||||
SYSCALL_EXECVE,
|
SYSCALL_EXECVE,
|
||||||
SYSCALL_SELECT,
|
SYSCALL_SELECT,
|
||||||
SYSCALL_FORK,
|
SYSCALL_FORK,
|
||||||
@ -56,8 +54,10 @@ namespace Noux {
|
|||||||
SYSCALL_PIPE,
|
SYSCALL_PIPE,
|
||||||
SYSCALL_DUP2,
|
SYSCALL_DUP2,
|
||||||
SYSCALL_UNLINK,
|
SYSCALL_UNLINK,
|
||||||
|
SYSCALL_READLINK,
|
||||||
SYSCALL_RENAME,
|
SYSCALL_RENAME,
|
||||||
SYSCALL_MKDIR,
|
SYSCALL_MKDIR,
|
||||||
|
SYSCALL_SYMLINK,
|
||||||
SYSCALL_SOCKET,
|
SYSCALL_SOCKET,
|
||||||
SYSCALL_GETSOCKOPT,
|
SYSCALL_GETSOCKOPT,
|
||||||
SYSCALL_SETSOCKOPT,
|
SYSCALL_SETSOCKOPT,
|
||||||
@ -78,7 +78,6 @@ namespace Noux {
|
|||||||
static char const *syscall_name(Syscall sc)
|
static char const *syscall_name(Syscall sc)
|
||||||
{
|
{
|
||||||
switch (sc) {
|
switch (sc) {
|
||||||
NOUX_DECL_SYSCALL_NAME(GETCWD)
|
|
||||||
NOUX_DECL_SYSCALL_NAME(WRITE)
|
NOUX_DECL_SYSCALL_NAME(WRITE)
|
||||||
NOUX_DECL_SYSCALL_NAME(READ)
|
NOUX_DECL_SYSCALL_NAME(READ)
|
||||||
NOUX_DECL_SYSCALL_NAME(STAT)
|
NOUX_DECL_SYSCALL_NAME(STAT)
|
||||||
@ -91,7 +90,6 @@ namespace Noux {
|
|||||||
NOUX_DECL_SYSCALL_NAME(IOCTL)
|
NOUX_DECL_SYSCALL_NAME(IOCTL)
|
||||||
NOUX_DECL_SYSCALL_NAME(LSEEK)
|
NOUX_DECL_SYSCALL_NAME(LSEEK)
|
||||||
NOUX_DECL_SYSCALL_NAME(DIRENT)
|
NOUX_DECL_SYSCALL_NAME(DIRENT)
|
||||||
NOUX_DECL_SYSCALL_NAME(FCHDIR)
|
|
||||||
NOUX_DECL_SYSCALL_NAME(EXECVE)
|
NOUX_DECL_SYSCALL_NAME(EXECVE)
|
||||||
NOUX_DECL_SYSCALL_NAME(SELECT)
|
NOUX_DECL_SYSCALL_NAME(SELECT)
|
||||||
NOUX_DECL_SYSCALL_NAME(FORK)
|
NOUX_DECL_SYSCALL_NAME(FORK)
|
||||||
@ -100,8 +98,10 @@ namespace Noux {
|
|||||||
NOUX_DECL_SYSCALL_NAME(PIPE)
|
NOUX_DECL_SYSCALL_NAME(PIPE)
|
||||||
NOUX_DECL_SYSCALL_NAME(DUP2)
|
NOUX_DECL_SYSCALL_NAME(DUP2)
|
||||||
NOUX_DECL_SYSCALL_NAME(UNLINK)
|
NOUX_DECL_SYSCALL_NAME(UNLINK)
|
||||||
|
NOUX_DECL_SYSCALL_NAME(READLINK)
|
||||||
NOUX_DECL_SYSCALL_NAME(RENAME)
|
NOUX_DECL_SYSCALL_NAME(RENAME)
|
||||||
NOUX_DECL_SYSCALL_NAME(MKDIR)
|
NOUX_DECL_SYSCALL_NAME(MKDIR)
|
||||||
|
NOUX_DECL_SYSCALL_NAME(SYMLINK)
|
||||||
NOUX_DECL_SYSCALL_NAME(SOCKET)
|
NOUX_DECL_SYSCALL_NAME(SOCKET)
|
||||||
NOUX_DECL_SYSCALL_NAME(GETSOCKOPT)
|
NOUX_DECL_SYSCALL_NAME(GETSOCKOPT)
|
||||||
NOUX_DECL_SYSCALL_NAME(SETSOCKOPT)
|
NOUX_DECL_SYSCALL_NAME(SETSOCKOPT)
|
||||||
|
@ -286,18 +286,20 @@ namespace Noux {
|
|||||||
|
|
||||||
enum General_error { ERR_FD_INVALID, NUM_GENERAL_ERRORS };
|
enum General_error { ERR_FD_INVALID, NUM_GENERAL_ERRORS };
|
||||||
enum Stat_error { STAT_ERR_NO_ENTRY = 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 Fcntl_error { FCNTL_ERR_CMD_INVALID = NUM_GENERAL_ERRORS };
|
||||||
enum Ftruncate_error { FTRUNCATE_ERR_NO_PERM = NUM_GENERAL_ERRORS };
|
enum Ftruncate_error { FTRUNCATE_ERR_NO_PERM = NUM_GENERAL_ERRORS };
|
||||||
enum Open_error { OPEN_ERR_UNACCESSIBLE, OPEN_ERR_NO_PERM,
|
enum Open_error { OPEN_ERR_UNACCESSIBLE, OPEN_ERR_NO_PERM,
|
||||||
OPEN_ERR_EXISTS };
|
OPEN_ERR_EXISTS };
|
||||||
enum Execve_error { EXECVE_NONEXISTENT = NUM_GENERAL_ERRORS };
|
enum Execve_error { EXECVE_NONEXISTENT = NUM_GENERAL_ERRORS };
|
||||||
enum Unlink_error { UNLINK_ERR_NO_ENTRY, UNLINK_ERR_NO_PERM };
|
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,
|
enum Rename_error { RENAME_ERR_NO_ENTRY, RENAME_ERR_CROSS_FS,
|
||||||
RENAME_ERR_NO_PERM };
|
RENAME_ERR_NO_PERM };
|
||||||
enum Mkdir_error { MKDIR_ERR_EXISTS, MKDIR_ERR_NO_ENTRY,
|
enum Mkdir_error { MKDIR_ERR_EXISTS, MKDIR_ERR_NO_ENTRY,
|
||||||
MKDIR_ERR_NO_SPACE, MKDIR_ERR_NO_PERM,
|
MKDIR_ERR_NO_SPACE, MKDIR_ERR_NO_PERM,
|
||||||
MKDIR_ERR_NAME_TOO_LONG};
|
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,
|
enum Read_error { READ_ERR_AGAIN, READ_ERR_WOULD_BLOCK,
|
||||||
READ_ERR_INVALID, READ_ERR_IO };
|
READ_ERR_INVALID, READ_ERR_IO };
|
||||||
@ -338,14 +340,15 @@ namespace Noux {
|
|||||||
union {
|
union {
|
||||||
General_error general;
|
General_error general;
|
||||||
Stat_error stat;
|
Stat_error stat;
|
||||||
Fchdir_error fchdir;
|
|
||||||
Fcntl_error fcntl;
|
Fcntl_error fcntl;
|
||||||
Ftruncate_error ftruncate;
|
Ftruncate_error ftruncate;
|
||||||
Open_error open;
|
Open_error open;
|
||||||
Execve_error execve;
|
Execve_error execve;
|
||||||
Unlink_error unlink;
|
Unlink_error unlink;
|
||||||
|
Readlink_error readlink;
|
||||||
Rename_error rename;
|
Rename_error rename;
|
||||||
Mkdir_error mkdir;
|
Mkdir_error mkdir;
|
||||||
|
Symlink_error symlink;
|
||||||
Read_error read;
|
Read_error read;
|
||||||
Write_error write;
|
Write_error write;
|
||||||
Accept_error accept;
|
Accept_error accept;
|
||||||
@ -360,13 +363,13 @@ namespace Noux {
|
|||||||
|
|
||||||
union {
|
union {
|
||||||
|
|
||||||
SYSIO_DECL(getcwd, { }, { Path path; });
|
|
||||||
|
|
||||||
SYSIO_DECL(write, { int fd; size_t count; Chunk chunk; },
|
SYSIO_DECL(write, { int fd; size_t count; Chunk chunk; },
|
||||||
{ size_t count; });
|
{ size_t count; });
|
||||||
|
|
||||||
SYSIO_DECL(stat, { Path path; }, { Stat st; });
|
SYSIO_DECL(stat, { Path path; }, { Stat st; });
|
||||||
|
|
||||||
|
SYSIO_DECL(symlink, { Path oldpath; Path newpath; }, { });
|
||||||
|
|
||||||
SYSIO_DECL(fstat, { int fd; }, { Stat st; });
|
SYSIO_DECL(fstat, { int fd; }, { Stat st; });
|
||||||
|
|
||||||
SYSIO_DECL(ftruncate, { int fd; off_t length; }, { });
|
SYSIO_DECL(ftruncate, { int fd; off_t length; }, { });
|
||||||
@ -385,11 +388,12 @@ namespace Noux {
|
|||||||
|
|
||||||
SYSIO_DECL(dirent, { int fd; }, { Dirent entry; });
|
SYSIO_DECL(dirent, { int fd; }, { Dirent entry; });
|
||||||
|
|
||||||
SYSIO_DECL(fchdir, { int fd; }, { });
|
|
||||||
|
|
||||||
SYSIO_DECL(read, { int fd; size_t count; },
|
SYSIO_DECL(read, { int fd; size_t count; },
|
||||||
{ Chunk chunk; 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(execve, { Path filename; Args args; Env env; }, { });
|
||||||
|
|
||||||
SYSIO_DECL(select, { Select_fds fds; Select_timeout timeout; },
|
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
|
# 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 {
|
foreach test_binary $test_binaries {
|
||||||
set source_files [ exec [cross_dev_prefix]objdump -dl bin/$test_binary | grep "^/.*:.*" | sed -e "s/:.*//" | uniq ]
|
set source_files [ exec [cross_dev_prefix]objdump -dl bin/$test_binary | grep "^/.*:.*" | sed -e "s/:.*//" | uniq ]
|
||||||
foreach source_file $source_files {
|
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
|
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
|
* 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)
|
static bool serialize_string_array(char const * const * array, char *dst, Genode::size_t dst_len)
|
||||||
{
|
{
|
||||||
for (unsigned i = 0; array[i]; i++)
|
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
|
* 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))
|
_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_open(char const *, int) { return true; }
|
||||||
bool supports_stat(char const *) { 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_pipe() { return true; }
|
||||||
bool supports_unlink(char const *) { 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_rename(const char *, const char *) { return true; }
|
||||||
bool supports_mkdir(const char *, mode_t) { return true; }
|
bool supports_mkdir(const char *, mode_t) { return true; }
|
||||||
bool supports_socket(int, int, int) { 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);
|
ssize_t write(Libc::File_descriptor *, const void *, ::size_t);
|
||||||
int close(Libc::File_descriptor *);
|
int close(Libc::File_descriptor *);
|
||||||
int dup2(Libc::File_descriptor *, 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 fstat(Libc::File_descriptor *, struct stat *);
|
||||||
int fsync(Libc::File_descriptor *);
|
int fsync(Libc::File_descriptor *);
|
||||||
int fstatfs(Libc::File_descriptor *, struct statfs *);
|
int fstatfs(Libc::File_descriptor *, struct statfs *);
|
||||||
@ -661,9 +573,10 @@ namespace {
|
|||||||
int fcntl(Libc::File_descriptor *, int, long);
|
int fcntl(Libc::File_descriptor *, int, long);
|
||||||
ssize_t getdirentries(Libc::File_descriptor *, char *, ::size_t, ::off_t *);
|
ssize_t getdirentries(Libc::File_descriptor *, char *, ::size_t, ::off_t *);
|
||||||
::off_t lseek(Libc::File_descriptor *, ::off_t offset, int whence);
|
::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 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 stat(char const *, struct stat *);
|
||||||
|
int symlink(const char *, const char *);
|
||||||
int ioctl(Libc::File_descriptor *, int request, char *argp);
|
int ioctl(Libc::File_descriptor *, int request, char *argp);
|
||||||
int pipe(Libc::File_descriptor *pipefd[2]);
|
int pipe(Libc::File_descriptor *pipefd[2]);
|
||||||
int unlink(char const *path);
|
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)
|
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)
|
int Plugin::fstatfs(Libc::File_descriptor *, struct statfs *buf)
|
||||||
{
|
{
|
||||||
buf->f_flags = MNT_UNION;
|
buf->f_flags = MNT_UNION;
|
||||||
@ -1027,8 +1044,7 @@ namespace {
|
|||||||
*/
|
*/
|
||||||
Libc::File_descriptor *new_fd =
|
Libc::File_descriptor *new_fd =
|
||||||
Libc::file_descriptor_allocator()->alloc(this, 0);
|
Libc::file_descriptor_allocator()->alloc(this, 0);
|
||||||
|
new_fd->path(fd->fd_path);
|
||||||
new_fd->context = noux_context(new_fd->libc_fd);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Use new allocated number as name of file descriptor
|
* 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)
|
int Plugin::unlink(char const *path)
|
||||||
{
|
{
|
||||||
Genode::strncpy(sysio()->unlink_in.path, path, sizeof(sysio()->unlink_in.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)
|
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));
|
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' */
|
unsigned num_entries = 0; /* index within 'env_array' */
|
||||||
|
|
||||||
|
static Libc::Absolute_path noux_cwd("/");
|
||||||
|
|
||||||
while (*env_string && (num_entries < ENV_MAX_ENTRIES - 1)) {
|
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_array[num_entries++] = env_string;
|
||||||
|
}
|
||||||
env_string += (strlen(env_string) + 1);
|
env_string += (strlen(env_string) + 1);
|
||||||
}
|
}
|
||||||
env_array[num_entries] = 0;
|
env_array[num_entries] = 0;
|
||||||
@ -1720,6 +1753,8 @@ void init_libc_noux(void)
|
|||||||
|
|
||||||
/* initialize noux libc plugin */
|
/* initialize noux libc plugin */
|
||||||
static Plugin noux_plugin;
|
static Plugin noux_plugin;
|
||||||
|
|
||||||
|
chdir(noux_cwd.base());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -296,7 +296,6 @@ namespace Noux {
|
|||||||
Dir_file_system *root_dir,
|
Dir_file_system *root_dir,
|
||||||
Args const &args,
|
Args const &args,
|
||||||
Sysio::Env const &env,
|
Sysio::Env const &env,
|
||||||
char const *pwd,
|
|
||||||
Cap_session *cap_session,
|
Cap_session *cap_session,
|
||||||
Service_registry &parent_services,
|
Service_registry &parent_services,
|
||||||
Rpc_entrypoint &resources_ep,
|
Rpc_entrypoint &resources_ep,
|
||||||
@ -329,7 +328,6 @@ namespace Noux {
|
|||||||
_child(_binary_ds, _resources.ram.cap(), _resources.cpu.cap(),
|
_child(_binary_ds, _resources.ram.cap(), _resources.cpu.cap(),
|
||||||
_resources.rm.cap(), &_entrypoint, &_child_policy)
|
_resources.rm.cap(), &_entrypoint, &_child_policy)
|
||||||
{
|
{
|
||||||
_env.pwd(pwd);
|
|
||||||
_args.dump();
|
_args.dump();
|
||||||
|
|
||||||
if (!forked && !_binary_ds.valid()) {
|
if (!forked && !_binary_ds.valid()) {
|
||||||
|
@ -466,6 +466,39 @@ namespace Noux {
|
|||||||
return false;
|
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)
|
bool rename(Sysio *sysio, char const *from_path, char const *to_path)
|
||||||
{
|
{
|
||||||
from_path = _sub_path(from_path);
|
from_path = _sub_path(from_path);
|
||||||
@ -518,6 +551,48 @@ namespace Noux {
|
|||||||
return false;
|
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)
|
bool mkdir(Sysio *sysio, char const *path)
|
||||||
{
|
{
|
||||||
path = _sub_path(path);
|
path = _sub_path(path);
|
||||||
|
@ -37,9 +37,11 @@ namespace Noux {
|
|||||||
virtual bool stat(Sysio *sysio, char const *path) = 0;
|
virtual bool stat(Sysio *sysio, char const *path) = 0;
|
||||||
virtual bool dirent(Sysio *sysio, char const *path, off_t index) = 0;
|
virtual bool dirent(Sysio *sysio, char const *path, off_t index) = 0;
|
||||||
virtual bool unlink(Sysio *sysio, char const *path) = 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,
|
virtual bool rename(Sysio *sysio, char const *from_path,
|
||||||
char const *to_path) = 0;
|
char const *to_path) = 0;
|
||||||
virtual bool mkdir(Sysio *sysio, char const *path) = 0;
|
virtual bool mkdir(Sysio *sysio, char const *path) = 0;
|
||||||
|
virtual bool symlink(Sysio *sysio, char const *path) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return number of directory entries located at given path
|
* Return number of directory entries located at given path
|
||||||
|
@ -13,28 +13,20 @@
|
|||||||
|
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <util/string.h>
|
#include <util/string.h>
|
||||||
#include <util/arg_string.h>
|
|
||||||
#include <os/attached_ram_dataspace.h>
|
#include <os/attached_ram_dataspace.h>
|
||||||
#include <base/printf.h>
|
#include <base/printf.h>
|
||||||
|
|
||||||
/* Noux includes */
|
/* Noux includes */
|
||||||
#include <path.h>
|
#include <path.h>
|
||||||
#include <pwd.h>
|
|
||||||
#include <range_checked_index.h>
|
|
||||||
|
|
||||||
namespace Noux {
|
namespace Noux {
|
||||||
|
|
||||||
/**
|
class Environment : private Attached_ram_dataspace
|
||||||
* Front-end for PWD environment variable
|
|
||||||
*/
|
|
||||||
class Environment : private Attached_ram_dataspace, public Pwd
|
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Sysio::Env *_env;
|
Sysio::Env *_env;
|
||||||
|
|
||||||
Pwd::Path _pwd_path;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,19 +45,5 @@ namespace Noux {
|
|||||||
* Return list of environment variables as zero-separated list
|
* Return list of environment variables as zero-separated list
|
||||||
*/
|
*/
|
||||||
Sysio::Env const &env() { return *_env; }
|
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
|
class Fs_file_system : public File_system
|
||||||
{
|
{
|
||||||
|
enum { verbose = false };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Lock _lock;
|
Lock _lock;
|
||||||
@ -84,6 +86,70 @@ namespace Noux {
|
|||||||
~Fs_handle_guard() { _fs.close(_handle); }
|
~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:
|
public:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -185,7 +251,8 @@ namespace Noux {
|
|||||||
Fs_handle_guard node_guard(_fs, node);
|
Fs_handle_guard node_guard(_fs, node);
|
||||||
status = _fs.status(node);
|
status = _fs.status(node);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
PWRN("stat failed for path '%s'", path);
|
if (verbose)
|
||||||
|
PDBG("stat failed for path '%s'", path);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,6 +351,40 @@ namespace Noux {
|
|||||||
return true;
|
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)
|
bool rename(Sysio *sysio, char const *from_path, char const *to_path)
|
||||||
{
|
{
|
||||||
Absolute_path from_dir_path(from_path);
|
Absolute_path from_dir_path(from_path);
|
||||||
@ -337,6 +438,40 @@ namespace Noux {
|
|||||||
return false;
|
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)
|
size_t num_dirent(char const *path)
|
||||||
{
|
{
|
||||||
if (strcmp(path, "") == 0)
|
if (strcmp(path, "") == 0)
|
||||||
@ -401,6 +536,7 @@ namespace Noux {
|
|||||||
bool const create = sysio->open_in.mode & Sysio::OPEN_MODE_CREATE;
|
bool const create = sysio->open_in.mode & Sysio::OPEN_MODE_CREATE;
|
||||||
|
|
||||||
if (create)
|
if (create)
|
||||||
|
if (verbose)
|
||||||
PDBG("creation of file %s requested", file_name.base() + 1);
|
PDBG("creation of file %s requested", file_name.base() + 1);
|
||||||
|
|
||||||
Sysio::Open_error error = Sysio::OPEN_ERR_UNACCESSIBLE;
|
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);
|
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;
|
sysio->write_out.count = _write(handle->file_handle(),
|
||||||
size_t const count = min(max_packet_size,
|
sysio->write_in.chunk, count,
|
||||||
min(sizeof(sysio->write_in.chunk),
|
|
||||||
sysio->write_in.count));
|
|
||||||
|
|
||||||
::File_system::Packet_descriptor
|
|
||||||
packet(source.alloc_packet(count),
|
|
||||||
0,
|
|
||||||
handle->file_handle(),
|
|
||||||
::File_system::Packet_descriptor::WRITE,
|
|
||||||
count,
|
|
||||||
handle->seek());
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -486,36 +599,14 @@ namespace Noux {
|
|||||||
size_t const file_bytes_left = file_size >= handle->seek()
|
size_t const file_bytes_left = file_size >= handle->seek()
|
||||||
? file_size - handle->seek() : 0;
|
? file_size - handle->seek() : 0;
|
||||||
|
|
||||||
::File_system::Session::Tx::Source &source = *_fs.tx();
|
size_t const count = min(file_bytes_left,
|
||||||
|
|
||||||
size_t const max_packet_size = source.bulk_buffer_size() / 2;
|
|
||||||
size_t const count = min(max_packet_size,
|
|
||||||
min(file_bytes_left,
|
|
||||||
min(sizeof(sysio->read_out.chunk),
|
min(sizeof(sysio->read_out.chunk),
|
||||||
sysio->read_in.count)));
|
sysio->read_in.count));
|
||||||
|
|
||||||
::File_system::Packet_descriptor
|
sysio->read_out.count = _read(handle->file_handle(),
|
||||||
packet(source.alloc_packet(count),
|
sysio->read_out.chunk,
|
||||||
0,
|
count, handle->seek());
|
||||||
handle->file_handle(),
|
|
||||||
::File_system::Packet_descriptor::READ,
|
|
||||||
count,
|
|
||||||
handle->seek());
|
|
||||||
|
|
||||||
/* pass packet to server side */
|
|
||||||
source.submit_packet(packet);
|
|
||||||
source.get_acked_packet();
|
|
||||||
|
|
||||||
memcpy(sysio->read_out.chunk, source.packet_content(packet), count);
|
|
||||||
|
|
||||||
sysio->read_out.count = count;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* XXX check if acked packet belongs to request,
|
|
||||||
* needed for thread safety
|
|
||||||
*/
|
|
||||||
|
|
||||||
source.release_packet(packet);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
|
|
||||||
/* Noux includes */
|
/* Noux includes */
|
||||||
#include <noux_session/sysio.h>
|
#include <noux_session/sysio.h>
|
||||||
#include <pwd.h>
|
|
||||||
#include <shared_pointer.h>
|
#include <shared_pointer.h>
|
||||||
#include <wake_up_notifier.h>
|
#include <wake_up_notifier.h>
|
||||||
|
|
||||||
@ -55,7 +54,6 @@ namespace Noux {
|
|||||||
virtual bool fstat(Sysio *sysio) { return false; }
|
virtual bool fstat(Sysio *sysio) { return false; }
|
||||||
virtual bool ftruncate(Sysio *sysio) { return false; }
|
virtual bool ftruncate(Sysio *sysio) { return false; }
|
||||||
virtual bool fcntl(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 dirent(Sysio *sysio) { return false; }
|
||||||
virtual bool ioctl(Sysio *sysio) { return false; }
|
virtual bool ioctl(Sysio *sysio) { return false; }
|
||||||
virtual bool lseek(Sysio *sysio) { return false; }
|
virtual bool lseek(Sysio *sysio) { return false; }
|
||||||
|
@ -127,12 +127,6 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
|||||||
try {
|
try {
|
||||||
switch (sc) {
|
switch (sc) {
|
||||||
|
|
||||||
case SYSCALL_GETCWD:
|
|
||||||
|
|
||||||
Genode::strncpy(_sysio->getcwd_out.path, _env.pwd(),
|
|
||||||
sizeof(_sysio->getcwd_out.path));
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case SYSCALL_WRITE:
|
case SYSCALL_WRITE:
|
||||||
{
|
{
|
||||||
size_t const count_in = _sysio->write_in.count;
|
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_STAT:
|
||||||
case SYSCALL_LSTAT: /* XXX implement difference between 'lstat' and 'stat' */
|
case SYSCALL_LSTAT: /* XXX implement difference between 'lstat' and 'stat' */
|
||||||
{
|
{
|
||||||
bool result = _root_dir->stat(_sysio, Absolute_path(_sysio->stat_in.path,
|
bool result = _root_dir->stat(_sysio, _sysio->stat_in.path);
|
||||||
_env.pwd()).base());
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instead of using the uid/gid given by the actual file system
|
* 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:
|
case SYSCALL_OPEN:
|
||||||
{
|
{
|
||||||
Absolute_path absolute_path(_sysio->open_in.path, _env.pwd());
|
Vfs_handle *vfs_handle = _root_dir->open(_sysio, _sysio->open_in.path);
|
||||||
|
|
||||||
Vfs_handle *vfs_handle = _root_dir->open(_sysio, absolute_path.base());
|
|
||||||
if (!vfs_handle)
|
if (!vfs_handle)
|
||||||
return false;
|
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
|
* File descriptors of opened directories are handled by
|
||||||
@ -226,10 +217,10 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
|||||||
* root.
|
* root.
|
||||||
*/
|
*/
|
||||||
if (vfs_handle->ds() == _root_dir)
|
if (vfs_handle->ds() == _root_dir)
|
||||||
leaf_path = absolute_path.base();
|
leaf_path = _sysio->open_in.path;
|
||||||
|
|
||||||
Shared_pointer<Io_channel>
|
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),
|
leaf_path, _root_dir, vfs_handle),
|
||||||
Genode::env()->heap());
|
Genode::env()->heap());
|
||||||
|
|
||||||
@ -262,24 +253,18 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
|||||||
|
|
||||||
return _lookup_channel(_sysio->dirent_in.fd)->dirent(_sysio);
|
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:
|
case SYSCALL_EXECVE:
|
||||||
{
|
{
|
||||||
Absolute_path absolute_path(_sysio->execve_in.filename, _env.pwd());
|
Dataspace_capability binary_ds = _root_dir->dataspace(_sysio->execve_in.filename);
|
||||||
|
|
||||||
Dataspace_capability binary_ds = _root_dir->dataspace(absolute_path.base());
|
|
||||||
|
|
||||||
if (!binary_ds.valid())
|
if (!binary_ds.valid())
|
||||||
throw Child::Binary_does_not_exist();
|
throw Child::Binary_does_not_exist();
|
||||||
|
|
||||||
Child_env<sizeof(_sysio->execve_in.args)> child_env(
|
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);
|
_sysio->execve_in.env);
|
||||||
|
|
||||||
_root_dir->release(absolute_path.base(), binary_ds);
|
_root_dir->release(_sysio->execve_in.filename, binary_ds);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Child *child = new Child(child_env.binary_name(),
|
Child *child = new Child(child_env.binary_name(),
|
||||||
@ -289,7 +274,6 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
|||||||
_root_dir,
|
_root_dir,
|
||||||
child_env.args(),
|
child_env.args(),
|
||||||
child_env.env(),
|
child_env.env(),
|
||||||
_env.pwd(),
|
|
||||||
_cap_session,
|
_cap_session,
|
||||||
_parent_services,
|
_parent_services,
|
||||||
_resources.ep,
|
_resources.ep,
|
||||||
@ -490,7 +474,6 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
|||||||
_root_dir,
|
_root_dir,
|
||||||
_args,
|
_args,
|
||||||
_env.env(),
|
_env.env(),
|
||||||
_env.pwd(),
|
|
||||||
_cap_session,
|
_cap_session,
|
||||||
_parent_services,
|
_parent_services,
|
||||||
_resources.ep,
|
_resources.ep,
|
||||||
@ -564,20 +547,25 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
|||||||
|
|
||||||
case SYSCALL_UNLINK:
|
case SYSCALL_UNLINK:
|
||||||
|
|
||||||
return _root_dir->unlink(_sysio, Absolute_path(_sysio->unlink_in.path,
|
return _root_dir->unlink(_sysio, _sysio->unlink_in.path);
|
||||||
_env.pwd()).base());
|
|
||||||
|
case SYSCALL_READLINK:
|
||||||
|
|
||||||
|
return _root_dir->readlink(_sysio, _sysio->readlink_in.path);
|
||||||
|
|
||||||
|
|
||||||
case SYSCALL_RENAME:
|
case SYSCALL_RENAME:
|
||||||
|
|
||||||
return _root_dir->rename(_sysio, Absolute_path(_sysio->rename_in.from_path,
|
return _root_dir->rename(_sysio, _sysio->rename_in.from_path,
|
||||||
_env.pwd()).base(),
|
_sysio->rename_in.to_path);
|
||||||
Absolute_path(_sysio->rename_in.to_path,
|
|
||||||
_env.pwd()).base());
|
|
||||||
|
|
||||||
case SYSCALL_MKDIR:
|
case SYSCALL_MKDIR:
|
||||||
|
|
||||||
return _root_dir->mkdir(_sysio, Absolute_path(_sysio->mkdir_in.path,
|
return _root_dir->mkdir(_sysio, _sysio->mkdir_in.path);
|
||||||
_env.pwd()).base());
|
|
||||||
|
case SYSCALL_SYMLINK:
|
||||||
|
|
||||||
|
return _root_dir->symlink(_sysio, _sysio->symlink_in.newpath);
|
||||||
|
|
||||||
case SYSCALL_USERINFO:
|
case SYSCALL_USERINFO:
|
||||||
{
|
{
|
||||||
@ -793,7 +781,6 @@ int main(int argc, char **argv)
|
|||||||
&root_dir,
|
&root_dir,
|
||||||
args_of_init_process(),
|
args_of_init_process(),
|
||||||
env_string_of_init_process(),
|
env_string_of_init_process(),
|
||||||
"/",
|
|
||||||
&cap,
|
&cap,
|
||||||
parent_services,
|
parent_services,
|
||||||
resources_ep,
|
resources_ep,
|
||||||
|
@ -150,7 +150,6 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc)
|
|||||||
/**
|
/**
|
||||||
* Keep compiler from complaining
|
* Keep compiler from complaining
|
||||||
*/
|
*/
|
||||||
case SYSCALL_GETCWD:
|
|
||||||
case SYSCALL_WRITE:
|
case SYSCALL_WRITE:
|
||||||
case SYSCALL_READ:
|
case SYSCALL_READ:
|
||||||
case SYSCALL_STAT:
|
case SYSCALL_STAT:
|
||||||
@ -162,7 +161,6 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc)
|
|||||||
case SYSCALL_IOCTL:
|
case SYSCALL_IOCTL:
|
||||||
case SYSCALL_LSEEK:
|
case SYSCALL_LSEEK:
|
||||||
case SYSCALL_DIRENT:
|
case SYSCALL_DIRENT:
|
||||||
case SYSCALL_FCHDIR:
|
|
||||||
case SYSCALL_EXECVE:
|
case SYSCALL_EXECVE:
|
||||||
case SYSCALL_SELECT:
|
case SYSCALL_SELECT:
|
||||||
case SYSCALL_FORK:
|
case SYSCALL_FORK:
|
||||||
@ -175,6 +173,8 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc)
|
|||||||
case SYSCALL_RENAME:
|
case SYSCALL_RENAME:
|
||||||
case SYSCALL_MKDIR:
|
case SYSCALL_MKDIR:
|
||||||
case SYSCALL_FTRUNCATE:
|
case SYSCALL_FTRUNCATE:
|
||||||
|
case SYSCALL_READLINK:
|
||||||
|
case SYSCALL_SYMLINK:
|
||||||
case SYSCALL_USERINFO:
|
case SYSCALL_USERINFO:
|
||||||
break;
|
break;
|
||||||
case SYSCALL_SOCKET:
|
case SYSCALL_SOCKET:
|
||||||
|
@ -103,7 +103,6 @@ namespace Noux {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fchdir(Sysio *sysio, Pwd *pwd) { return false; }
|
|
||||||
bool dirent(Sysio *sysio) { return false; }
|
bool dirent(Sysio *sysio) { return false; }
|
||||||
|
|
||||||
bool check_unblock(bool rd, bool wr, bool ex) const
|
bool check_unblock(bool rd, bool wr, bool ex) const
|
||||||
|
@ -134,6 +134,12 @@ namespace Noux {
|
|||||||
return false;
|
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)
|
bool rename(Sysio *sysio, char const *from_path, char const *to_path)
|
||||||
{
|
{
|
||||||
/* not supported */
|
/* not supported */
|
||||||
@ -146,6 +152,12 @@ namespace Noux {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool symlink(Sysio *sysio, char const *path)
|
||||||
|
{
|
||||||
|
/* not supported */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/***************************
|
/***************************
|
||||||
** File_system interface **
|
** File_system interface **
|
||||||
***************************/
|
***************************/
|
||||||
@ -171,7 +183,7 @@ namespace Noux {
|
|||||||
return true;
|
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 */
|
/* Noux includes */
|
||||||
#include <noux_session/sysio.h>
|
#include <noux_session/sysio.h>
|
||||||
#include <pwd.h>
|
|
||||||
|
|
||||||
namespace Noux {
|
namespace Noux {
|
||||||
|
|
||||||
|
@ -389,10 +389,34 @@ namespace Noux {
|
|||||||
|
|
||||||
bool unlink(Sysio *, char const *) { return false; }
|
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 rename(Sysio *, char const *, char const *) { return false; }
|
||||||
|
|
||||||
bool mkdir(Sysio *, 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)
|
size_t num_dirent(char const *path)
|
||||||
{
|
{
|
||||||
return _cached_num_dirent.num_dirent(path);
|
return _cached_num_dirent.num_dirent(path);
|
||||||
|
@ -169,6 +169,12 @@ namespace Noux {
|
|||||||
return false;
|
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)
|
bool rename(Sysio *sysio, char const *from_path, char const *to_path)
|
||||||
{
|
{
|
||||||
/* not supported */
|
/* not supported */
|
||||||
@ -181,6 +187,12 @@ namespace Noux {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool symlink(Sysio *sysio, char const *path)
|
||||||
|
{
|
||||||
|
/* not supported */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/***************************
|
/***************************
|
||||||
** File_system interface **
|
** File_system interface **
|
||||||
***************************/
|
***************************/
|
||||||
@ -205,7 +217,7 @@ namespace Noux {
|
|||||||
return true;
|
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; }
|
Vfs_handle *open(Sysio *, char const *) { _msg("open"); return 0; }
|
||||||
bool dirent(Sysio *, char const *, off_t) { return _msg("dirent"); }
|
bool dirent(Sysio *, char const *, off_t) { return _msg("dirent"); }
|
||||||
bool unlink(Sysio *, char const *) { return _msg("unlink"); }
|
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 rename(Sysio *, char const *, char const *) { return _msg("rename"); }
|
||||||
bool mkdir(Sysio *, char const *) { return _msg("mkdir"); }
|
bool mkdir(Sysio *, char const *) { return _msg("mkdir"); }
|
||||||
|
bool symlink(Sysio *, char const *) { return _msg("symlink"); }
|
||||||
size_t num_dirent(char const *) { return 0; }
|
size_t num_dirent(char const *) { return 0; }
|
||||||
bool is_directory(char const *) { return false; }
|
bool is_directory(char const *) { return false; }
|
||||||
char const *leaf_path(char const *path) { return 0; }
|
char const *leaf_path(char const *path) { return 0; }
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
#include <io_channel.h>
|
#include <io_channel.h>
|
||||||
#include <file_system.h>
|
#include <file_system.h>
|
||||||
#include <dir_file_system.h>
|
#include <dir_file_system.h>
|
||||||
#include <pwd.h>
|
|
||||||
|
|
||||||
namespace Noux {
|
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
|
* The 'dirent' function for the root directory only (the
|
||||||
* 'Dir_file_system::open()' function handles all requests referring
|
* 'Dir_file_system::open()' function handles all requests referring
|
||||||
|
@ -134,6 +134,12 @@ namespace Noux {
|
|||||||
return false;
|
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)
|
bool rename(Sysio *sysio, char const *from_path, char const *to_path)
|
||||||
{
|
{
|
||||||
/* not supported */
|
/* not supported */
|
||||||
@ -146,6 +152,12 @@ namespace Noux {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool symlink(Sysio *sysio, char const *path)
|
||||||
|
{
|
||||||
|
/* not supported */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/***************************
|
/***************************
|
||||||
** File_system interface **
|
** File_system interface **
|
||||||
***************************/
|
***************************/
|
||||||
|
Reference in New Issue
Block a user