1.1 --- a/libfsserver/lib/files/ext2_file_opener.cc Fri Aug 06 19:30:20 2021 +0200
1.2 +++ b/libfsserver/lib/files/ext2_file_opener.cc Fri Aug 06 19:32:06 2021 +0200
1.3 @@ -19,13 +19,83 @@
1.4 * Boston, MA 02110-1301, USA
1.5 */
1.6
1.7 +#include <dirent.h>
1.8 +#include <string.h>
1.9 +
1.10 +#include <thread>
1.11 +
1.12 #include <e2access/path.h>
1.13 -
1.14 +#include <fsclient/client.h>
1.15 #include <systypes/fcntl.h>
1.16
1.17 #include "ext2_file_accessor.h"
1.18 #include "ext2_file_opener.h"
1.19
1.20 +
1.21 +
1.22 +/* Common definitions. */
1.23 +
1.24 +#define DIRENT_CORE_SIZE (sizeof(struct dirent) - sizeof(((struct dirent *) 0)->d_name))
1.25 +
1.26 +/* File type conversion. */
1.27 +
1.28 +static int convert_file_type(int type)
1.29 +{
1.30 + switch (type)
1.31 + {
1.32 + case EXT2_FT_REG_FILE: return DT_REG;
1.33 + case EXT2_FT_DIR: return DT_DIR;
1.34 + case EXT2_FT_CHRDEV: return DT_CHR;
1.35 + case EXT2_FT_BLKDEV: return DT_BLK;
1.36 + case EXT2_FT_FIFO: return DT_FIFO;
1.37 + case EXT2_FT_SOCK: return DT_SOCK;
1.38 + case EXT2_FT_SYMLINK: return DT_LNK;
1.39 + default: return DT_UNKNOWN;
1.40 + }
1.41 +}
1.42 +
1.43 +/* Helper function to ensure alignment in generated entries. */
1.44 +
1.45 +static int pad_align(int value)
1.46 +{
1.47 + return value + (sizeof(unsigned int) - (value % sizeof(unsigned int)));
1.48 +}
1.49 +
1.50 +/* Callback function. */
1.51 +
1.52 +static int read_directory_entry(struct ext2_dir_entry *dir_entry, int offset,
1.53 + int blocksize, char *buf, void *priv_data)
1.54 +{
1.55 + (void) offset; (void) blocksize; (void) buf;
1.56 +
1.57 + struct Ext2FileOpenerDir *dir = reinterpret_cast<struct Ext2FileOpenerDir *>(priv_data);
1.58 +
1.59 + dir->entry = dir_entry;
1.60 + dir->offset = offset;
1.61 + return dir->opener->write_directory_entry(dir);
1.62 +}
1.63 +
1.64 +/* Thread payload. */
1.65 +
1.66 +static void _read_directory(Ext2FileOpener *opener, fileid_t fileid, file_t *writer)
1.67 +{
1.68 + /* Subscribe to space and closure notifications on the pipe. */
1.69 +
1.70 + long err = client_set_blocking(writer, NOTIFY_SPACE_AVAILABLE);
1.71 +
1.72 + if (err)
1.73 + {
1.74 + client_close(writer);
1.75 + return;
1.76 + }
1.77 +
1.78 + opener->read_directory(fileid, writer);
1.79 +
1.80 + client_close(writer);
1.81 +}
1.82 +
1.83 +
1.84 +
1.85 Ext2FileOpener::~Ext2FileOpener()
1.86 {
1.87 }
1.88 @@ -46,6 +116,93 @@
1.89 return _ops->is_file((ext2_ino_t) fileid);
1.90 }
1.91
1.92 +// NOTE: This is mostly the same as the HostFileOpener implementation.
1.93 +
1.94 +long Ext2FileOpener::get_directory(const char *path, flags_t flags, fileid_t fileid, offset_t *size, l4_cap_idx_t *cap)
1.95 +{
1.96 + (void) path; (void) flags;
1.97 +
1.98 + file_t *reader, *writer;
1.99 +
1.100 + // NOTE: Might be more appropriate to use lower-level file operations to
1.101 + // NOTE: avoid unnecessary mapping of the reader's memory region.
1.102 +
1.103 + long err = client_pipe(&reader, &writer);
1.104 +
1.105 + if (err)
1.106 + return err;
1.107 +
1.108 + *size = reader->size;
1.109 + *cap = reader->ref;
1.110 +
1.111 + /* Discard the reader structure but do not close the reader itself. */
1.112 +
1.113 + delete reader;
1.114 +
1.115 + /* Spawn a independent thread for reading the directory details and writing
1.116 + them to the pipe. */
1.117 +
1.118 + std::thread(_read_directory, this, fileid, writer).detach();
1.119 +
1.120 + return L4_EOK;
1.121 +}
1.122 +
1.123 +/* Thread payload helper method. */
1.124 +
1.125 +void Ext2FileOpener::read_directory(fileid_t fileid, file_t *writer)
1.126 +{
1.127 + /* Initialise directory reading state: opener, writer, entry, offset. */
1.128 +
1.129 + struct Ext2FileOpenerDir dir = {this, writer, NULL, 0};
1.130 +
1.131 + /* Call the handler function for each directory entry. */
1.132 +
1.133 + _ops->directory_iterate((ext2_ino_t) fileid, read_directory_entry, &dir);
1.134 +}
1.135 +
1.136 +/* Callback method for directory entry output. */
1.137 +
1.138 +int Ext2FileOpener::write_directory_entry(struct Ext2FileOpenerDir *dir)
1.139 +{
1.140 + struct ext2_inode inode;
1.141 +
1.142 + /* Obtain the inode details for metadata. */
1.143 +
1.144 + if (_ops->read_inode(dir->entry->inode, &inode))
1.145 + return DIRENT_ABORT;
1.146 +
1.147 + /* Align the size of the entry to avoid problems on architectures which
1.148 + require aligned accesses and where the compiler needs to assume an
1.149 + aligned structure. */
1.150 +
1.151 + offset_t namelen = ext2fs_dirent_name_len(dir->entry);
1.152 + offset_t reclen = pad_align(DIRENT_CORE_SIZE + namelen);
1.153 +
1.154 + /* Construct a directory entry structure of the calculated size. */
1.155 +
1.156 + char buffer[reclen];
1.157 + struct dirent *dirent = (struct dirent *) buffer;
1.158 +
1.159 + dirent->d_ino = dir->entry->inode;
1.160 + dirent->d_off = dir->offset;
1.161 + dirent->d_reclen = reclen;
1.162 + dirent->d_type = convert_file_type(ext2fs_dirent_file_type(dir->entry));
1.163 +
1.164 + /* Copy the name, padding the memory after it to the alignment boundary. */
1.165 +
1.166 + memcpy(dirent->d_name, dir->entry->name, namelen);
1.167 + memset(dirent->d_name + namelen, 0, reclen - namelen);
1.168 +
1.169 + /* Write the structure to the pipe. */
1.170 +
1.171 + offset_t nwritten = 0;
1.172 +
1.173 + while (nwritten < reclen)
1.174 + nwritten += client_write(dir->writer, (const void *) (dirent + nwritten), reclen - nwritten);
1.175 +
1.176 + return 0;
1.177 +}
1.178 +
1.179 /* Return a file identifier for the given 'path'. */
1.180
1.181 long Ext2FileOpener::get_fileid(const char *path, flags_t flags, fileid_t *fileid)