# HG changeset patch # User Paul Boddie # Date 1632093419 -7200 # Node ID 85396ddb32608faf4e5011923d46c377ac30fbd2 # Parent 2eb7fd1dc939a316060a1e69b32f83f5959e39df Introduced directory resource, provider and accessor objects. The opendir operation has been moved from the opener to the directory resource, and the opener resource and file paging coordinator now support the creation of directory-related objects. diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsclient/include/fsclient/client.h --- a/libfsclient/include/fsclient/client.h Sat Sep 18 18:51:43 2021 +0200 +++ b/libfsclient/include/fsclient/client.h Mon Sep 20 01:16:59 2021 +0200 @@ -39,8 +39,7 @@ file_t *client_open(const char *name, flags_t flags); file_t *client_open_using(const char *name, flags_t flags, l4_cap_idx_t server); -file_t *client_opendir(const char *name); -file_t *client_opendir_using(const char *name, l4_cap_idx_t server); +file_t *client_opendir(file_t *file); long client_pipe(file_t **reader, file_t **writer, flags_t flags); long client_pipe_using(file_t **reader, file_t **writer, flags_t flags, l4_cap_idx_t server); diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsclient/include/fsclient/file.h --- a/libfsclient/include/fsclient/file.h Sat Sep 18 18:51:43 2021 +0200 +++ b/libfsclient/include/fsclient/file.h Mon Sep 20 01:16:59 2021 +0200 @@ -145,6 +145,12 @@ +/* Directory operations. */ + +long directory_opendir(file_t *file, file_t *reader); + + + EXTERN_C_END // vim: tabstop=2 expandtab shiftwidth=2 diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsclient/lib/src/Makefile --- a/libfsclient/lib/src/Makefile Sat Sep 18 18:51:43 2021 +0200 +++ b/libfsclient/lib/src/Makefile Mon Sep 20 01:16:59 2021 +0200 @@ -15,7 +15,9 @@ # Individual interfaces. -CLIENT_INTERFACES_CC = dataspace file filesystem flush mapped_file notification opener opener_context pipe pipe_opener +CLIENT_INTERFACES_CC = dataspace directory file filesystem flush \ + mapped_file notification opener \ + opener_context pipe pipe_opener # Generated and plain source files. diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsclient/lib/src/client.cc --- a/libfsclient/lib/src/client.cc Sat Sep 18 18:51:43 2021 +0200 +++ b/libfsclient/lib/src/client.cc Mon Sep 20 01:16:59 2021 +0200 @@ -247,34 +247,33 @@ -/* Open a directory. */ +/* Open a directory listing stream via the given directory. */ -file_t *client_opendir(const char *name) +file_t *client_opendir(file_t *file) { - l4_cap_idx_t server = l4re_env_get_cap("server"); + if (file == NULL) + return NULL; - return client_opendir_using(name, server); -} - -/* Open a directory using a named capability. */ + file_t *reader = (file_t *) malloc(sizeof(file_t)); -file_t *client_opendir_using(const char *name, l4_cap_idx_t server) -{ - file_t *file = client_open_using(name, O_DIRECTORY, server); + if (reader == NULL) + return NULL; - if (file == NULL) + long err = directory_opendir(file, reader); + + if (err) return NULL; /* Set blocking read mode to be able to conveniently read directory entries from the stream. */ - if (client_set_blocking(file, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED)) + if (client_set_blocking(reader, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED)) { - client_close(file); + client_close(reader); return NULL; } - return file; + return reader; } diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsclient/lib/src/file.cc --- a/libfsclient/lib/src/file.cc Sat Sep 18 18:51:43 2021 +0200 +++ b/libfsclient/lib/src/file.cc Mon Sep 20 01:16:59 2021 +0200 @@ -25,6 +25,7 @@ #include #include "dataspace_client.h" +#include "directory_client.h" #include "file_client.h" #include "filesystem_client.h" #include "flush_client.h" @@ -545,4 +546,15 @@ return -L4_EINVAL; } + + +/* Obtain a directory listing stream from a directory. */ + +long directory_opendir(file_t *file, file_t *reader) +{ + client_Directory directory(file->ref); + file_init(reader); + return directory.opendir(&reader->size, &reader->ref, &reader->object_flags); +} + // vim: tabstop=2 expandtab shiftwidth=2 diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsserver/include/fsserver/directory_accessor.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsserver/include/fsserver/directory_accessor.h Mon Sep 20 01:16:59 2021 +0200 @@ -0,0 +1,38 @@ +/* + * An object providing access to a filesystem directory. + * + * 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 + + + +/* An object providing access to a directory. */ + +class DirectoryAccessor +{ +public: + virtual ~DirectoryAccessor(); + + virtual void read_directory(file_t *writer) = 0; +}; + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsserver/include/fsserver/directory_provider.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsserver/include/fsserver/directory_provider.h Mon Sep 20 01:16:59 2021 +0200 @@ -0,0 +1,44 @@ +/* + * An object providing a directory abstraction with notification facilities. + * + * 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 + + + +/* An object providing access to directory functionality. */ + +class DirectoryProvider : public FileNotification +{ +protected: + DirectoryAccessor *_accessor; + +public: + explicit DirectoryProvider(DirectoryAccessor *accessor); + + virtual ~DirectoryProvider(); + + virtual DirectoryAccessor *accessor(); +}; + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsserver/include/fsserver/directory_resource.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsserver/include/fsserver/directory_resource.h Mon Sep 20 01:16:59 2021 +0200 @@ -0,0 +1,65 @@ +/* + * 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 +#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: + FileRegistry *_registry; + DirectoryProvider *_provider; + +public: + fileid_t fileid; + + DirectoryResource(fileid_t fileid, DirectoryProvider *provider, + FileRegistry *registry); + + virtual ~DirectoryResource(); + + virtual void close(); + + /* Server details. */ + + int expected_items(); + + ipc_server_handler_type handler(); + + void *interface() + { return static_cast(this); } + + /* Directory reading methods. */ + + virtual long opendir(offset_t *size, l4_cap_idx_t *cap, + object_flags_t *object_flags); +}; + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsserver/include/fsserver/ext2_directory_accessor.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsserver/include/fsserver/ext2_directory_accessor.h Mon Sep 20 01:16:59 2021 +0200 @@ -0,0 +1,72 @@ +/* + * 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 Ext2DirectoryAccessor : public DirectoryAccessor +{ +protected: + Ext2FileOperations *_ops; + fileid_t _fileid; + +public: + explicit Ext2DirectoryAccessor(Ext2FileOperations *ops, fileid_t fileid); + + virtual ~Ext2DirectoryAccessor(); + + /* Accessor methods. */ + + virtual void read_directory(file_t *writer); + + /* Helper methods. */ + + int write_directory_entry(struct Ext2DirectoryState *dir); +}; + + + +/* Helper structures. */ + +struct Ext2DirectoryState +{ + Ext2DirectoryAccessor *directory; + file_t *writer; + struct ext2_dir_entry *entry; + long offset; +}; + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsserver/include/fsserver/ext2_file_opener.h --- a/libfsserver/include/fsserver/ext2_file_opener.h Sat Sep 18 18:51:43 2021 +0200 +++ b/libfsserver/include/fsserver/ext2_file_opener.h Mon Sep 20 01:16:59 2021 +0200 @@ -30,12 +30,6 @@ -/* Forward declarations. */ - -struct Ext2FileOpenerDir; - - - /* Support for providing access to files. */ class Ext2FileOpener : public OpenerResource @@ -50,12 +44,6 @@ virtual bool accessing_file(const char *path, flags_t flags, fileid_t fileid); - /* Convenience methods obtaining different pager types. */ - - virtual long get_directory(const char *path, flags_t flags, fileid_t fileid, - offset_t *size, l4_cap_idx_t *cap, - object_flags_t *object_flags); - public: explicit Ext2FileOpener(FilePaging *paging, Ext2FileOperations *ops, user_t user) : OpenerResource(paging), _ops(ops), _user(user) @@ -64,29 +52,16 @@ virtual ~Ext2FileOpener(); - /* Configurable methods. */ + /* File opening methods. */ virtual long get_fileid(const char *path, flags_t flags, fileid_t *fileid); - virtual long make_accessor(const char *path, flags_t flags, fileid_t fileid, Accessor **accessor); - - /* Helper methods. */ - - void read_directory(fileid_t fileid, file_t *writer); - - int write_directory_entry(struct Ext2FileOpenerDir *dir); -}; - + virtual long make_accessor(const char *path, flags_t flags, fileid_t fileid, + Accessor **accessor); - -/* Helper structures. */ - -struct Ext2FileOpenerDir -{ - Ext2FileOpener *opener; - file_t *writer; - struct ext2_dir_entry *entry; - long offset; + virtual long make_directory_accessor(const char *path, flags_t flags, + fileid_t fileid, + DirectoryAccessor **accessor); }; // vim: tabstop=4 expandtab shiftwidth=4 diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsserver/include/fsserver/file_opening.h --- a/libfsserver/include/fsserver/file_opening.h Sat Sep 18 18:51:43 2021 +0200 +++ b/libfsserver/include/fsserver/file_opening.h Mon Sep 20 01:16:59 2021 +0200 @@ -22,6 +22,7 @@ #pragma once #include +#include @@ -32,7 +33,12 @@ public: virtual long get_fileid(const char *path, flags_t flags, fileid_t *fileid) = 0; - virtual long make_accessor(const char *path, flags_t flags, fileid_t fileid, Accessor **accessor) = 0; + virtual long make_accessor(const char *path, flags_t flags, fileid_t fileid, + Accessor **accessor) = 0; + + virtual long make_directory_accessor(const char *path, flags_t flags, + fileid_t fileid, + DirectoryAccessor **accessor) = 0; }; // vim: tabstop=4 expandtab shiftwidth=4 diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsserver/include/fsserver/file_pager.h --- a/libfsserver/include/fsserver/file_pager.h Sat Sep 18 18:51:43 2021 +0200 +++ b/libfsserver/include/fsserver/file_pager.h Mon Sep 20 01:16:59 2021 +0200 @@ -23,7 +23,8 @@ #include #include -#include +#include +#include @@ -32,7 +33,7 @@ class FilePager : public Pager, public MappedFileObject { protected: - FilePaging *_paging; + FileRegistry *_registry; FileProvider *_provider; /* Notification endpoint for event subscription. */ @@ -47,7 +48,7 @@ fileid_t fileid; explicit FilePager(fileid_t fileid, FileProvider *provider, map_flags_t flags, - FilePaging *paging); + FileRegistry *registry); virtual void close(); diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsserver/include/fsserver/file_paging.h --- a/libfsserver/include/fsserver/file_paging.h Sat Sep 18 18:51:43 2021 +0200 +++ b/libfsserver/include/fsserver/file_paging.h Mon Sep 20 01:16:59 2021 +0200 @@ -21,57 +21,44 @@ #pragma once -#include -#include - -#include +#include #include #include +#include #include #include -/* Mapping type from file identifiers to page mappers. */ - -typedef std::map FileMapping; -typedef std::pair FileMappingEntry; - - - /* A registry of filesystem objects. */ -class FilePaging +class FilePaging : public FileRegistry { protected: Pages *_pages; - FileMapping _providers; - std::mutex _lock; - /* Filesystem object access. */ - - Accountable *get(fileid_t fileid); - - void remove(fileid_t fileid, Accountable *obj); - - void set(fileid_t fileid, Accountable *obj); - - /* Pager initialisation methods. */ + /* Resource initialisation methods. */ map_flags_t get_flags(flags_t flags); - long get_provider(FileOpening *opening, const char *path, flags_t flags, fileid_t fileid, FileProvider **file_provider); + long get_directory_provider(FileOpening *opening, const char *path, + flags_t flags, fileid_t fileid, + DirectoryProvider **directory_provider); + + long get_file_provider(FileOpening *opening, const char *path, + flags_t flags, fileid_t fileid, + FileProvider **file_provider); public: explicit FilePaging(Pages *pages); - /* Pager initialisation methods. */ - - long get_pager(FileOpening *opening, const char *path, flags_t flags, fileid_t fileid, Pager **pager); + /* Resource initialisation methods. */ - /* Methods for the pager. */ + long get_directory(FileOpening *opening, const char *path, flags_t flags, + fileid_t fileid, Resource **resource); - void detach_pager(fileid_t fileid, Accountable *mapper); + long get_pager(FileOpening *opening, const char *path, flags_t flags, + fileid_t fileid, Pager **pager); }; // vim: tabstop=4 expandtab shiftwidth=4 diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsserver/include/fsserver/file_registry.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsserver/include/fsserver/file_registry.h Mon Sep 20 01:16:59 2021 +0200 @@ -0,0 +1,61 @@ +/* + * A registry of filesystem objects. + * + * 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 + + + +/* Mapping type from file identifiers to page mappers. */ + +typedef std::map FileMapping; +typedef std::pair FileMappingEntry; + + + +/* A registry of filesystem objects. */ + +class FileRegistry +{ +protected: + FileMapping _providers; + std::mutex _lock; + + /* Filesystem object access. */ + + Accountable *get(fileid_t fileid); + + void remove(fileid_t fileid, Accountable *obj); + + void set(fileid_t fileid, Accountable *obj); + +public: + /* Methods for resources. */ + + void detach(fileid_t fileid, Accountable *mapper); +}; + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsserver/include/fsserver/host_directory_accessor.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsserver/include/fsserver/host_directory_accessor.h Mon Sep 20 01:16:59 2021 +0200 @@ -0,0 +1,45 @@ +/* + * 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 HostDirectoryAccessor : public DirectoryAccessor +{ +protected: + const char *_path; + +public: + explicit HostDirectoryAccessor(const char *path); + + virtual ~HostDirectoryAccessor(); + + /* Accessor methods. */ + + virtual void read_directory(file_t *writer); +}; + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsserver/include/fsserver/host_file_opener.h --- a/libfsserver/include/fsserver/host_file_opener.h Sat Sep 18 18:51:43 2021 +0200 +++ b/libfsserver/include/fsserver/host_file_opener.h Mon Sep 20 01:16:59 2021 +0200 @@ -54,12 +54,6 @@ virtual bool accessing_file(const char *path, flags_t flags, fileid_t fileid); - /* Convenience methods obtaining different pager types. */ - - virtual long get_directory(const char *path, flags_t flags, fileid_t fileid, - offset_t *size, l4_cap_idx_t *cap, - object_flags_t *object_flags); - public: explicit HostFileOpener(FilePaging *paging) : OpenerResource(paging) @@ -68,11 +62,16 @@ virtual ~HostFileOpener(); - /* Configurable methods. */ + /* File opening methods. */ virtual long get_fileid(const char *path, flags_t flags, fileid_t *fileid); - virtual long make_accessor(const char *path, flags_t flags, fileid_t fileid, Accessor **accessor); + virtual long make_accessor(const char *path, flags_t flags, fileid_t fileid, + Accessor **accessor); + + virtual long make_directory_accessor(const char *path, flags_t flags, + fileid_t fileid, + DirectoryAccessor **accessor); }; // vim: tabstop=4 expandtab shiftwidth=4 diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsserver/include/fsserver/opener_resource.h --- a/libfsserver/include/fsserver/opener_resource.h Sat Sep 18 18:51:43 2021 +0200 +++ b/libfsserver/include/fsserver/opener_resource.h Mon Sep 20 01:16:59 2021 +0200 @@ -42,7 +42,7 @@ virtual bool accessing_file(const char *path, flags_t flags, fileid_t fileid) = 0; - /* Convenience methods obtaining different pager types. */ + /* Convenience methods obtaining different resource types. */ virtual long get_directory(const char *path, flags_t flags, fileid_t fileid, offset_t *size, l4_cap_idx_t *cap, @@ -52,10 +52,6 @@ offset_t *size, l4_cap_idx_t *cap, object_flags_t *object_flags); - /* Preparation of resources for pagers. */ - - long resource_for_pager(Pager *pager, offset_t *size, l4_cap_idx_t *cap); - public: explicit OpenerResource(FilePaging *paging); diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsserver/include/fsserver/test_file_opener.h --- a/libfsserver/include/fsserver/test_file_opener.h Sat Sep 18 18:51:43 2021 +0200 +++ b/libfsserver/include/fsserver/test_file_opener.h Mon Sep 20 01:16:59 2021 +0200 @@ -47,7 +47,12 @@ virtual long get_fileid(const char *path, flags_t flags, fileid_t *fileid); - virtual long make_accessor(const char *path, flags_t flags, fileid_t fileid, Accessor **accessor); + virtual long make_accessor(const char *path, flags_t flags, fileid_t fileid, + Accessor **accessor); + + virtual long make_directory_accessor(const char *path, flags_t flags, + fileid_t fileid, + DirectoryAccessor **accessor); }; // vim: tabstop=4 expandtab shiftwidth=4 diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsserver/lib/Makefile --- a/libfsserver/lib/Makefile Sat Sep 18 18:51:43 2021 +0200 +++ b/libfsserver/lib/Makefile Mon Sep 20 01:16:59 2021 +0200 @@ -15,6 +15,9 @@ # Compound interfaces. +directory_object_NAME = DirectoryObject +directory_object_INTERFACES = directory # notification + filesystem_object_NAME = FilesystemObject filesystem_object_INTERFACES = filesystem filesystem_factory @@ -27,7 +30,7 @@ pipe_object_NAME = PipeObject pipe_object_INTERFACES = dataspace flush notification pipe -COMP_INTERFACES_CC = filesystem_object mapped_file_object opener_context_object pipe_object +COMP_INTERFACES_CC = directory_object filesystem_object mapped_file_object opener_context_object pipe_object # Individual interfaces. @@ -42,6 +45,11 @@ SERVER_INTERFACES_SRC_CC = $(call interfaces_to_server_cc,$(SERVER_INTERFACES_CC) $(COMP_INTERFACES_CC)) PLAIN_SRC_CC = \ + directories/directory_accessor.cc \ + directories/directory_provider.cc \ + directories/directory_resource.cc \ + directories/ext2_directory_accessor.cc \ + directories/host_directory_accessor.cc \ files/block_file_accessor.cc \ files/block_file_opener.cc \ files/ext2_file_accessor.cc \ @@ -52,6 +60,7 @@ files/file_pager.cc \ files/file_paging.cc \ files/file_provider.cc \ + files/file_registry.cc \ files/filesystem_resource.cc \ files/host_file_accessor.cc \ files/host_file_opener.cc \ diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsserver/lib/directories/directory_accessor.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsserver/lib/directories/directory_accessor.cc Mon Sep 20 01:16:59 2021 +0200 @@ -0,0 +1,32 @@ +/* + * An object providing access to a filesystem directory. + * + * 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 "directory_accessor.h" + + + +/* Deallocate the accessor. */ + +DirectoryAccessor::~DirectoryAccessor() +{ +} + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsserver/lib/directories/directory_provider.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsserver/lib/directories/directory_provider.cc Mon Sep 20 01:16:59 2021 +0200 @@ -0,0 +1,46 @@ +/* + * An object providing access to directory functionality. + * + * 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 "directory_provider.h" + + + +/* Initialise the provider. */ + +DirectoryProvider::DirectoryProvider(DirectoryAccessor *accessor) +: FileNotification(), _accessor(accessor) +{ +} + +/* Deallocate the provider's resources. */ + +DirectoryProvider::~DirectoryProvider() +{ +} + +/* Return the accessor. */ + +DirectoryAccessor *DirectoryProvider::accessor() +{ + return _accessor; +} + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsserver/lib/directories/directory_resource.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsserver/lib/directories/directory_resource.cc Mon Sep 20 01:16:59 2021 +0200 @@ -0,0 +1,129 @@ +/* + * 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 +#include + +#include "directory_resource.h" +#include "directory_object_server.h" + + + +DirectoryResource::DirectoryResource(fileid_t fileid, + DirectoryProvider *provider, + FileRegistry *registry) +: _registry(registry), _provider(provider), fileid(fileid) +{ +} + +DirectoryResource::~DirectoryResource() +{ +} + + + +int DirectoryResource::expected_items() +{ + return DirectoryObject_expected_items; +} + +ipc_server_handler_type DirectoryResource::handler() +{ + return (ipc_server_handler_type) handle_DirectoryObject; +} + + + +/* Close the resource, removing the provider from the registry if + appropriate. */ + +void DirectoryResource::close() +{ + /* Detach the resource, potentially removing the file provider. */ + + _registry->detach(fileid, _provider); +} + + + +/* Thread payload for directory listing production. */ + +static void read_directory(FileRegistry *registry, DirectoryProvider *provider, + fileid_t fileid, file_t *writer) +{ + DirectoryAccessor *accessor = provider->accessor(); + + /* Attach to the provider to keep it available, even if the directory + resource is released. */ + + provider->attach(); + + /* Invoke the directory reading mechanism. */ + + accessor->read_directory(writer); + + /* Close and detach from the registry. */ + + client_close(writer); + registry->detach(fileid, provider); +} + + + +/* Open a directory to read the directory entries via a file-like object. */ + +long DirectoryResource::opendir(offset_t *size, l4_cap_idx_t *file, + 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; + *file = 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); + + /* Initiate the reading process. */ + + std::thread(read_directory, _registry, _provider, fileid, writer).detach(); + + /* Send the capability immediately, discarding it afterwards. */ + + complete_Directory_opendir(*size, *file, *object_flags); + ipc_cap_free_um(*file); + + return IPC_MESSAGE_SENT; +} + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsserver/lib/directories/ext2_directory_accessor.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsserver/lib/directories/ext2_directory_accessor.cc Mon Sep 20 01:16:59 2021 +0200 @@ -0,0 +1,145 @@ +/* + * 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 "ext2_directory_accessor.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); +} + + + +/* Accessor methods. */ + +Ext2DirectoryAccessor::Ext2DirectoryAccessor(Ext2FileOperations *ops, + fileid_t fileid) +: _ops(ops), _fileid(fileid) +{ +} + +Ext2DirectoryAccessor::~Ext2DirectoryAccessor() +{ +} + +/* Thread payload helper method. */ + +void Ext2DirectoryAccessor::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 Ext2DirectoryAccessor::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 2eb7fd1dc939 -r 85396ddb3260 libfsserver/lib/directories/host_directory_accessor.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsserver/lib/directories/host_directory_accessor.cc Mon Sep 20 01:16:59 2021 +0200 @@ -0,0 +1,57 @@ +/* + * 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 "host_directory_accessor.h" + + + +HostDirectoryAccessor::HostDirectoryAccessor(const char *path) +: _path(path) +{ +} + +HostDirectoryAccessor::~HostDirectoryAccessor() +{ +} + +void HostDirectoryAccessor::read_directory(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; + } +} + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsserver/lib/files/ext2_file_opener.cc --- a/libfsserver/lib/files/ext2_file_opener.cc Sat Sep 18 18:51:43 2021 +0200 +++ b/libfsserver/lib/files/ext2_file_opener.cc Mon Sep 20 01:16:59 2021 +0200 @@ -19,70 +19,16 @@ * Boston, MA 02110-1301, USA */ -#include #include -#include - #include #include #include +#include "ext2_directory_accessor.h" #include "ext2_file_accessor.h" #include "ext2_file_opener.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 Ext2FileOpenerDir *dir = reinterpret_cast(priv_data); - - dir->entry = dir_entry; - dir->offset = offset; - return dir->opener->write_directory_entry(dir); -} - -/* Thread payload. */ - -static void _read_directory(Ext2FileOpener *opener, fileid_t fileid, file_t *writer) -{ - opener->read_directory(fileid, writer); - - client_close(writer); -} +#include "resource_server.h" @@ -106,104 +52,6 @@ return _ops->is_file((ext2_ino_t) fileid); } -// NOTE: This is mostly the same as the HostFileOpener implementation. - -long Ext2FileOpener::get_directory(const char *path, flags_t flags, - fileid_t fileid, offset_t *size, - l4_cap_idx_t *cap, object_flags_t *object_flags) -{ - /* The file identifier is used to obtain the directory. */ - - (void) path; (void) 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, fileid, 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 opener context. */ - - return IPC_MESSAGE_SENT; -} - -/* Thread payload helper method. */ - -void Ext2FileOpener::read_directory(fileid_t fileid, file_t *writer) -{ - /* Initialise directory reading state: opener, writer, entry, offset. */ - - struct Ext2FileOpenerDir 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 Ext2FileOpener::write_directory_entry(struct Ext2FileOpenerDir *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; -} - /* Return a file identifier for the given 'path'. */ long Ext2FileOpener::get_fileid(const char *path, flags_t flags, fileid_t *fileid) @@ -245,7 +93,8 @@ /* Return a new accessor for 'fileid'. */ -long Ext2FileOpener::make_accessor(const char *path, flags_t flags, fileid_t fileid, Accessor **accessor) +long Ext2FileOpener::make_accessor(const char *path, flags_t flags, + fileid_t fileid, Accessor **accessor) { (void) path; (void) flags; @@ -259,4 +108,16 @@ return L4_EOK; } +/* Return a directory object reference for the given file identifier. */ + +long Ext2FileOpener::make_directory_accessor(const char *path, flags_t flags, + fileid_t fileid, + DirectoryAccessor **accessor) +{ + (void) path; (void) flags; + + *accessor = new Ext2DirectoryAccessor(_ops, fileid); + return L4_EOK; +} + // vim: tabstop=4 expandtab shiftwidth=4 diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsserver/lib/files/file_pager.cc --- a/libfsserver/lib/files/file_pager.cc Sat Sep 18 18:51:43 2021 +0200 +++ b/libfsserver/lib/files/file_pager.cc Mon Sep 20 01:16:59 2021 +0200 @@ -25,13 +25,13 @@ /* Initialise a pager for a file with a unique file identifier, file provider, - mapping flags and a file paging coordinator. The provider offers a shared - page mapper for moderating access to loaded pages. */ + mapping flags and a file registry. The provider offers a shared page mapper + for moderating access to loaded pages. */ FilePager::FilePager(fileid_t fileid, FileProvider *provider, map_flags_t flags, - FilePaging *paging) + FileRegistry *registry) : Pager(provider->mapper(), flags), - _paging(paging), _provider(provider), fileid(fileid) + _registry(registry), _provider(provider), fileid(fileid) { } @@ -57,7 +57,7 @@ /* Detach the pager, potentially removing the file provider. */ - _paging->detach_pager(fileid, _provider); + _registry->detach(fileid, _provider); } diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsserver/lib/files/file_paging.cc --- a/libfsserver/lib/files/file_paging.cc Sat Sep 18 18:51:43 2021 +0200 +++ b/libfsserver/lib/files/file_paging.cc Mon Sep 20 01:16:59 2021 +0200 @@ -1,5 +1,5 @@ /* - * General functionality supporting file paging. + * File registry and opening functionality. * * Copyright (C) 2021 Paul Boddie * @@ -19,6 +19,7 @@ * Boston, MA 02110-1301, USA */ +#include "directory_resource.h" #include "file_pager.h" #include "file_paging.h" @@ -36,44 +37,6 @@ -/* Return any registered provider for the given 'fileid' or NULL if no such - provider is registered. */ - -Accountable *FilePaging::get(fileid_t fileid) -{ - FileMapping::iterator entry = _providers.find(fileid); - Accountable *provider; - - if (entry == _providers.end()) - provider = NULL; - else - provider = entry->second; - - return provider; -} - -/* Remove a provider and its resources for the given 'fileid'. */ - -void FilePaging::remove(fileid_t fileid, Accountable *provider) -{ - _providers.erase(fileid); - delete provider; -} - -/* Register a 'provider' for the given 'fileid'. */ - -void FilePaging::set(fileid_t fileid, Accountable *provider) -{ - FileMapping::iterator entry = _providers.find(fileid); - - if (entry != _providers.end()) - return; - - _providers[fileid] = provider; -} - - - /* Convert opening flags to map-compatible paging flags. */ map_flags_t FilePaging::get_flags(flags_t flags) @@ -83,10 +46,11 @@ -/* Obtain a provider for the 'fileid' or register a new one in the - paging object. */ +/* Obtain a provider for the 'fileid' or register a new one. */ -long FilePaging::get_provider(FileOpening *opening, const char *path, flags_t flags, fileid_t fileid, FileProvider **file_provider) +long FilePaging::get_directory_provider(FileOpening *opening, const char *path, + flags_t flags, fileid_t fileid, + DirectoryProvider **directory_provider) { /* Obtain any registered provider. */ @@ -94,10 +58,42 @@ if (provider != NULL) { - /* Distinguish between file providers and other objects that may be - registered. For files specifically, a file provider is needed - because it will provide a page mapper. */ + *directory_provider = dynamic_cast(provider); + + if ((*directory_provider) != NULL) + return L4_EOK; + else + return -L4_EIO; + } + + /* Make an accessor and a provider to encapsulate it. */ + + DirectoryAccessor *accessor; + long err = opening->make_directory_accessor(path, flags, fileid, &accessor); + + if (err) + return err; + + *directory_provider = new DirectoryProvider(accessor); + /* Register the provider. */ + + set(fileid, *directory_provider); + return L4_EOK; +} + +/* Obtain a provider for the 'fileid' or register a new one. */ + +long FilePaging::get_file_provider(FileOpening *opening, const char *path, + flags_t flags, fileid_t fileid, + FileProvider **file_provider) +{ + /* Obtain any registered provider. */ + + Accountable *provider = get(fileid); + + if (provider != NULL) + { *file_provider = dynamic_cast(provider); if ((*file_provider) != NULL) @@ -125,9 +121,35 @@ +/* Return a directory resource initialised with a provider. */ + +long FilePaging::get_directory(FileOpening *opening, const char *path, + flags_t flags, fileid_t fileid, + Resource **resource) +{ + std::lock_guard guard(_lock); + + /* Obtain any existing provider registered for the object, or make a new + provider. */ + + DirectoryProvider *provider; + long err = get_directory_provider(opening, path, flags, fileid, &provider); + + if (err) + return err; + + /* Initialise the resource with the provider and a reference to this object + for detaching from the provider. */ + + provider->attach(); + *resource = new DirectoryResource(fileid, provider, this); + return L4_EOK; +} + /* Return a pager initialised with a provider, page mapper and accessor. */ -long FilePaging::get_pager(FileOpening *opening, const char *path, flags_t flags, fileid_t fileid, Pager **pager) +long FilePaging::get_pager(FileOpening *opening, const char *path, + flags_t flags, fileid_t fileid, Pager **pager) { std::lock_guard guard(_lock); @@ -135,27 +157,17 @@ provider. */ FileProvider *provider; - long err = get_provider(opening, path, flags, fileid, &provider); + long err = get_file_provider(opening, path, flags, fileid, &provider); if (err) return err; /* Initialise the pager with the provider and a reference to this object for - closing the provider, mapper and accessor. */ + detaching from the provider. */ provider->attach(); *pager = new FilePager(fileid, provider, get_flags(flags), this); return L4_EOK; } -/* Detach a pager, potentially removing its resources. */ - -void FilePaging::detach_pager(fileid_t fileid, Accountable *provider) -{ - std::lock_guard guard(_lock); - - if (!provider->detach()) - remove(fileid, provider); -} - // vim: tabstop=4 expandtab shiftwidth=4 diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsserver/lib/files/file_registry.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsserver/lib/files/file_registry.cc Mon Sep 20 01:16:59 2021 +0200 @@ -0,0 +1,76 @@ +/* + * File registry functionality. + * + * 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 "file_registry.h" + + + +/* Methods for use with the lock already acquired. */ + +/* Return any registered provider for the given 'fileid' or NULL if no such + provider is registered. */ + +Accountable *FileRegistry::get(fileid_t fileid) +{ + FileMapping::iterator entry = _providers.find(fileid); + Accountable *provider; + + if (entry == _providers.end()) + provider = NULL; + else + provider = entry->second; + + return provider; +} + +/* Remove a provider and its resources for the given 'fileid'. */ + +void FileRegistry::remove(fileid_t fileid, Accountable *provider) +{ + _providers.erase(fileid); + delete provider; +} + +/* Register a 'provider' for the given 'fileid'. */ + +void FileRegistry::set(fileid_t fileid, Accountable *provider) +{ + FileMapping::iterator entry = _providers.find(fileid); + + if (entry != _providers.end()) + return; + + _providers[fileid] = provider; +} + + + +/* Detach from a provider, potentially removing it from the registry. */ + +void FileRegistry::detach(fileid_t fileid, Accountable *provider) +{ + std::lock_guard guard(_lock); + + if (!provider->detach()) + remove(fileid, provider); +} + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsserver/lib/files/host_file_opener.cc --- a/libfsserver/lib/files/host_file_opener.cc Sat Sep 18 18:51:43 2021 +0200 +++ b/libfsserver/lib/files/host_file_opener.cc Mon Sep 20 01:16:59 2021 +0200 @@ -19,40 +19,14 @@ * Boston, MA 02110-1301, USA */ -#include - -#include #include #include -#include +#include "host_directory_accessor.h" #include "host_file_accessor.h" #include "host_file_opener.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); -} +#include "resource_server.h" @@ -82,41 +56,6 @@ return (st.st_mode & S_IFREG) ? true : false; } -long HostFileOpener::get_directory(const char *path, flags_t flags, - fileid_t fileid, offset_t *size, - l4_cap_idx_t *cap, object_flags_t *object_flags) -{ - /* The path is used to obtain the directory. */ - - (void) flags; (void) fileid; - - 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; -} - /* Return a file identifier for the given 'path'. */ long HostFileOpener::get_fileid(const char *path, flags_t flags, fileid_t *fileid) @@ -164,7 +103,8 @@ /* Return a new accessor for 'fileid'. */ -long HostFileOpener::make_accessor(const char *path, flags_t flags, fileid_t fileid, Accessor **accessor) +long HostFileOpener::make_accessor(const char *path, flags_t flags, + fileid_t fileid, Accessor **accessor) { // NOTE: Not testing for create or write flags. @@ -179,4 +119,16 @@ return L4_EOK; } +/* Return a directory accessor for 'fileid'. */ + +long HostFileOpener::make_directory_accessor(const char *path, flags_t flags, + fileid_t fileid, + DirectoryAccessor **accessor) +{ + (void) flags; (void) fileid; + + *accessor = new HostDirectoryAccessor(path); + return L4_EOK; +} + // vim: tabstop=4 expandtab shiftwidth=4 diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsserver/lib/files/opener_context_resource.cc --- a/libfsserver/lib/files/opener_context_resource.cc Sat Sep 18 18:51:43 2021 +0200 +++ b/libfsserver/lib/files/opener_context_resource.cc Mon Sep 20 01:16:59 2021 +0200 @@ -75,19 +75,7 @@ if (path == NULL) return -L4_EINVAL; - long err = _opener->open(path, 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_OpenerContext_open(*size, *file, *object_flags); - ipc_cap_free_um(*file); - return IPC_MESSAGE_SENT; - } - - return err; + return _opener->open(path, flags, size, file, object_flags); } // vim: tabstop=4 expandtab shiftwidth=4 diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsserver/lib/files/opener_resource.cc --- a/libfsserver/lib/files/opener_resource.cc Sat Sep 18 18:51:43 2021 +0200 +++ b/libfsserver/lib/files/opener_resource.cc Mon Sep 20 01:16:59 2021 +0200 @@ -71,14 +71,25 @@ -/* Return a directory pager. */ +/* Return a directory object reference for the given file identifier. */ long OpenerResource::get_directory(const char *path, flags_t flags, fileid_t fileid, offset_t *size, - l4_cap_idx_t *cap, object_flags_t *object_flags) + l4_cap_idx_t *cap, + object_flags_t *object_flags) { - (void) path; (void) flags; (void) fileid; (void) size; (void) cap; (void) object_flags; - return -L4_EIO; + Resource *directory; + long err = _paging->get_directory(this, path, flags, fileid, &directory); + + if (err) + return err; + + /* Provide non-file values for certain outputs. */ + + *size = 0; + *object_flags = 0; + + return ResourceServer(directory).start_thread(cap); } /* Return a file pager. */ @@ -93,20 +104,11 @@ if (err) return err; - *object_flags = OBJECT_SUPPORTS_MMAP | OBJECT_HAS_SIZE; - - return resource_for_pager(pager, size, cap); -} - -/* Return pager resource details. */ + /* Obtain the size details from the pager, also providing appropriate + flags. */ -long OpenerResource::resource_for_pager(Pager *pager, offset_t *size, l4_cap_idx_t *cap) -{ *size = pager->get_data_size(); - - /* Complete the initialisation and start a server in a new thread. - If the thread does not start, the resource (including pager) will be - finalised. */ + *object_flags = OBJECT_SUPPORTS_MMAP | OBJECT_HAS_SIZE; return ResourceServer(pager).start_thread(cap); } diff -r 2eb7fd1dc939 -r 85396ddb3260 libfsserver/lib/files/test_file_opener.cc --- a/libfsserver/lib/files/test_file_opener.cc Sat Sep 18 18:51:43 2021 +0200 +++ b/libfsserver/lib/files/test_file_opener.cc Mon Sep 20 01:16:59 2021 +0200 @@ -61,11 +61,22 @@ /* Return a new accessor for 'fileid'. */ -long TestFileOpener::make_accessor(const char *path, flags_t flags, fileid_t fileid, Accessor **accessor) +long TestFileOpener::make_accessor(const char *path, flags_t flags, + fileid_t fileid, Accessor **accessor) { (void) flags; (void) path; *accessor = new TestFileAccessor(fileid, _file_size); return L4_EOK; } +/* Return a new directory accessor for 'fileid'. */ + +long TestFileOpener::make_directory_accessor(const char *path, flags_t flags, + fileid_t fileid, + DirectoryAccessor **accessor) +{ + (void) flags; (void) path; (void) fileid; (void) accessor; + return -L4_EIO; +} + // vim: tabstop=4 expandtab shiftwidth=4 diff -r 2eb7fd1dc939 -r 85396ddb3260 libsystypes/idl/directory.idl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/idl/directory.idl Mon Sep 20 01:16:59 2021 +0200 @@ -0,0 +1,14 @@ +#include /* 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(out offset_t size, out cap file, + out object_flags_t object_flags); +}; + +/* vim: tabstop=2 expandtab shiftwidth=2 +*/ diff -r 2eb7fd1dc939 -r 85396ddb3260 tests/dstest_file_readdir.cc --- a/tests/dstest_file_readdir.cc Sat Sep 18 18:51:43 2021 +0200 +++ b/tests/dstest_file_readdir.cc Mon Sep 20 01:16:59 2021 +0200 @@ -47,11 +47,11 @@ /* Invoke the open method to receive the file reference. */ - return client_opendir_using(filename, opener); + return client_open_using(filename, O_DIRECTORY, opener); } else { - return client_opendir(filename); + return client_open(filename, O_DIRECTORY); } } @@ -79,11 +79,19 @@ return 1; } + file_t *reader = client_opendir(file); + + if (reader == NULL) + { + printf("Could not read from directory.\n"); + return 1; + } + printf("Reading...\n"); struct dirent *dirent; - while ((dirent = client_readdir(file)) != NULL) + while ((dirent = client_readdir(reader)) != NULL) { printf("> %s\n", dirent->d_name); free(dirent); @@ -101,7 +109,15 @@ return 1; } - dirent = client_readdir(file); + reader = client_opendir(file); + + if (reader == NULL) + { + printf("Could not read from directory.\n"); + return 1; + } + + dirent = client_readdir(reader); if (dirent != NULL) {