# HG changeset patch # User Paul Boddie # Date 1631311022 -7200 # Node ID 2a5dfbcbba34785409bb2a237dead47e4bd8827d # Parent 955a946c32f3594c377e5125c74fe39375ca1de9 Added directory resources to encapsulate directory access. diff -r 955a946c32f3 -r 2a5dfbcbba34 libfsserver/include/fsserver/directory_resource.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsserver/include/fsserver/directory_resource.h Fri Sep 10 23:57:02 2021 +0200 @@ -0,0 +1,58 @@ +/* + * A resource offering support for directory operations. + * + * Copyright (C) 2021 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include + + + +/* Support for providing access to directories. + NOTE: Notification methods to be added when DirectoryObject is extended. */ + +class DirectoryResource : public Resource, public DirectoryObject +{ +protected: + /* Methods requiring customisation. */ + + virtual long _opendir(flags_t flags, offset_t *size, l4_cap_idx_t *cap, + object_flags_t *object_flags) = 0; + +public: + virtual ~DirectoryResource(); + + /* Server details. */ + + int expected_items(); + + ipc_server_handler_type handler(); + + void *interface() + { return static_cast(this); } + + /* Directory reading methods. */ + + virtual long opendir(flags_t flags, offset_t *size, l4_cap_idx_t *cap, + object_flags_t *object_flags); +}; + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 955a946c32f3 -r 2a5dfbcbba34 libfsserver/include/fsserver/ext2_directory.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsserver/include/fsserver/ext2_directory.h Fri Sep 10 23:57:02 2021 +0200 @@ -0,0 +1,76 @@ +/* + * An object for a directory provided by an Ext2-compatible filesystem. + * + * Copyright (C) 2021 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include + +#include +#include +#include + + + +/* Forward declarations. */ + +struct Ext2DirectoryState; + + + +/* Support for providing access to files. */ + +class Ext2Directory : public DirectoryResource +{ +protected: + Ext2FileOperations *_ops; + fileid_t _fileid; + + virtual long _opendir(flags_t flags, offset_t *size, l4_cap_idx_t *cap, + object_flags_t *object_flags); + +public: + explicit Ext2Directory(Ext2FileOperations *ops, fileid_t fileid) + : _ops(ops), _fileid(fileid) + { + } + + virtual ~Ext2Directory(); + + /* Helper methods. */ + + void read_directory(fileid_t fileid, file_t *writer); + + int write_directory_entry(struct Ext2DirectoryState *dir); +}; + + + +/* Helper structures. */ + +struct Ext2DirectoryState +{ + Ext2Directory *directory; + file_t *writer; + struct ext2_dir_entry *entry; + long offset; +}; + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 955a946c32f3 -r 2a5dfbcbba34 libfsserver/include/fsserver/host_directory.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsserver/include/fsserver/host_directory.h Fri Sep 10 23:57:02 2021 +0200 @@ -0,0 +1,40 @@ +/* + * An object for a "host" directory provided via the C library. + * + * Copyright (C) 2021 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include + + + +/* Support for providing access to directories. */ + +class HostDirectory : public DirectoryResource +{ +protected: + virtual long _opendir(flags_t flags, offset_t *size, l4_cap_idx_t *cap, + object_flags_t *object_flags); + +public: + virtual ~HostDirectory(); +}; + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 955a946c32f3 -r 2a5dfbcbba34 libfsserver/lib/directories/directory_resource.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsserver/lib/directories/directory_resource.cc Fri Sep 10 23:57:02 2021 +0200 @@ -0,0 +1,63 @@ +/* + * A resource offering support for accessing directories. + * + * Copyright (C) 2021 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include + +#include "directory_resource.h" +#include "directory_object_server.h" + + + +int DirectoryResource::expected_items() +{ + return DirectoryObject_expected_items; +} + +ipc_server_handler_type DirectoryResource::handler() +{ + return (ipc_server_handler_type) handle_DirectoryObject; +} + + + +/* Open a directory to read the directory entries via a file-like object. */ + +long DirectoryResource::opendir(flags_t flags, offset_t *size, + l4_cap_idx_t *file, object_flags_t *object_flags) +{ + /* Invoke the specialised directory opening method. */ + + long err = _opendir(flags, size, file, object_flags); + + /* Handle propagated capabilities. By indicating the special status, the + operation is first completed and then the capability is discarded. */ + + if (err == IPC_MESSAGE_SENT) + { + complete_DirectoryObject_open(*size, *file, *object_flags); + ipc_cap_free_um(*file); + return IPC_MESSAGE_SENT; + } + + return err; +} + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 955a946c32f3 -r 2a5dfbcbba34 libfsserver/lib/directories/ext2_directory.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsserver/lib/directories/ext2_directory.cc Fri Sep 10 23:57:02 2021 +0200 @@ -0,0 +1,184 @@ +/* + * An object for a directory provided by an Ext2-compatible filesystem. + * + * Copyright (C) 2021 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include + +#include + +#include + +#include "ext2_directory.h" + + + +/* Common definitions. */ + +#define DIRENT_CORE_SIZE (sizeof(struct dirent) - sizeof(((struct dirent *) 0)->d_name)) + +/* File type conversion. */ + +static int convert_file_type(int type) +{ + switch (type) + { + case EXT2_FT_REG_FILE: return DT_REG; + case EXT2_FT_DIR: return DT_DIR; + case EXT2_FT_CHRDEV: return DT_CHR; + case EXT2_FT_BLKDEV: return DT_BLK; + case EXT2_FT_FIFO: return DT_FIFO; + case EXT2_FT_SOCK: return DT_SOCK; + case EXT2_FT_SYMLINK: return DT_LNK; + default: return DT_UNKNOWN; + } +} + +/* Helper function to ensure alignment in generated entries. */ + +static int pad_align(int value) +{ + return value + (sizeof(unsigned int) - (value % sizeof(unsigned int))); +} + +/* Callback function. */ + +static int read_directory_entry(struct ext2_dir_entry *dir_entry, int offset, + int blocksize, char *buf, void *priv_data) +{ + (void) offset; (void) blocksize; (void) buf; + + struct Ext2DirectoryState *dir = reinterpret_cast(priv_data); + + dir->entry = dir_entry; + dir->offset = offset; + return dir->directory->write_directory_entry(dir); +} + +/* Thread payload. */ + +static void _read_directory(Ext2Directory *directory, file_t *writer) +{ + directory->read_directory(writer); + + client_close(writer); +} + + + +Ext2Directory::~Ext2Directory() +{ +} + +/* Open the directory for directory entry reading. + NOTE: This is mostly the same as the HostDirectory implementation. */ + +long Ext2Directory::_opendir(flags_t flags, offset_t *size, l4_cap_idx_t *cap, + object_flags_t *object_flags) +{ + file_t *reader, *writer; + + // Mapping of the reader's memory region should be avoided because no use + // of the reader will be made here. + + long err = client_pipe(&reader, &writer, 0); + + if (err) + return err; + + *size = reader->size; + *cap = reader->ref; + *object_flags = 0; /* does not support mmap, has no fixed size */ + + /* Spawn a independent thread for reading the directory details and writing + them to the pipe. */ + + std::thread(_read_directory, this, writer).detach(); + + /* Discard the reader structure but preserve the capability. */ + + reader->ref = L4_INVALID_CAP; + client_close(reader); + + /* Return an indication that the capability will be propagated and not + retained. This is explicitly supported by the directory resource. */ + + return IPC_MESSAGE_SENT; +} + +/* Thread payload helper method. */ + +void Ext2Directory::read_directory(file_t *writer) +{ + /* Initialise directory reading state: directory, writer, entry, offset. */ + + struct Ext2DirectoryState dir = {this, writer, NULL, 0}; + + /* Call the handler function for each directory entry. */ + + _ops->directory_iterate((ext2_ino_t) _fileid, read_directory_entry, &dir); +} + +/* Callback method for directory entry output. */ + +int Ext2Directory::write_directory_entry(struct Ext2DirectoryState *dir) +{ + struct ext2_inode inode; + + /* Obtain the inode details for metadata. */ + + if (_ops->read_inode(dir->entry->inode, &inode)) + return DIRENT_ABORT; + + /* Align the size of the entry to avoid problems on architectures which + require aligned accesses and where the compiler needs to assume an + aligned structure. */ + + offset_t namelen = ext2fs_dirent_name_len(dir->entry); + offset_t reclen = pad_align(DIRENT_CORE_SIZE + namelen); + + /* Construct a directory entry structure of the calculated size. */ + + char buffer[reclen]; + struct dirent *dirent = (struct dirent *) buffer; + + dirent->d_ino = dir->entry->inode; + dirent->d_off = dir->offset; + dirent->d_reclen = reclen; + dirent->d_type = convert_file_type(ext2fs_dirent_file_type(dir->entry)); + + /* Copy the name, padding the memory after it to the alignment boundary. */ + + memcpy(dirent->d_name, dir->entry->name, namelen); + memset(dirent->d_name + namelen, 0, reclen - namelen); + + /* Write the structure to the pipe. */ + + offset_t nwritten = client_write(dir->writer, (const void *) dirent, reclen); + + /* Stop writing if the pipe is closed. */ + + if (nwritten < reclen) + return DIRENT_ABORT; + + return 0; +} + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 955a946c32f3 -r 2a5dfbcbba34 libfsserver/lib/directories/host_directory.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsserver/lib/directories/host_directory.cc Fri Sep 10 23:57:02 2021 +0200 @@ -0,0 +1,92 @@ +/* + * An object for a "host" directory provided via the C library. + * + * Copyright (C) 2021 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include + +#include + +#include + +#include "host_directory.h" + + + +/* Thread payload. */ + +static void read_directory(const char *path, file_t *writer) +{ + DIR *dir = opendir(path); + struct dirent *dirent; + + /* Write directory entries to the pipe, closing the pipe when finished. */ + + while ((dirent = readdir(dir)) != NULL) + { + offset_t nwritten = client_write(writer, (const void *) dirent, dirent->d_reclen); + + /* Stop writing if the pipe is closed. */ + + if (nwritten < dirent->d_reclen) + break; + } + + client_close(writer); +} + + + +HostDirectory::~HostDirectory() +{ +} + +/* Open a directory for reading directory entries. */ + +long HostDirectory::_opendir(flags_t flags, offset_t *size, l4_cap_idx_t *cap, + object_flags_t *object_flags) +{ + file_t *reader, *writer; + + /* Mapping of the reader's memory region should be avoided because no use + of the reader will be made here. */ + + long err = client_pipe(&reader, &writer, 0); + + if (err) + return err; + + *size = reader->size; + *cap = reader->ref; + *object_flags = 0; /* does not support mmap, has no fixed size */ + + /* Discard the reader structure but preserve the capability. */ + + reader->ref = L4_INVALID_CAP; + file_close(reader); + + /* Spawn a independent thread for reading the directory details and writing + them to the pipe. */ + + std::thread(read_directory, path, writer).detach(); + + return L4_EOK; +} + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 955a946c32f3 -r 2a5dfbcbba34 libsystypes/idl/directory.idl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/idl/directory.idl Fri Sep 10 23:57:02 2021 +0200 @@ -0,0 +1,14 @@ +#include /* flags_t, object_flags_t, offset_t */ + +/* An interface to a filesystem directory. */ + +interface Directory +{ + /* Obtain a file reference for reading directory entries. */ + + [opcode(26)] void opendir(in flags_t flags, out offset_t size, out cap file, + out object_flags_t object_flags); +}; + +/* vim: tabstop=2 expandtab shiftwidth=2 +*/