genode/repos/dde_linux/src/lib/vfs/lxip/vfs.cc

1672 lines
40 KiB
C++
Raw Normal View History

/*
* \brief lxip-based socket file system
* \author Christian Helmuth
* \author Josef Soentgen
* \author Emery Hemingway
* \date 2016-02-01
*/
/*
* Copyright (C) 2015-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* Genode includes */
#include <base/log.h>
#include <base/snprintf.h>
#include <net/ipv4.h>
#include <util/string.h>
#include <util/xml_node.h>
#include <vfs/directory_service.h>
#include <vfs/file_io_service.h>
#include <vfs/file_system_factory.h>
#include <vfs/vfs_handle.h>
/* Lxip includes */
#include <lxip/lxip.h>
#include <lx.h>
/* Lx_kit */
#include <lx_kit/env.h>
#include <lx_kit/malloc.h>
namespace Linux {
2017-05-29 13:06:16 +02:00
#include <lx_emul.h>
#include <msghdr.h>
#include <lx_emul/extern_c_begin.h>
#include <linux/socket.h>
#include <uapi/linux/in.h>
#include <uapi/linux/if.h>
extern int sock_setsockopt(socket *sock, int level,
int op, char __user *optval,
unsigned int optlen);
extern int sock_getsockopt(socket *sock, int level,
int op, char __user *optval,
int __user *optlen);
socket *sock_alloc(void);
#include <lx_emul/extern_c_end.h>
enum {
POLLIN_SET = (POLLRDNORM | POLLRDBAND | POLLIN | POLLHUP | POLLERR),
POLLOUT_SET = (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR),
POLLEX_SET = (POLLPRI)
};
}
namespace {
long get_port(char const *p)
{
long tmp = -1;
while (*++p) {
if (*p == ':') {
Genode::ascii_to_unsigned(++p, tmp, 10);
break;
}
}
return tmp;
}
unsigned get_addr(char const *p)
{
unsigned char to[4] = { 0, 0, 0, 0};
for (unsigned char &c : to) {
unsigned long result = 0;
p += Genode::ascii_to_unsigned(p, result, 10);
c = result;
if (*p == '.') ++p;
if (*p == 0) break;
};
return (to[0]<<0)|(to[1]<<8)|(to[2]<<16)|(to[3]<<24);
}
}
namespace Lxip {
using namespace Linux;
struct Protocol_dir;
struct Socket_dir;
class Protocol_dir_impl;
enum {
MAX_SOCKETS = 128, /* 3 */
MAX_SOCKET_NAME_LEN = 3 + 1, /* + \0 */
MAX_DATA_LEN = 32, /* 255.255.255.255:65536 + something */
};
}
struct Lxip::Protocol_dir
{
enum Type { TYPE_STREAM, TYPE_DGRAM };
virtual char const *top_dir() = 0;
virtual Type type() = 0;
virtual unsigned adopt_socket(socket &, bool) = 0;
virtual bool lookup_port(long) = 0;
};
struct Lxip::Socket_dir
{
virtual Protocol_dir &parent() = 0;
virtual char const *top_dir() = 0;
virtual unsigned accept(socket&) = 0;
virtual void bind(bool) = 0; /* bind to port */
virtual long bind() = 0; /* return bound port */
virtual bool lookup_port(long) = 0;
virtual void connect(bool) = 0;
virtual void listen(bool) = 0;
virtual sockaddr_storage &remote_addr() = 0;
virtual void close() = 0;
virtual bool closed() const = 0;
virtual void trigger_io_response(Vfs::Vfs_handle::Context *) = 0;
};
namespace Vfs {
using namespace Genode;
struct Node;
struct Directory;
struct File;
class Lxip_file;
class Lxip_data_file;
class Lxip_bind_file;
class Lxip_accept_file;
class Lxip_connect_file;
class Lxip_listen_file;
class Lxip_local_file;
class Lxip_remote_file;
class Lxip_socket_dir;
class Lxip_new_socket_file;
class Lxip_address_file;
class Lxip_vfs_handle;
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
class Lxip_vfs_file_handle;
class Lxip_vfs_dir_handle;
class Lxip_file_system;
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
typedef Genode::List<List_element<Lxip_vfs_file_handle> > Lxip_vfs_file_handles;
}
/***************
** Vfs nodes **
***************/
struct Vfs::Node
{
char const *_name;
Node(char const *name) : _name(name) { }
virtual ~Node() { }
virtual char const *name() { return _name; }
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
virtual void close() { }
/**
* Pass len data to handle read callback
*/
virtual Lxip::ssize_t read(char *, Genode::size_t, file_size)
{
Genode::error("lxip: read from write-only handle");
return -1;
}
/**
* Pass len data to handle write callback
*/
virtual Lxip::ssize_t write(char const *, Genode::size_t, file_size)
{
Genode::error("lxip: write to read-only handle");
return -1;
}
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
};
struct Vfs::File : Vfs::Node
{
Lxip_vfs_file_handles handles;
File(char const *name) : Node(name) { }
virtual ~File() { }
/**
* Read or write operation would block exception
*/
struct Would_block { };
/**
* Check for data to read or write
*/
virtual bool poll(bool trigger_io_response, Vfs::Vfs_handle::Context *context) = 0;
};
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
struct Vfs::Directory : Vfs::Node
{
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
Directory(char const *name) : Node(name) { }
virtual ~Directory() { };
virtual Vfs::Node *child(char const *) = 0;
virtual file_size num_dirent() = 0;
};
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
struct Vfs::Lxip_vfs_handle : Vfs::Vfs_handle
{
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
Node &node;
Lxip_vfs_handle(Vfs::File_system &fs, Allocator &alloc, int status_flags,
Vfs::Node &node)
: Vfs::Vfs_handle(fs, fs, alloc, status_flags), node(node) { }
};
struct Vfs::Lxip_vfs_file_handle final : Vfs::Lxip_vfs_handle
{
Vfs::File &file;
List_element<Lxip_vfs_file_handle> file_le { this };
List_element<Lxip_vfs_file_handle> polling_le { this };
Lxip_vfs_file_handle(Vfs::File_system &fs, Allocator &alloc, int status_flags,
Vfs::File &file)
: Lxip_vfs_handle(fs, alloc, status_flags, file), file(file)
{
file.handles.insert(&file_le);
}
~Lxip_vfs_file_handle()
{
file.handles.remove(&file_le);
}
};
struct Vfs::Lxip_vfs_dir_handle final : Vfs::Lxip_vfs_handle
{
Vfs::Directory &dir;
Lxip_vfs_dir_handle(Vfs::File_system &fs, Allocator &alloc, int status_flags,
Vfs::Directory &dir)
: Vfs::Lxip_vfs_handle(fs, alloc, status_flags, dir),
dir(dir) { }
};
/**
* List of open handles to potentially poll
*
* Could be a dynamic queue, but this works for now.
*/
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
static Vfs::Lxip_vfs_file_handles _polling_handles;
static void poll_all()
{
using namespace Linux;
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
for (Genode::List_element<Vfs::Lxip_vfs_file_handle> *le = _polling_handles.first();
le; le = le->next())
{
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
Vfs::Lxip_vfs_file_handle *handle = le->object();
handle->file.poll(true, handle->context);
}
}
/*****************************
** Lxip vfs specific nodes **
*****************************/
class Vfs::Lxip_file : public Vfs::File
{
protected:
Lxip::Socket_dir &_parent;
Linux::socket &_sock;
char _content_buffer[Lxip::MAX_DATA_LEN];
public:
Lxip_file(Lxip::Socket_dir &p, Linux::socket &s, char const *name)
: Vfs::File(name), _parent(p), _sock(s) { }
virtual ~Lxip_file() { }
void dissolve_handles()
{
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
for (Genode::List_element<Vfs::Lxip_vfs_file_handle> *le = handles.first();
le; le = le->next())
{
_polling_handles.remove(&le->object()->polling_le);
}
}
};
class Vfs::Lxip_data_file : public Vfs::Lxip_file
{
public:
Lxip_data_file(Lxip::Socket_dir &p, Linux::socket &s)
: Lxip_file(p, s, "data") { }
/********************
** File interface **
********************/
bool poll(bool trigger_io_response,
Vfs::Vfs_handle::Context *context) override
{
using namespace Linux;
file f;
f.f_flags = 0;
if (_sock.ops->poll(&f, &_sock, nullptr) & (POLLIN_SET)) {
if (trigger_io_response)
_parent.trigger_io_response(context);
return true;
}
return false;
}
Lxip::ssize_t write(char const *src, Genode::size_t len,
file_size /* ignored */) override
{
using namespace Linux;
2017-05-29 13:06:16 +02:00
iovec iov { const_cast<char *>(src), len };
2017-05-29 13:06:16 +02:00
msghdr msg = create_msghdr(&_parent.remote_addr(),
sizeof(sockaddr_in), len, &iov);
return _sock.ops->sendmsg(&_sock, &msg, len);
}
Lxip::ssize_t read(char *dst, Genode::size_t len,
file_size /* ignored */) override
{
using namespace Linux;
2017-05-29 13:06:16 +02:00
iovec iov { dst, len };
2017-05-29 13:06:16 +02:00
msghdr msg = create_msghdr(nullptr, 0, len, &iov);
Lxip::ssize_t ret = _sock.ops->recvmsg(&_sock, &msg, len, MSG_DONTWAIT);
if (ret == -EAGAIN)
throw Would_block();
return ret;
}
};
class Vfs::Lxip_bind_file : public Vfs::Lxip_file
{
private:
long _port = -1;
public:
Lxip_bind_file(Lxip::Socket_dir &p, Linux::socket &s)
: Lxip_file(p, s, "bind") { }
long port() { return _port; }
/********************
** File interface **
********************/
bool poll(bool, Vfs::Vfs_handle::Context *) { return true; }
Lxip::ssize_t write(char const *src, Genode::size_t len,
file_size /* ignored */) override
{
using namespace Linux;
if (len > (sizeof(_content_buffer) - 2))
return -1;
/* already bound to port */
if (_port >= 0) return -1;
Genode::memcpy(_content_buffer, src, len);
_content_buffer[len+1] = '\n';
_content_buffer[len+2] = '\0';
/* check if port is already used by other socket */
long port = get_port(_content_buffer);
if (port == -1) return -1;
if (_parent.lookup_port(port)) return -1;
/* port is free, try to bind it */
sockaddr_storage addr_storage;
sockaddr_in *addr = (sockaddr_in *)&addr_storage;
addr->sin_port = htons(port);
addr->sin_addr.s_addr = get_addr(_content_buffer);
addr->sin_family = AF_INET;
int res = _sock.ops->bind(&_sock, (sockaddr*)addr, sizeof(addr_storage));
if (res != 0) return -1;
_port = port;
_parent.bind(true);
return len;
}
Lxip::ssize_t read(char *dst, Genode::size_t len,
file_size /* ignored */) override
{
if (len < sizeof(_content_buffer))
return -1;
Genode::size_t const n = Genode::strlen(_content_buffer);
Genode::memcpy(dst, _content_buffer, n);
return n;
}
};
class Vfs::Lxip_listen_file : public Vfs::Lxip_file
{
public:
Lxip_listen_file(Lxip::Socket_dir &p, Linux::socket &s)
: Lxip_file(p, s, "listen") { }
/********************
** File interface **
********************/
bool poll(bool, Vfs::Vfs_handle::Context *) { return true; }
Lxip::ssize_t write(char const *src, Genode::size_t len,
file_size /* ignored */) override
{
if (len > (sizeof(_content_buffer) - 2))
return -1;
Lxip::ssize_t res;
unsigned long backlog = 5; /* default */
Genode::ascii_to_unsigned(src, backlog, 10);
res = _sock.ops->listen(&_sock, backlog);
if (res != 0) return -1;
Genode::memcpy(_content_buffer, src, len);
_content_buffer[len+1] = '\n';
_content_buffer[len+2] = '\0';
_parent.listen(true);
return len;
}
Lxip::ssize_t read(char *dst, Genode::size_t len,
file_size /* ignored */) override
{
if (len < sizeof(_content_buffer))
return -1;
Genode::size_t const n = Genode::strlen(_content_buffer);
Genode::memcpy(dst, _content_buffer, n);
return n;
}
};
class Vfs::Lxip_connect_file : public Vfs::Lxip_file
{
private:
bool _connecting = false;
bool _is_connected = false;
public:
Lxip_connect_file(Lxip::Socket_dir &p, Linux::socket &s)
: Lxip_file(p, s, "connect") { }
/********************
** File interface **
********************/
bool poll(bool, Vfs::Vfs_handle::Context *) { return true; }
Lxip::ssize_t write(char const *src, Genode::size_t len,
file_size /* ignored */) override
{
using namespace Linux;
if (len > (sizeof(_content_buffer) - 2))
return -1;
Genode::memcpy(_content_buffer, src, len);
_content_buffer[len+1] = '\n';
_content_buffer[len+2] = '\0';
long const port = get_port(_content_buffer);
if (port == -1) return -1;
sockaddr_storage addr_storage;
sockaddr_in *addr = (sockaddr_in *)&addr_storage;
addr->sin_port = htons(port);
addr->sin_addr.s_addr = get_addr(_content_buffer);
addr->sin_family = AF_INET;
int res = _sock.ops->connect(&_sock, (sockaddr *)addr, sizeof(addr_storage), 0);
switch (res) {
case Lxip::Io_result::LINUX_EINPROGRESS:
_connecting = true;
return -1;
case Lxip::Io_result::LINUX_EALREADY:
return -1;
case Lxip::Io_result::LINUX_EISCONN:
/*
* Connecting on an already connected socket is an error.
* If we get this error after we got EINPROGRESS it is
* fine.
*/
if (_is_connected || !_connecting) return -1;
_is_connected = true;
break;
default:
if (res != 0) return -1;
break;
}
sockaddr_in *remote_addr = (sockaddr_in *)&_parent.remote_addr();
remote_addr->sin_port = htons(port);
remote_addr->sin_addr.s_addr = get_addr(_content_buffer);
remote_addr->sin_family = AF_INET;
_parent.connect(true);
return len;
}
};
class Vfs::Lxip_local_file : public Vfs::Lxip_file
{
public:
Lxip_local_file(Lxip::Socket_dir &p, Linux::socket &s)
: Lxip_file(p, s, "local") { }
/********************
** File interface **
********************/
bool poll(bool, Vfs::Vfs_handle::Context *) { return true; }
Lxip::ssize_t read(char *dst, Genode::size_t len,
file_size /* ignored */) override
{
using namespace Linux;
if (len < sizeof(_content_buffer))
return -1;
sockaddr_storage addr_storage;
sockaddr_in *addr = (sockaddr_in *)&addr_storage;
int out_len = sizeof(addr_storage);
int const res = _sock.ops->getname(&_sock, (sockaddr *)addr, &out_len, 0);
if (res < 0) return -1;
in_addr const i_addr = addr->sin_addr;
unsigned char const *a = (unsigned char *)&i_addr.s_addr;
unsigned char const *p = (unsigned char *)&addr->sin_port;
return Genode::snprintf(dst, len,
"%d.%d.%d.%d:%u\n",
a[0], a[1], a[2], a[3], (p[0]<<8)|(p[1]<<0));
}
};
class Vfs::Lxip_remote_file : public Vfs::Lxip_file
{
public:
Lxip_remote_file(Lxip::Socket_dir &p, Linux::socket &s)
: Lxip_file(p, s, "remote") { }
/********************
** File interface **
********************/
bool poll(bool trigger_io_response,
Vfs::Vfs_handle::Context *context) override
{
using namespace Linux;
file f;
f.f_flags = 0;
switch (_parent.parent().type()) {
case Lxip::Protocol_dir::TYPE_DGRAM:
if (_sock.ops->poll(&f, &_sock, nullptr) & (POLLIN_SET)) {
if (trigger_io_response)
_parent.trigger_io_response(context);
return true;
}
return false;
case Lxip::Protocol_dir::TYPE_STREAM:
if (trigger_io_response)
_parent.trigger_io_response(context);
return true;
}
return false;
}
Lxip::ssize_t read(char *dst, Genode::size_t len,
file_size /* ignored */) override
{
using namespace Linux;
sockaddr_storage addr_storage;
sockaddr_in *addr = (sockaddr_in *)&addr_storage;
switch (_parent.parent().type()) {
case Lxip::Protocol_dir::TYPE_DGRAM:
{
/* peek the sender address of the next packet */
/* buffer not used */
2017-05-29 13:06:16 +02:00
iovec iov { _content_buffer, sizeof(_content_buffer) };
msghdr msg = create_msghdr(addr, sizeof(addr_storage),
sizeof(_content_buffer), &iov);
int const res = _sock.ops->recvmsg(&_sock, &msg, 0, MSG_DONTWAIT|MSG_PEEK);
if (res == -EAGAIN) throw Would_block();
if (res < 0) return -1;
}
break;
case Lxip::Protocol_dir::TYPE_STREAM:
{
int out_len = sizeof(addr_storage);
int const res = _sock.ops->getname(&_sock, (sockaddr *)addr, &out_len, 1);
if (res < 0) return -1;
}
break;
}
in_addr const i_addr = addr->sin_addr;
unsigned char const *a = (unsigned char *)&i_addr.s_addr;
unsigned char const *p = (unsigned char *)&addr->sin_port;
return Genode::snprintf(dst, len,
"%d.%d.%d.%d:%u\n",
a[0], a[1], a[2], a[3], (p[0]<<8)|(p[1]<<0));
}
Lxip::ssize_t write(char const *src, Genode::size_t len,
file_size /* ignored */) override
{
using namespace Linux;
if (len > (sizeof(_content_buffer) - 2))
return -1;
Genode::memcpy(_content_buffer, src, len);
_content_buffer[len+1] = '\n';
_content_buffer[len+2] = '\0';
long const port = get_port(_content_buffer);
if (port == -1) return -1;
sockaddr_in *remote_addr = (sockaddr_in *)&_parent.remote_addr();
remote_addr->sin_port = htons(port);
remote_addr->sin_addr.s_addr = get_addr(_content_buffer);
remote_addr->sin_family = AF_INET;
return len;
}
};
class Vfs::Lxip_accept_file : public Vfs::Lxip_file
{
public:
Lxip_accept_file(Lxip::Socket_dir &p, Linux::socket &s)
: Lxip_file(p, s, "accept") { }
/********************
** File interface **
********************/
bool poll(bool trigger_io_response,
Vfs::Vfs_handle::Context *context) override
{
using namespace Linux;
file f;
f.f_flags = 0;
if (_sock.ops->poll(&f, &_sock, nullptr) & (POLLIN)) {
if (trigger_io_response)
_parent.trigger_io_response(context);
return true;
}
return false;
}
Lxip::ssize_t read(char *dst, Genode::size_t len,
file_size /* ignored */) override
{
using namespace Linux;
if (!poll(false, nullptr)) {
throw Would_block();
}
socket *new_sock = sock_alloc();
if (int res = _sock.ops->accept(&_sock, new_sock, O_NONBLOCK)) {
kfree(new_sock);
if (res == -EAGAIN) {
throw Would_block();
} else {
return -1;
}
}
set_sock_wait(new_sock, 0);
new_sock->type = _sock.type;
new_sock->ops = _sock.ops;
try {
unsigned const id = _parent.accept(*new_sock);
return Genode::snprintf(dst, len, "%s/%u\n", _parent.top_dir(), id);
} catch (...) {
Genode::error("lxip: could not adopt new client socket");
}
kfree(new_sock);
return -1;
}
};
class Vfs::Lxip_socket_dir final : public Vfs::Directory,
public Lxip::Socket_dir
{
public:
enum {
ACCEPT_NODE, BIND_NODE, CONNECT_NODE,
DATA_NODE, LOCAL_NODE, LISTEN_NODE, REMOTE_NODE,
MAX_NODES
};
private:
Genode::Allocator &_alloc;
Lxip::Protocol_dir &_parent;
Vfs::Io_response_handler &_io_response_handler;
Linux::socket &_sock;
Vfs::Node *_nodes[MAX_NODES];
Linux::sockaddr_storage _remote_addr;
unsigned _num_nodes()
{
unsigned num = 0;
for (Vfs::Node *n : _nodes) num += (n != nullptr);
return num;
}
Lxip_accept_file _accept_file { *this, _sock };
Lxip_bind_file _bind_file { *this, _sock };
Lxip_connect_file _connect_file { *this, _sock };
Lxip_data_file _data_file { *this, _sock };
Lxip_listen_file _listen_file { *this, _sock };
Lxip_local_file _local_file { *this, _sock };
Lxip_remote_file _remote_file { *this, _sock };
char _name[Lxip::MAX_SOCKET_NAME_LEN];
public:
Lxip_socket_dir(Genode::Allocator &alloc, unsigned id,
Lxip::Protocol_dir &parent,
Vfs::Io_response_handler &io_response_handler,
Linux::socket &sock,
bool from_accept)
:
Directory(_name),
_alloc(alloc), _parent(parent), _io_response_handler(io_response_handler),
_sock(sock)
{
Genode::snprintf(_name, sizeof(_name), "%u", id);
for (Vfs::Node * &node : _nodes) node = nullptr;
_nodes[BIND_NODE] = &_bind_file;
_nodes[CONNECT_NODE] = &_connect_file;
_nodes[DATA_NODE] = &_data_file;
_nodes[LOCAL_NODE] = &_local_file;
_nodes[REMOTE_NODE] = &_remote_file;
}
~Lxip_socket_dir()
{
_accept_file.dissolve_handles();
_bind_file.dissolve_handles();
_connect_file.dissolve_handles();
_data_file.dissolve_handles();
_listen_file.dissolve_handles();
_local_file.dissolve_handles();
_remote_file.dissolve_handles();
Linux::socket *sock = &_sock;
if (sock->ops)
sock->ops->release(sock);
kfree(sock->wq);
kfree(sock);
}
/**************************
** Socket_dir interface **
**************************/
Lxip::Protocol_dir &parent() override { return _parent; }
Linux::sockaddr_storage &remote_addr() override { return _remote_addr; }
char const *top_dir() override { return _parent.top_dir(); }
unsigned accept(Linux::socket &sock) override
{
return _parent.adopt_socket(sock, true);
}
void bind(bool v) override
{
_nodes[LISTEN_NODE] = v ? &_listen_file : nullptr;
}
long bind() override { return _bind_file.port(); }
bool lookup_port(long port) override { return _parent.lookup_port(port); }
void connect(bool v) override
{
_nodes[REMOTE_NODE] = v ? &_remote_file : nullptr;
}
void listen(bool v) override
{
_nodes[ACCEPT_NODE] = v ? &_accept_file : nullptr;
}
bool _closed = false;
void close() override { _closed = true; }
bool closed() const override { return _closed; }
void trigger_io_response(Vfs::Vfs_handle::Context *context) override
{
_io_response_handler.handle_io_response(context);
}
/*************************
** Directory interface **
*************************/
Vfs::Node *child(char const *name) override
{
for (Vfs::Node *n : _nodes)
if (n && Genode::strcmp(n->name(), name) == 0)
return n;
return nullptr;
}
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
file_size num_dirent() override { return _num_nodes(); }
Lxip::ssize_t read(char *dst, Genode::size_t len,
file_size seek_offset) override
{
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
typedef Vfs::Directory_service::Dirent Dirent;
if (len < sizeof(Dirent))
return -1;
Vfs::file_size index = seek_offset / sizeof(Dirent);
Dirent *out = (Dirent*)dst;
out->fileno = index+1;
out->type = Directory_service::DIRENT_TYPE_END;
out->name[0] = '\0';
Vfs::Node *node = nullptr;
for (Vfs::Node *n : _nodes) {
if (n) {
if (index == 0) {
node = n;
break;
}
--index;
}
}
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
if (!node) return -1;
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
out->type = Directory_service::DIRENT_TYPE_FILE;
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
strncpy(out->name, node->name(), sizeof(out->name));
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
return sizeof(Dirent);
}
};
class Vfs::Lxip_new_socket_file : public Vfs::File
{
private:
Lxip::Protocol_dir &_parent;
public:
Lxip_new_socket_file(Lxip::Protocol_dir &parent)
: Vfs::File("new_socket"), _parent(parent) { }
bool poll(bool, Vfs::Vfs_handle::Context *) override { return true; }
Lxip::ssize_t read(char *dst, Genode::size_t len,
file_size /* ignored */) override
{
using namespace Linux;
socket *sock = nullptr;
int type = (_parent.type() == Lxip::Protocol_dir::TYPE_STREAM)
? SOCK_STREAM : SOCK_DGRAM;
if (sock_create_kern(nullptr, AF_INET, type, 0, &sock)) {
kfree(sock);
return -1;
}
set_sock_wait(sock, 0);
/* XXX always allow UDP broadcast */
if (type == SOCK_DGRAM) {
int enable = 1;
sock_setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&enable, sizeof(enable));
}
try {
unsigned const id = _parent.adopt_socket(*sock, false);
return Genode::snprintf(dst, len, "%s/%u\n", _parent.top_dir(), id);
} catch (...) {
Genode::error("lxip: could not adopt socket");
}
return -1;
}
};
class Lxip::Protocol_dir_impl : public Protocol_dir,
public Vfs::Directory
{
private:
Genode::Allocator &_alloc;
Vfs::File_system &_parent;
Vfs::Io_response_handler &_io_response_handler;
Type const _type;
/**************************
** Simple node registry **
**************************/
enum { MAX_NODES = Lxip::MAX_SOCKETS + 1 };
Vfs::Node *_nodes[MAX_NODES];
unsigned _num_nodes()
{
unsigned n = 0;
for (Genode::size_t i = 0; i < MAX_NODES; i++)
n += (_nodes[i] != nullptr);
return n;
}
Vfs::Node **_unused_node()
{
for (Genode::size_t i = 0; i < MAX_NODES; i++)
if (_nodes[i] == nullptr) return &_nodes[i];
throw -1;
}
void _free_node(Vfs::Node *node)
{
for (Genode::size_t i = 0; i < MAX_NODES; i++)
if (_nodes[i] == node) {
_nodes[i] = nullptr;
break;
}
}
bool _is_root(const char *path)
{
return (Genode::strcmp(path, "") == 0) || (Genode::strcmp(path, "/") == 0);
}
Vfs::Lxip_new_socket_file _new_socket_file { *this };
public:
Protocol_dir_impl(Genode::Allocator &alloc,
Vfs::File_system &parent,
Vfs::Io_response_handler &io_response_handler,
char const *name,
Lxip::Protocol_dir::Type type)
:
Directory(name),
_alloc(alloc), _parent(parent), _io_response_handler(io_response_handler),
_type(type)
{
for (Genode::size_t i = 0; i < MAX_NODES; i++) {
_nodes[i] = nullptr;
}
_nodes[0] = &_new_socket_file;
}
~Protocol_dir_impl() { }
Vfs::Node *lookup(char const *path)
{
if (*path == '/') path++;
if (*path == '\0') return this;
char const *p = path;
while (*++p && *p != '/');
for (Genode::size_t i = 0; i < MAX_NODES; i++) {
if (!_nodes[i]) continue;
if (Genode::strcmp(_nodes[i]->name(), path, (p - path)) == 0) {
Vfs::Directory *dir = dynamic_cast<Directory *>(_nodes[i]);
if (!dir) return _nodes[i];
Socket_dir *socket = dynamic_cast<Socket_dir *>(_nodes[i]);
if (socket && socket->closed())
return nullptr;
if (*p == '/') return dir->child(p+1);
else return dir;
}
}
return nullptr;
}
Vfs::Directory_service::Unlink_result unlink(char const *path)
{
Vfs::Node *node = lookup(path);
if (!node) return Vfs::Directory_service::UNLINK_ERR_NO_ENTRY;
Vfs::Directory *dir = dynamic_cast<Vfs::Directory*>(node);
if (!dir) return Vfs::Directory_service::UNLINK_ERR_NO_ENTRY;
_free_node(node);
Genode::destroy(&_alloc, dir);
return Vfs::Directory_service::UNLINK_OK;
}
/****************************
** Protocol_dir interface **
****************************/
char const *top_dir() override { return name(); }
Type type() { return _type; }
unsigned adopt_socket(Linux::socket &sock, bool from_accept)
{
Vfs::Node **node = _unused_node();
if (!node) throw -1;
unsigned const id = ((unsigned char*)node - (unsigned char*)_nodes)/sizeof(*_nodes);
Vfs::Lxip_socket_dir *dir = new (&_alloc)
Vfs::Lxip_socket_dir(_alloc, id, *this, _io_response_handler,
sock, from_accept);
*node = dir;
return id;
}
bool lookup_port(long port)
{
for (Genode::size_t i = 0; i < MAX_NODES; i++) {
if (_nodes[i] == nullptr) continue;
Lxip::Socket_dir *dir = dynamic_cast<Lxip::Socket_dir*>(_nodes[i]);
if (dir && dir->bind() == port) return true;
}
return false;
}
/*************************
** Directory interface **
*************************/
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
Vfs::file_size num_dirent() override { return _num_nodes(); }
Lxip::ssize_t read(char *dst, Genode::size_t len,
Vfs::file_size seek_offset) override
{
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
typedef Vfs::Directory_service::Dirent Dirent;
if (len < sizeof(Dirent))
return -1;
Vfs::file_size index = seek_offset / sizeof(Dirent);
Dirent *out = (Dirent*)dst;
out->fileno = index+1;
out->type = Vfs::Directory_service::DIRENT_TYPE_END;
out->name[0] = '\0';
Vfs::Node *node = nullptr;
for (Vfs::Node *n : _nodes) {
if (n) {
if (index == 0) {
node = n;
break;
}
--index;
}
}
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
if (!node) return -1;
if (dynamic_cast<Vfs::Directory*>(node))
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
out->type = Vfs::Directory_service::DIRENT_TYPE_DIRECTORY;
if (dynamic_cast<Vfs::File*>(node))
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
out->type = Vfs::Directory_service::DIRENT_TYPE_FILE;
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
Genode::strncpy(out->name, node->name(), sizeof(out->name));
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
return sizeof(Dirent);
}
Vfs::Node *child(char const *name) override { return nullptr; }
};
class Vfs::Lxip_address_file : public Vfs::File
{
private:
unsigned int &_numeric_address;
public:
Lxip_address_file(char const *name, unsigned int &numeric_address)
: Vfs::File(name), _numeric_address(numeric_address) { }
bool poll(bool, Vfs::Vfs_handle::Context *) { return true; }
Lxip::ssize_t read(char *dst, Genode::size_t len,
file_size /* ignored */) override
{
enum {
MAX_ADDRESS_STRING_SIZE = sizeof("000.000.000.000\n")
};
Genode::String<MAX_ADDRESS_STRING_SIZE> address {
Net::Ipv4_address(&_numeric_address)
};
Lxip::size_t n = min(len, strlen(address.string()));
memcpy(dst, address.string(), n);
if (n < len)
dst[n++] = '\n';
return n;
}
};
extern "C" unsigned int ic_myaddr;
extern "C" unsigned int ic_netmask;
extern "C" unsigned int ic_gateway;
extern "C" unsigned int ic_nameservers[1];
/*******************************
** Filesystem implementation **
*******************************/
class Vfs::Lxip_file_system : public Vfs::File_system,
public Vfs::Directory
{
private:
Genode::Entrypoint &_ep;
Genode::Allocator &_alloc;
Vfs::Io_response_handler &_io_response_handler;
Lxip::Protocol_dir_impl _tcp_dir {
_alloc, *this, _io_response_handler, "tcp", Lxip::Protocol_dir::TYPE_STREAM };
Lxip::Protocol_dir_impl _udp_dir {
_alloc, *this, _io_response_handler, "udp", Lxip::Protocol_dir::TYPE_DGRAM };
Lxip_address_file _address { "address", ic_myaddr };
Lxip_address_file _netmask { "netmask", ic_netmask };
Lxip_address_file _gateway { "gateway", ic_gateway };
Lxip_address_file _nameserver { "nameserver", ic_nameservers[0] };
Vfs::Node *_lookup(char const *path)
{
if (*path == '/') path++;
if (*path == '\0') return this;
if (Genode::strcmp(path, "tcp", 3) == 0)
return _tcp_dir.lookup(&path[3]);
if (Genode::strcmp(path, "udp", 3) == 0)
return _udp_dir.lookup(&path[3]);
if (Genode::strcmp(path, _address.name(),
strlen(_address.name()) + 1) == 0)
return &_address;
if (Genode::strcmp(path, _netmask.name(),
strlen(_netmask.name()) + 1) == 0)
return &_netmask;
if (Genode::strcmp(path, _gateway.name(),
strlen(_gateway.name()) + 1) == 0)
return &_gateway;
if (Genode::strcmp(path, _nameserver.name(),
strlen(_nameserver.name()) + 1) == 0)
return &_nameserver;
return nullptr;
}
bool _is_root(const char *path)
{
return (strcmp(path, "") == 0) || (strcmp(path, "/") == 0);
}
Read_result _read(Vfs::Vfs_handle *vfs_handle, char *dst,
Vfs::file_size count,
Vfs::file_size &out_count)
{
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
Vfs::Node &node =
static_cast<Vfs::Lxip_vfs_handle *>(vfs_handle)->node;
if (!count)
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
Genode::error("zero read of ", node.name());
if (count) {
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
Lxip::ssize_t res = node.read(dst, count, vfs_handle->seek());
if (res < 0) return READ_ERR_IO;
out_count = res;
}
return READ_OK;
}
public:
Lxip_file_system(Genode::Env &env, Genode::Allocator &alloc,
Genode::Xml_node config,
Vfs::Io_response_handler &io_response_handler)
:
Directory(""),
_ep(env.ep()), _alloc(alloc), _io_response_handler(io_response_handler)
{
apply_config(config);
}
~Lxip_file_system() { }
char const *name() { return "lxip"; }
char const *type() override { return "lxip"; }
/***************************
** File_system interface **
***************************/
void apply_config(Genode::Xml_node const &config) override
{
typedef String<16> Addr;
try {
if (config.attribute_value("dhcp", false)) {
log("Using DHCP for interface configuration.");
lxip_configure_dhcp();
return;
}
} catch (...) { }
try {
Addr ip_addr = config.attribute_value("ip_addr", Addr());
Addr netmask = config.attribute_value("netmask", Addr());
Addr gateway = config.attribute_value("gateway", Addr());
Addr nameserver = config.attribute_value("nameserver", Addr());
/* either none or all 4 interface attributes must exist */
if (ip_addr == "") {
warning("Missing \"ip_addr\" attribute. Ignoring network interface config.");
throw Genode::Xml_node::Nonexistent_attribute();
} else if (netmask == "") {
warning("Missing \"netmask\" attribute. Ignoring network interface config.");
throw Genode::Xml_node::Nonexistent_attribute();
} else if (gateway == "") {
warning("Missing \"gateway\" attribute. Ignoring network interface config.");
throw Genode::Xml_node::Nonexistent_attribute();
}
log("static network interface: ip_addr=",ip_addr," netmask=",netmask," gateway=",gateway);
lxip_configure_static(ip_addr.string(), netmask.string(),
gateway.string(), nameserver.string());
} catch (...) { }
}
/*************************
** Directory interface **
*************************/
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
file_size num_dirent() override { return 6; }
Lxip::ssize_t read(char *dst, Genode::size_t len,
file_size seek_offset) override
{
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
if (len < sizeof(Dirent))
return -1;
file_size index = seek_offset / sizeof(Dirent);
Dirent *out = (Dirent*)dst;
if (index == 0) {
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
out->fileno = (Genode::addr_t)&_tcp_dir;
out->type = Directory_service::DIRENT_TYPE_DIRECTORY;
Genode::strncpy(out->name, "tcp", sizeof(out->name));
} else if (index == 1) {
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
out->fileno = (Genode::addr_t)&_udp_dir;
out->type = Directory_service::DIRENT_TYPE_DIRECTORY;
Genode::strncpy(out->name, "udp", sizeof(out->name));
} else if (index == 2) {
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
out->fileno = (Genode::addr_t)&_address;
out->type = Directory_service::DIRENT_TYPE_FILE;
Genode::strncpy(out->name, "address", sizeof(out->name));
} else if (index == 3) {
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
out->fileno = (Genode::addr_t)&_netmask;
out->type = Directory_service::DIRENT_TYPE_FILE;
Genode::strncpy(out->name, "netmask", sizeof(out->name));
} else if (index == 4) {
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
out->fileno = (Genode::addr_t)&_gateway;
out->type = Directory_service::DIRENT_TYPE_FILE;
Genode::strncpy(out->name, "gateway", sizeof(out->name));
} else if (index == 5) {
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
out->fileno = (Genode::addr_t)&_nameserver;
out->type = Directory_service::DIRENT_TYPE_FILE;
Genode::strncpy(out->name, "nameserver", sizeof(out->name));
} else {
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
out->fileno = 0;
out->type = Directory_service::DIRENT_TYPE_END;
out->name[0] = '\0';
}
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
return sizeof(Dirent);
}
Vfs::Node *child(char const *name) override { return nullptr; }
/*********************************
** Directory-service interface **
*********************************/
Dataspace_capability dataspace(char const *path) override {
return Dataspace_capability(); }
void release(char const *path, Dataspace_capability ds_cap) override { }
Stat_result stat(char const *path, Stat &out) override
{
Vfs::Node *node = _lookup(path);
if (!node) return STAT_ERR_NO_ENTRY;
Vfs::Directory *dir = dynamic_cast<Vfs::Directory*>(node);
if (dir) {
out.mode = STAT_MODE_DIRECTORY | 0777;
return STAT_OK;
}
if (dynamic_cast<Lxip_file*>(node)) {
out.mode = STAT_MODE_FILE | 0666;
out.size = 0;
return STAT_OK;
}
if (dynamic_cast<Vfs::File*>(node)) {
out.mode = STAT_MODE_FILE | 0666;
out.size = 0x1000; /* there may be something to read */
return STAT_OK;
}
return STAT_ERR_NO_ENTRY;
}
file_size num_dirent(char const *path) override
{
if (_is_root(path)) return num_dirent();
Vfs::Node *node = _lookup(path);
if (!node) return 0;
Vfs::Directory *dir = dynamic_cast<Vfs::Directory*>(node);
if (!dir) return 0;
return dir->num_dirent();
}
bool directory(char const *path) override
{
Vfs::Node *node = _lookup(path);
return node ? dynamic_cast<Vfs::Directory *>(node) : 0;
}
char const *leaf_path(char const *path) override
{
return path;
}
Open_result open(char const *path, unsigned mode,
Vfs_handle **out_handle,
Genode::Allocator &alloc) override
{
if (mode & OPEN_MODE_CREATE) return OPEN_ERR_NO_PERM;
Vfs::Node *node = _lookup(path);
if (!node) return OPEN_ERR_UNACCESSIBLE;
Vfs::File *file = dynamic_cast<Vfs::File*>(node);
if (file) {
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
Lxip_vfs_file_handle *handle =
new (alloc) Vfs::Lxip_vfs_file_handle(*this, alloc, 0, *file);
*out_handle = handle;
return OPEN_OK;
}
return OPEN_ERR_UNACCESSIBLE;
}
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
Opendir_result opendir(char const *path, bool create,
Vfs_handle **out_handle, Allocator &alloc) override
{
Vfs::Node *node = _lookup(path);
if (!node) return OPENDIR_ERR_LOOKUP_FAILED;
Vfs::Directory *dir = dynamic_cast<Vfs::Directory*>(node);
if (dir) {
Lxip_vfs_dir_handle *handle =
new (alloc) Vfs::Lxip_vfs_dir_handle(*this, alloc, 0, *dir);
*out_handle = handle;
return OPENDIR_OK;
}
return OPENDIR_ERR_LOOKUP_FAILED;
}
void close(Vfs_handle *vfs_handle) override
{
Lxip_vfs_handle *handle =
static_cast<Vfs::Lxip_vfs_handle*>(vfs_handle);
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
if (!handle)
return;
Lxip_vfs_file_handle *file_handle =
dynamic_cast<Vfs::Lxip_vfs_file_handle*>(handle);
if (file_handle)
_polling_handles.remove(&file_handle->polling_le);
Genode::destroy(handle->alloc(), handle);
}
Unlink_result unlink(char const *path) override
{
if (*path == '/') path++;
if (Genode::strcmp(path, "tcp", 3) == 0)
return _tcp_dir.unlink(&path[3]);
if (Genode::strcmp(path, "udp", 3) == 0)
return _udp_dir.unlink(&path[3]);
return UNLINK_ERR_NO_ENTRY;
}
Rename_result rename(char const *, char const *) override {
return RENAME_ERR_NO_PERM; }
/*************************************
** Lxip_file I/O service interface **
*************************************/
Write_result write(Vfs_handle *vfs_handle, char const *src,
file_size count,
file_size &out_count) override
{
Vfs::File &file =
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
static_cast<Vfs::Lxip_vfs_file_handle *>(vfs_handle)->file;
if (!count)
Genode::error("zero write of ",file.name());
if (count) try {
Lxip::ssize_t res = file.write(src, count, vfs_handle->seek());
if (res < 0) return WRITE_ERR_IO;
out_count = res;
} catch (File::Would_block) { return WRITE_ERR_WOULD_BLOCK; }
return WRITE_OK;
}
Read_result complete_read(Vfs_handle *vfs_handle,
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
char *dst, file_size count,
file_size &out_count) override
{
try { return _read(vfs_handle, dst, count, out_count); }
catch (File::Would_block) { return READ_QUEUED; }
}
Ftruncate_result ftruncate(Vfs_handle *vfs_handle, file_size) override
{
/* report ok because libc always executes ftruncate() when opening rw */
return FTRUNCATE_OK;
}
bool notify_read_ready(Vfs_handle *vfs_handle) override
{
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
Lxip_vfs_file_handle *handle =
static_cast<Vfs::Lxip_vfs_file_handle *>(vfs_handle);
if (dynamic_cast<Lxip_file*>(&handle->file)) {
_polling_handles.remove(&handle->polling_le);
_polling_handles.insert(&handle->polling_le);
}
return true;
}
bool read_ready(Vfs_handle *vfs_handle) override
{
VFS: nonblocking interface The VFS library can be used in single-threaded or multi-threaded environments and depending on that, signals are handled by the same thread which uses the VFS library or possibly by a different thread. If a VFS plugin needs to block to wait for a signal, there is currently no way which works reliably in both environments. For this reason, this commit makes the interface of the VFS library nonblocking, similar to the File_system session interface. The most important changes are: - Directories are created and opened with the 'opendir()' function and the directory entries are read with the recently introduced 'queue_read()' and 'complete_read()' functions. - Symbolic links are created and opened with the 'openlink()' function and the link target is read with the 'queue_read()' and 'complete_read()' functions and written with the 'write()' function. - The 'write()' function does not wait for signals anymore. This can have the effect that data written by a VFS library user has not been processed by a file system server yet when the library user asks for the size of the file or closes it (both done with RPC functions at the file system server). For this reason, a user of the VFS library should request synchronization before calling 'stat()' or 'close()'. To make sure that a file system server has processed all write request packets which a client submitted before the synchronization request, synchronization is now requested at the file system server with a synchronization packet instead of an RPC function. Because of this change, the synchronization interface of the VFS library is now split into 'queue_sync()' and 'complete_sync()' functions. Fixes #2399
2017-08-15 20:51:53 +02:00
Lxip_vfs_file_handle *handle =
static_cast<Vfs::Lxip_vfs_file_handle *>(vfs_handle);
return handle->file.poll(false, nullptr);
}
};
struct Lxip_factory : Vfs::File_system_factory
{
struct Init
{
char _config_buf[128];
char *_parse_config(Genode::Xml_node);
Init(Genode::Env &env,
Genode::Allocator &alloc)
{
Lx_kit::Env &lx_env = Lx_kit::construct_env(env);
Lx::lxcc_emul_init(lx_env);
Lx::malloc_init(env, lx_env.heap());
Lx::timer_init(env, lx_env.env().ep(), lx_env.heap(), &poll_all);
Lx::event_init(env, lx_env.env().ep(), &poll_all);
Lx::nic_client_init(env, lx_env.env().ep(), lx_env.heap(), &poll_all);
lxip_init();
}
};
Vfs::File_system *create(Genode::Env &env,
Genode::Allocator &alloc,
Genode::Xml_node config,
Vfs::Io_response_handler &io_handler) override
{
static Init inst(env, alloc);
return new (alloc) Vfs::Lxip_file_system(env, alloc, config, io_handler);
}
};
extern "C" Vfs::File_system_factory *vfs_file_system_factory(void)
{
static Lxip_factory factory;
return &factory;
}