1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/conf/dstest_file_readdir.cfg Fri Aug 06 19:32:06 2021 +0200
1.3 @@ -0,0 +1,51 @@
1.4 +-- vim:set ft=lua:
1.5 +
1.6 +local L4 = require("L4");
1.7 +
1.8 +local l = L4.default_loader;
1.9 +
1.10 +local pipe_server = l:new_channel();
1.11 +
1.12 +l:startv({
1.13 + caps = {
1.14 + server = pipe_server:svr(),
1.15 + },
1.16 + log = { "pipes", "r" },
1.17 + },
1.18 + "rom/dstest_pipe_server", "10");
1.19 +
1.20 +local block_server = l:new_channel();
1.21 +
1.22 +l:startv({
1.23 + caps = {
1.24 + server = block_server:svr(),
1.25 + },
1.26 + log = { "blocksvr", "r" },
1.27 + },
1.28 + "rom/dstest_block_server", "10");
1.29 +
1.30 +local ext2svr = l:new_channel();
1.31 +
1.32 +l:startv({
1.33 + caps = {
1.34 + blocksvr = block_server,
1.35 + pipes = pipe_server,
1.36 + ext2svr = ext2svr:svr(),
1.37 + },
1.38 + log = { "ext2svr", "y" },
1.39 + },
1.40 + "rom/dstest_ext2_server", "blocksvr", "rom/e2test.fs", "10", "ext2svr");
1.41 +
1.42 +-- Obtain user filesystems with umask 0022 (18).
1.43 +
1.44 +local open_for_user = 6;
1.45 +local ext2svr_paulb = L4.cast(L4.Proto.Factory, ext2svr):create(open_for_user, 1000, 1000, 18);
1.46 +
1.47 +l:startv({
1.48 + caps = {
1.49 + server = ext2svr_paulb,
1.50 + },
1.51 + log = { "client", "g" },
1.52 + },
1.53 + -- program, file to create
1.54 + "rom/dstest_file_readdir", "home/paulb/many");
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/conf/dstest_file_readdir.list Fri Aug 06 19:32:06 2021 +0200
2.3 @@ -0,0 +1,28 @@
2.4 +entry dstest_file_readdir
2.5 +roottask moe rom/dstest_file_readdir.cfg
2.6 +module dstest_file_readdir.cfg
2.7 +module e2test.fs
2.8 +module l4re
2.9 +module ned
2.10 +module dstest_file_readdir
2.11 +module dstest_ext2_server
2.12 +module dstest_block_server
2.13 +module dstest_pipe_server
2.14 +module lib4re-c.so
2.15 +module lib4re-c-util.so
2.16 +module lib4re.so
2.17 +module lib4re-util.so
2.18 +module libc_be_l4refile.so
2.19 +module libc_be_l4re.so
2.20 +module libc_be_socket_noop.so
2.21 +module libc_support_misc.so
2.22 +module libdl.so
2.23 +module libipc.so
2.24 +module libl4sys-direct.so
2.25 +module libl4sys.so
2.26 +module libl4util.so
2.27 +module libld-l4.so
2.28 +module libpthread.so
2.29 +module libstdc++.so
2.30 +module libsupc++.so
2.31 +module libuc_c.so
3.1 --- a/libfsserver/include/fsserver/ext2_file_opener.h Fri Aug 06 19:30:20 2021 +0200
3.2 +++ b/libfsserver/include/fsserver/ext2_file_opener.h Fri Aug 06 19:32:06 2021 +0200
3.3 @@ -23,12 +23,19 @@
3.4
3.5 #include <ext2fs/ext2fs.h>
3.6
3.7 +#include <fsclient/file.h>
3.8 #include <fsserver/ext2_file_operations.h>
3.9 #include <fsserver/opener_resource.h>
3.10 #include <systypes/user.h>
3.11
3.12
3.13
3.14 +/* Forward declarations. */
3.15 +
3.16 +struct Ext2FileOpenerDir;
3.17 +
3.18 +
3.19 +
3.20 /* Support for providing access to files. */
3.21
3.22 class Ext2FileOpener : public OpenerResource
3.23 @@ -43,6 +50,10 @@
3.24
3.25 virtual bool accessing_file(const char *path, flags_t flags, fileid_t fileid);
3.26
3.27 + /* Convenience methods obtaining different pager types. */
3.28 +
3.29 + virtual long get_directory(const char *path, flags_t flags, fileid_t fileid, offset_t *size, l4_cap_idx_t *cap);
3.30 +
3.31 public:
3.32 explicit Ext2FileOpener(FilePaging *paging, Ext2FileOperations *ops, user_t user)
3.33 : OpenerResource(paging), _ops(ops), _user(user)
3.34 @@ -56,6 +67,24 @@
3.35 virtual long get_fileid(const char *path, flags_t flags, fileid_t *fileid);
3.36
3.37 virtual long make_accessor(const char *path, flags_t flags, fileid_t fileid, Accessor **accessor);
3.38 +
3.39 + /* Helper methods. */
3.40 +
3.41 + void read_directory(fileid_t fileid, file_t *writer);
3.42 +
3.43 + int write_directory_entry(struct Ext2FileOpenerDir *dir);
3.44 +};
3.45 +
3.46 +
3.47 +
3.48 +/* Helper structures. */
3.49 +
3.50 +struct Ext2FileOpenerDir
3.51 +{
3.52 + Ext2FileOpener *opener;
3.53 + file_t *writer;
3.54 + struct ext2_dir_entry *entry;
3.55 + long offset;
3.56 };
3.57
3.58 // vim: tabstop=4 expandtab shiftwidth=4
4.1 --- a/libfsserver/include/fsserver/ext2_file_operations.h Fri Aug 06 19:30:20 2021 +0200
4.2 +++ b/libfsserver/include/fsserver/ext2_file_operations.h Fri Aug 06 19:32:06 2021 +0200
4.3 @@ -64,6 +64,12 @@
4.4 offset_t read_file(ext2_file_t file, offset_t filepos, void *addr, offset_t size);
4.5
4.6 void write_file(ext2_file_t file, offset_t filepos, const void *addr, offset_t size);
4.7 +
4.8 + long directory_iterate(ext2_ino_t dir,
4.9 + int func(struct ext2_dir_entry *, int, int, char *, void *),
4.10 + void *priv_data);
4.11 +
4.12 + long read_inode(ext2_ino_t ino_file, struct ext2_inode *inode);
4.13 };
4.14
4.15 // vim: tabstop=4 expandtab shiftwidth=4
5.1 --- a/libfsserver/lib/files/ext2_file_opener.cc Fri Aug 06 19:30:20 2021 +0200
5.2 +++ b/libfsserver/lib/files/ext2_file_opener.cc Fri Aug 06 19:32:06 2021 +0200
5.3 @@ -19,13 +19,83 @@
5.4 * Boston, MA 02110-1301, USA
5.5 */
5.6
5.7 +#include <dirent.h>
5.8 +#include <string.h>
5.9 +
5.10 +#include <thread>
5.11 +
5.12 #include <e2access/path.h>
5.13 -
5.14 +#include <fsclient/client.h>
5.15 #include <systypes/fcntl.h>
5.16
5.17 #include "ext2_file_accessor.h"
5.18 #include "ext2_file_opener.h"
5.19
5.20 +
5.21 +
5.22 +/* Common definitions. */
5.23 +
5.24 +#define DIRENT_CORE_SIZE (sizeof(struct dirent) - sizeof(((struct dirent *) 0)->d_name))
5.25 +
5.26 +/* File type conversion. */
5.27 +
5.28 +static int convert_file_type(int type)
5.29 +{
5.30 + switch (type)
5.31 + {
5.32 + case EXT2_FT_REG_FILE: return DT_REG;
5.33 + case EXT2_FT_DIR: return DT_DIR;
5.34 + case EXT2_FT_CHRDEV: return DT_CHR;
5.35 + case EXT2_FT_BLKDEV: return DT_BLK;
5.36 + case EXT2_FT_FIFO: return DT_FIFO;
5.37 + case EXT2_FT_SOCK: return DT_SOCK;
5.38 + case EXT2_FT_SYMLINK: return DT_LNK;
5.39 + default: return DT_UNKNOWN;
5.40 + }
5.41 +}
5.42 +
5.43 +/* Helper function to ensure alignment in generated entries. */
5.44 +
5.45 +static int pad_align(int value)
5.46 +{
5.47 + return value + (sizeof(unsigned int) - (value % sizeof(unsigned int)));
5.48 +}
5.49 +
5.50 +/* Callback function. */
5.51 +
5.52 +static int read_directory_entry(struct ext2_dir_entry *dir_entry, int offset,
5.53 + int blocksize, char *buf, void *priv_data)
5.54 +{
5.55 + (void) offset; (void) blocksize; (void) buf;
5.56 +
5.57 + struct Ext2FileOpenerDir *dir = reinterpret_cast<struct Ext2FileOpenerDir *>(priv_data);
5.58 +
5.59 + dir->entry = dir_entry;
5.60 + dir->offset = offset;
5.61 + return dir->opener->write_directory_entry(dir);
5.62 +}
5.63 +
5.64 +/* Thread payload. */
5.65 +
5.66 +static void _read_directory(Ext2FileOpener *opener, fileid_t fileid, file_t *writer)
5.67 +{
5.68 + /* Subscribe to space and closure notifications on the pipe. */
5.69 +
5.70 + long err = client_set_blocking(writer, NOTIFY_SPACE_AVAILABLE);
5.71 +
5.72 + if (err)
5.73 + {
5.74 + client_close(writer);
5.75 + return;
5.76 + }
5.77 +
5.78 + opener->read_directory(fileid, writer);
5.79 +
5.80 + client_close(writer);
5.81 +}
5.82 +
5.83 +
5.84 +
5.85 Ext2FileOpener::~Ext2FileOpener()
5.86 {
5.87 }
5.88 @@ -46,6 +116,93 @@
5.89 return _ops->is_file((ext2_ino_t) fileid);
5.90 }
5.91
5.92 +// NOTE: This is mostly the same as the HostFileOpener implementation.
5.93 +
5.94 +long Ext2FileOpener::get_directory(const char *path, flags_t flags, fileid_t fileid, offset_t *size, l4_cap_idx_t *cap)
5.95 +{
5.96 + (void) path; (void) flags;
5.97 +
5.98 + file_t *reader, *writer;
5.99 +
5.100 + // NOTE: Might be more appropriate to use lower-level file operations to
5.101 + // NOTE: avoid unnecessary mapping of the reader's memory region.
5.102 +
5.103 + long err = client_pipe(&reader, &writer);
5.104 +
5.105 + if (err)
5.106 + return err;
5.107 +
5.108 + *size = reader->size;
5.109 + *cap = reader->ref;
5.110 +
5.111 + /* Discard the reader structure but do not close the reader itself. */
5.112 +
5.113 + delete reader;
5.114 +
5.115 + /* Spawn a independent thread for reading the directory details and writing
5.116 + them to the pipe. */
5.117 +
5.118 + std::thread(_read_directory, this, fileid, writer).detach();
5.119 +
5.120 + return L4_EOK;
5.121 +}
5.122 +
5.123 +/* Thread payload helper method. */
5.124 +
5.125 +void Ext2FileOpener::read_directory(fileid_t fileid, file_t *writer)
5.126 +{
5.127 + /* Initialise directory reading state: opener, writer, entry, offset. */
5.128 +
5.129 + struct Ext2FileOpenerDir dir = {this, writer, NULL, 0};
5.130 +
5.131 + /* Call the handler function for each directory entry. */
5.132 +
5.133 + _ops->directory_iterate((ext2_ino_t) fileid, read_directory_entry, &dir);
5.134 +}
5.135 +
5.136 +/* Callback method for directory entry output. */
5.137 +
5.138 +int Ext2FileOpener::write_directory_entry(struct Ext2FileOpenerDir *dir)
5.139 +{
5.140 + struct ext2_inode inode;
5.141 +
5.142 + /* Obtain the inode details for metadata. */
5.143 +
5.144 + if (_ops->read_inode(dir->entry->inode, &inode))
5.145 + return DIRENT_ABORT;
5.146 +
5.147 + /* Align the size of the entry to avoid problems on architectures which
5.148 + require aligned accesses and where the compiler needs to assume an
5.149 + aligned structure. */
5.150 +
5.151 + offset_t namelen = ext2fs_dirent_name_len(dir->entry);
5.152 + offset_t reclen = pad_align(DIRENT_CORE_SIZE + namelen);
5.153 +
5.154 + /* Construct a directory entry structure of the calculated size. */
5.155 +
5.156 + char buffer[reclen];
5.157 + struct dirent *dirent = (struct dirent *) buffer;
5.158 +
5.159 + dirent->d_ino = dir->entry->inode;
5.160 + dirent->d_off = dir->offset;
5.161 + dirent->d_reclen = reclen;
5.162 + dirent->d_type = convert_file_type(ext2fs_dirent_file_type(dir->entry));
5.163 +
5.164 + /* Copy the name, padding the memory after it to the alignment boundary. */
5.165 +
5.166 + memcpy(dirent->d_name, dir->entry->name, namelen);
5.167 + memset(dirent->d_name + namelen, 0, reclen - namelen);
5.168 +
5.169 + /* Write the structure to the pipe. */
5.170 +
5.171 + offset_t nwritten = 0;
5.172 +
5.173 + while (nwritten < reclen)
5.174 + nwritten += client_write(dir->writer, (const void *) (dirent + nwritten), reclen - nwritten);
5.175 +
5.176 + return 0;
5.177 +}
5.178 +
5.179 /* Return a file identifier for the given 'path'. */
5.180
5.181 long Ext2FileOpener::get_fileid(const char *path, flags_t flags, fileid_t *fileid)
6.1 --- a/libfsserver/lib/files/ext2_file_operations.cc Fri Aug 06 19:30:20 2021 +0200
6.2 +++ b/libfsserver/lib/files/ext2_file_operations.cc Fri Aug 06 19:32:06 2021 +0200
6.3 @@ -155,4 +155,28 @@
6.4 ext2fs_file_write(file, addr, size, NULL);
6.5 }
6.6
6.7 +/* Initiate iteration over a directory, with the given 'func' being called
6.8 + with directory entry details for each entry. */
6.9 +
6.10 +long Ext2FileOperations::directory_iterate(ext2_ino_t dir,
6.11 + int func(struct ext2_dir_entry *, int, int,
6.12 + char *, void *),
6.13 + void *priv_data)
6.14 +{
6.15 + if (ext2fs_dir_iterate(_fs, dir, 0, 0, func, priv_data))
6.16 + return -L4_EIO;
6.17 +
6.18 + return L4_EOK;
6.19 +}
6.20 +
6.21 +long Ext2FileOperations::read_inode(ext2_ino_t ino_file, struct ext2_inode *inode)
6.22 +{
6.23 + std::lock_guard<std::mutex> guard(_lock);
6.24 +
6.25 + if (ext2fs_read_inode(_fs, ino_file, inode))
6.26 + return -L4_EIO;
6.27 +
6.28 + return L4_EOK;
6.29 +}
6.30 +
6.31 // vim: tabstop=4 expandtab shiftwidth=4