1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libfsserver/include/fsserver/directory_resource.h Fri Sep 10 23:57:02 2021 +0200 1.3 @@ -0,0 +1,58 @@ 1.4 +/* 1.5 + * A resource offering support for directory operations. 1.6 + * 1.7 + * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk> 1.8 + * 1.9 + * This program is free software; you can redistribute it and/or 1.10 + * modify it under the terms of the GNU General Public License as 1.11 + * published by the Free Software Foundation; either version 2 of 1.12 + * the License, or (at your option) any later version. 1.13 + * 1.14 + * This program is distributed in the hope that it will be useful, 1.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 1.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1.17 + * GNU General Public License for more details. 1.18 + * 1.19 + * You should have received a copy of the GNU General Public License 1.20 + * along with this program; if not, write to the Free Software 1.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, 1.22 + * Boston, MA 02110-1301, USA 1.23 + */ 1.24 + 1.25 +#pragma once 1.26 + 1.27 +#include <fsserver/directory_object_interface.h> 1.28 +#include <fsserver/resource.h> 1.29 + 1.30 + 1.31 + 1.32 +/* Support for providing access to directories. 1.33 + NOTE: Notification methods to be added when DirectoryObject is extended. */ 1.34 + 1.35 +class DirectoryResource : public Resource, public DirectoryObject 1.36 +{ 1.37 +protected: 1.38 + /* Methods requiring customisation. */ 1.39 + 1.40 + virtual long _opendir(flags_t flags, offset_t *size, l4_cap_idx_t *cap, 1.41 + object_flags_t *object_flags) = 0; 1.42 + 1.43 +public: 1.44 + virtual ~DirectoryResource(); 1.45 + 1.46 + /* Server details. */ 1.47 + 1.48 + int expected_items(); 1.49 + 1.50 + ipc_server_handler_type handler(); 1.51 + 1.52 + void *interface() 1.53 + { return static_cast<DirectoryObject *>(this); } 1.54 + 1.55 + /* Directory reading methods. */ 1.56 + 1.57 + virtual long opendir(flags_t flags, offset_t *size, l4_cap_idx_t *cap, 1.58 + object_flags_t *object_flags); 1.59 +}; 1.60 + 1.61 +// vim: tabstop=4 expandtab shiftwidth=4
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/libfsserver/include/fsserver/ext2_directory.h Fri Sep 10 23:57:02 2021 +0200 2.3 @@ -0,0 +1,76 @@ 2.4 +/* 2.5 + * An object for a directory provided by an Ext2-compatible filesystem. 2.6 + * 2.7 + * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk> 2.8 + * 2.9 + * This program is free software; you can redistribute it and/or 2.10 + * modify it under the terms of the GNU General Public License as 2.11 + * published by the Free Software Foundation; either version 2 of 2.12 + * the License, or (at your option) any later version. 2.13 + * 2.14 + * This program is distributed in the hope that it will be useful, 2.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 2.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 2.17 + * GNU General Public License for more details. 2.18 + * 2.19 + * You should have received a copy of the GNU General Public License 2.20 + * along with this program; if not, write to the Free Software 2.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, 2.22 + * Boston, MA 02110-1301, USA 2.23 + */ 2.24 + 2.25 +#pragma once 2.26 + 2.27 +#include <ext2fs/ext2fs.h> 2.28 + 2.29 +#include <fsclient/file.h> 2.30 +#include <fsserver/ext2_file_operations.h> 2.31 +#include <fsserver/directory_resource.h> 2.32 + 2.33 + 2.34 + 2.35 +/* Forward declarations. */ 2.36 + 2.37 +struct Ext2DirectoryState; 2.38 + 2.39 + 2.40 + 2.41 +/* Support for providing access to files. */ 2.42 + 2.43 +class Ext2Directory : public DirectoryResource 2.44 +{ 2.45 +protected: 2.46 + Ext2FileOperations *_ops; 2.47 + fileid_t _fileid; 2.48 + 2.49 + virtual long _opendir(flags_t flags, offset_t *size, l4_cap_idx_t *cap, 2.50 + object_flags_t *object_flags); 2.51 + 2.52 +public: 2.53 + explicit Ext2Directory(Ext2FileOperations *ops, fileid_t fileid) 2.54 + : _ops(ops), _fileid(fileid) 2.55 + { 2.56 + } 2.57 + 2.58 + virtual ~Ext2Directory(); 2.59 + 2.60 + /* Helper methods. */ 2.61 + 2.62 + void read_directory(fileid_t fileid, file_t *writer); 2.63 + 2.64 + int write_directory_entry(struct Ext2DirectoryState *dir); 2.65 +}; 2.66 + 2.67 + 2.68 + 2.69 +/* Helper structures. */ 2.70 + 2.71 +struct Ext2DirectoryState 2.72 +{ 2.73 + Ext2Directory *directory; 2.74 + file_t *writer; 2.75 + struct ext2_dir_entry *entry; 2.76 + long offset; 2.77 +}; 2.78 + 2.79 +// vim: tabstop=4 expandtab shiftwidth=4
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/libfsserver/include/fsserver/host_directory.h Fri Sep 10 23:57:02 2021 +0200 3.3 @@ -0,0 +1,40 @@ 3.4 +/* 3.5 + * An object for a "host" directory provided via the C library. 3.6 + * 3.7 + * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk> 3.8 + * 3.9 + * This program is free software; you can redistribute it and/or 3.10 + * modify it under the terms of the GNU General Public License as 3.11 + * published by the Free Software Foundation; either version 2 of 3.12 + * the License, or (at your option) any later version. 3.13 + * 3.14 + * This program is distributed in the hope that it will be useful, 3.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 3.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 3.17 + * GNU General Public License for more details. 3.18 + * 3.19 + * You should have received a copy of the GNU General Public License 3.20 + * along with this program; if not, write to the Free Software 3.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, 3.22 + * Boston, MA 02110-1301, USA 3.23 + */ 3.24 + 3.25 +#pragma once 3.26 + 3.27 +#include <fsserver/directory_resource.h> 3.28 + 3.29 + 3.30 + 3.31 +/* Support for providing access to directories. */ 3.32 + 3.33 +class HostDirectory : public DirectoryResource 3.34 +{ 3.35 +protected: 3.36 + virtual long _opendir(flags_t flags, offset_t *size, l4_cap_idx_t *cap, 3.37 + object_flags_t *object_flags); 3.38 + 3.39 +public: 3.40 + virtual ~HostDirectory(); 3.41 +}; 3.42 + 3.43 +// vim: tabstop=4 expandtab shiftwidth=4
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/libfsserver/lib/directories/directory_resource.cc Fri Sep 10 23:57:02 2021 +0200 4.3 @@ -0,0 +1,63 @@ 4.4 +/* 4.5 + * A resource offering support for accessing directories. 4.6 + * 4.7 + * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk> 4.8 + * 4.9 + * This program is free software; you can redistribute it and/or 4.10 + * modify it under the terms of the GNU General Public License as 4.11 + * published by the Free Software Foundation; either version 2 of 4.12 + * the License, or (at your option) any later version. 4.13 + * 4.14 + * This program is distributed in the hope that it will be useful, 4.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 4.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 4.17 + * GNU General Public License for more details. 4.18 + * 4.19 + * You should have received a copy of the GNU General Public License 4.20 + * along with this program; if not, write to the Free Software 4.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, 4.22 + * Boston, MA 02110-1301, USA 4.23 + */ 4.24 + 4.25 +#include <ipc/cap_alloc.h> 4.26 + 4.27 +#include "directory_resource.h" 4.28 +#include "directory_object_server.h" 4.29 + 4.30 + 4.31 + 4.32 +int DirectoryResource::expected_items() 4.33 +{ 4.34 + return DirectoryObject_expected_items; 4.35 +} 4.36 + 4.37 +ipc_server_handler_type DirectoryResource::handler() 4.38 +{ 4.39 + return (ipc_server_handler_type) handle_DirectoryObject; 4.40 +} 4.41 + 4.42 + 4.43 + 4.44 +/* Open a directory to read the directory entries via a file-like object. */ 4.45 + 4.46 +long DirectoryResource::opendir(flags_t flags, offset_t *size, 4.47 + l4_cap_idx_t *file, object_flags_t *object_flags) 4.48 +{ 4.49 + /* Invoke the specialised directory opening method. */ 4.50 + 4.51 + long err = _opendir(flags, size, file, object_flags); 4.52 + 4.53 + /* Handle propagated capabilities. By indicating the special status, the 4.54 + operation is first completed and then the capability is discarded. */ 4.55 + 4.56 + if (err == IPC_MESSAGE_SENT) 4.57 + { 4.58 + complete_DirectoryObject_open(*size, *file, *object_flags); 4.59 + ipc_cap_free_um(*file); 4.60 + return IPC_MESSAGE_SENT; 4.61 + } 4.62 + 4.63 + return err; 4.64 +} 4.65 + 4.66 +// vim: tabstop=4 expandtab shiftwidth=4
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/libfsserver/lib/directories/ext2_directory.cc Fri Sep 10 23:57:02 2021 +0200 5.3 @@ -0,0 +1,184 @@ 5.4 +/* 5.5 + * An object for a directory provided by an Ext2-compatible filesystem. 5.6 + * 5.7 + * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk> 5.8 + * 5.9 + * This program is free software; you can redistribute it and/or 5.10 + * modify it under the terms of the GNU General Public License as 5.11 + * published by the Free Software Foundation; either version 2 of 5.12 + * the License, or (at your option) any later version. 5.13 + * 5.14 + * This program is distributed in the hope that it will be useful, 5.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 5.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 5.17 + * GNU General Public License for more details. 5.18 + * 5.19 + * You should have received a copy of the GNU General Public License 5.20 + * along with this program; if not, write to the Free Software 5.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, 5.22 + * Boston, MA 02110-1301, USA 5.23 + */ 5.24 + 5.25 +#include <dirent.h> 5.26 +#include <string.h> 5.27 + 5.28 +#include <thread> 5.29 + 5.30 +#include <fsclient/client.h> 5.31 + 5.32 +#include "ext2_directory.h" 5.33 + 5.34 + 5.35 + 5.36 +/* Common definitions. */ 5.37 + 5.38 +#define DIRENT_CORE_SIZE (sizeof(struct dirent) - sizeof(((struct dirent *) 0)->d_name)) 5.39 + 5.40 +/* File type conversion. */ 5.41 + 5.42 +static int convert_file_type(int type) 5.43 +{ 5.44 + switch (type) 5.45 + { 5.46 + case EXT2_FT_REG_FILE: return DT_REG; 5.47 + case EXT2_FT_DIR: return DT_DIR; 5.48 + case EXT2_FT_CHRDEV: return DT_CHR; 5.49 + case EXT2_FT_BLKDEV: return DT_BLK; 5.50 + case EXT2_FT_FIFO: return DT_FIFO; 5.51 + case EXT2_FT_SOCK: return DT_SOCK; 5.52 + case EXT2_FT_SYMLINK: return DT_LNK; 5.53 + default: return DT_UNKNOWN; 5.54 + } 5.55 +} 5.56 + 5.57 +/* Helper function to ensure alignment in generated entries. */ 5.58 + 5.59 +static int pad_align(int value) 5.60 +{ 5.61 + return value + (sizeof(unsigned int) - (value % sizeof(unsigned int))); 5.62 +} 5.63 + 5.64 +/* Callback function. */ 5.65 + 5.66 +static int read_directory_entry(struct ext2_dir_entry *dir_entry, int offset, 5.67 + int blocksize, char *buf, void *priv_data) 5.68 +{ 5.69 + (void) offset; (void) blocksize; (void) buf; 5.70 + 5.71 + struct Ext2DirectoryState *dir = reinterpret_cast<struct Ext2DirectoryState *>(priv_data); 5.72 + 5.73 + dir->entry = dir_entry; 5.74 + dir->offset = offset; 5.75 + return dir->directory->write_directory_entry(dir); 5.76 +} 5.77 + 5.78 +/* Thread payload. */ 5.79 + 5.80 +static void _read_directory(Ext2Directory *directory, file_t *writer) 5.81 +{ 5.82 + directory->read_directory(writer); 5.83 + 5.84 + client_close(writer); 5.85 +} 5.86 + 5.87 + 5.88 + 5.89 +Ext2Directory::~Ext2Directory() 5.90 +{ 5.91 +} 5.92 + 5.93 +/* Open the directory for directory entry reading. 5.94 + NOTE: This is mostly the same as the HostDirectory implementation. */ 5.95 + 5.96 +long Ext2Directory::_opendir(flags_t flags, offset_t *size, l4_cap_idx_t *cap, 5.97 + object_flags_t *object_flags) 5.98 +{ 5.99 + file_t *reader, *writer; 5.100 + 5.101 + // Mapping of the reader's memory region should be avoided because no use 5.102 + // of the reader will be made here. 5.103 + 5.104 + long err = client_pipe(&reader, &writer, 0); 5.105 + 5.106 + if (err) 5.107 + return err; 5.108 + 5.109 + *size = reader->size; 5.110 + *cap = reader->ref; 5.111 + *object_flags = 0; /* does not support mmap, has no fixed size */ 5.112 + 5.113 + /* Spawn a independent thread for reading the directory details and writing 5.114 + them to the pipe. */ 5.115 + 5.116 + std::thread(_read_directory, this, writer).detach(); 5.117 + 5.118 + /* Discard the reader structure but preserve the capability. */ 5.119 + 5.120 + reader->ref = L4_INVALID_CAP; 5.121 + client_close(reader); 5.122 + 5.123 + /* Return an indication that the capability will be propagated and not 5.124 + retained. This is explicitly supported by the directory resource. */ 5.125 + 5.126 + return IPC_MESSAGE_SENT; 5.127 +} 5.128 + 5.129 +/* Thread payload helper method. */ 5.130 + 5.131 +void Ext2Directory::read_directory(file_t *writer) 5.132 +{ 5.133 + /* Initialise directory reading state: directory, writer, entry, offset. */ 5.134 + 5.135 + struct Ext2DirectoryState dir = {this, writer, NULL, 0}; 5.136 + 5.137 + /* Call the handler function for each directory entry. */ 5.138 + 5.139 + _ops->directory_iterate((ext2_ino_t) _fileid, read_directory_entry, &dir); 5.140 +} 5.141 + 5.142 +/* Callback method for directory entry output. */ 5.143 + 5.144 +int Ext2Directory::write_directory_entry(struct Ext2DirectoryState *dir) 5.145 +{ 5.146 + struct ext2_inode inode; 5.147 + 5.148 + /* Obtain the inode details for metadata. */ 5.149 + 5.150 + if (_ops->read_inode(dir->entry->inode, &inode)) 5.151 + return DIRENT_ABORT; 5.152 + 5.153 + /* Align the size of the entry to avoid problems on architectures which 5.154 + require aligned accesses and where the compiler needs to assume an 5.155 + aligned structure. */ 5.156 + 5.157 + offset_t namelen = ext2fs_dirent_name_len(dir->entry); 5.158 + offset_t reclen = pad_align(DIRENT_CORE_SIZE + namelen); 5.159 + 5.160 + /* Construct a directory entry structure of the calculated size. */ 5.161 + 5.162 + char buffer[reclen]; 5.163 + struct dirent *dirent = (struct dirent *) buffer; 5.164 + 5.165 + dirent->d_ino = dir->entry->inode; 5.166 + dirent->d_off = dir->offset; 5.167 + dirent->d_reclen = reclen; 5.168 + dirent->d_type = convert_file_type(ext2fs_dirent_file_type(dir->entry)); 5.169 + 5.170 + /* Copy the name, padding the memory after it to the alignment boundary. */ 5.171 + 5.172 + memcpy(dirent->d_name, dir->entry->name, namelen); 5.173 + memset(dirent->d_name + namelen, 0, reclen - namelen); 5.174 + 5.175 + /* Write the structure to the pipe. */ 5.176 + 5.177 + offset_t nwritten = client_write(dir->writer, (const void *) dirent, reclen); 5.178 + 5.179 + /* Stop writing if the pipe is closed. */ 5.180 + 5.181 + if (nwritten < reclen) 5.182 + return DIRENT_ABORT; 5.183 + 5.184 + return 0; 5.185 +} 5.186 + 5.187 +// vim: tabstop=4 expandtab shiftwidth=4
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/libfsserver/lib/directories/host_directory.cc Fri Sep 10 23:57:02 2021 +0200 6.3 @@ -0,0 +1,92 @@ 6.4 +/* 6.5 + * An object for a "host" directory provided via the C library. 6.6 + * 6.7 + * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk> 6.8 + * 6.9 + * This program is free software; you can redistribute it and/or 6.10 + * modify it under the terms of the GNU General Public License as 6.11 + * published by the Free Software Foundation; either version 2 of 6.12 + * the License, or (at your option) any later version. 6.13 + * 6.14 + * This program is distributed in the hope that it will be useful, 6.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 6.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 6.17 + * GNU General Public License for more details. 6.18 + * 6.19 + * You should have received a copy of the GNU General Public License 6.20 + * along with this program; if not, write to the Free Software 6.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, 6.22 + * Boston, MA 02110-1301, USA 6.23 + */ 6.24 + 6.25 +#include <thread> 6.26 + 6.27 +#include <dirent.h> 6.28 + 6.29 +#include <fsclient/client.h> 6.30 + 6.31 +#include "host_directory.h" 6.32 + 6.33 + 6.34 + 6.35 +/* Thread payload. */ 6.36 + 6.37 +static void read_directory(const char *path, file_t *writer) 6.38 +{ 6.39 + DIR *dir = opendir(path); 6.40 + struct dirent *dirent; 6.41 + 6.42 + /* Write directory entries to the pipe, closing the pipe when finished. */ 6.43 + 6.44 + while ((dirent = readdir(dir)) != NULL) 6.45 + { 6.46 + offset_t nwritten = client_write(writer, (const void *) dirent, dirent->d_reclen); 6.47 + 6.48 + /* Stop writing if the pipe is closed. */ 6.49 + 6.50 + if (nwritten < dirent->d_reclen) 6.51 + break; 6.52 + } 6.53 + 6.54 + client_close(writer); 6.55 +} 6.56 + 6.57 + 6.58 + 6.59 +HostDirectory::~HostDirectory() 6.60 +{ 6.61 +} 6.62 + 6.63 +/* Open a directory for reading directory entries. */ 6.64 + 6.65 +long HostDirectory::_opendir(flags_t flags, offset_t *size, l4_cap_idx_t *cap, 6.66 + object_flags_t *object_flags) 6.67 +{ 6.68 + file_t *reader, *writer; 6.69 + 6.70 + /* Mapping of the reader's memory region should be avoided because no use 6.71 + of the reader will be made here. */ 6.72 + 6.73 + long err = client_pipe(&reader, &writer, 0); 6.74 + 6.75 + if (err) 6.76 + return err; 6.77 + 6.78 + *size = reader->size; 6.79 + *cap = reader->ref; 6.80 + *object_flags = 0; /* does not support mmap, has no fixed size */ 6.81 + 6.82 + /* Discard the reader structure but preserve the capability. */ 6.83 + 6.84 + reader->ref = L4_INVALID_CAP; 6.85 + file_close(reader); 6.86 + 6.87 + /* Spawn a independent thread for reading the directory details and writing 6.88 + them to the pipe. */ 6.89 + 6.90 + std::thread(read_directory, path, writer).detach(); 6.91 + 6.92 + return L4_EOK; 6.93 +} 6.94 + 6.95 +// vim: tabstop=4 expandtab shiftwidth=4
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/libsystypes/idl/directory.idl Fri Sep 10 23:57:02 2021 +0200 7.3 @@ -0,0 +1,14 @@ 7.4 +#include <systypes/base.h> /* flags_t, object_flags_t, offset_t */ 7.5 + 7.6 +/* An interface to a filesystem directory. */ 7.7 + 7.8 +interface Directory 7.9 +{ 7.10 + /* Obtain a file reference for reading directory entries. */ 7.11 + 7.12 + [opcode(26)] void opendir(in flags_t flags, out offset_t size, out cap file, 7.13 + out object_flags_t object_flags); 7.14 +}; 7.15 + 7.16 +/* vim: tabstop=2 expandtab shiftwidth=2 7.17 +*/