# HG changeset patch # User Paul Boddie # Date 1633211822 -7200 # Node ID dc521e9dbd13ff4f9a0cb8c01325a9811dc188a1 # Parent aa2eb23bd36d43a5cf27281cf7f77b6313235f98 Added tentative support for directory-level notifications. diff -r aa2eb23bd36d -r dc521e9dbd13 conf/dstest_file_monitor.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/dstest_file_monitor.cfg Sat Oct 02 23:57:02 2021 +0200 @@ -0,0 +1,40 @@ +-- vim:set ft=lua: + +local L4 = require("L4"); + +local l = L4.default_loader; + +local blocksvr = l:new_channel(); + +l:startv({ + caps = { + server = blocksvr:svr(), + }, + log = { "blocksvr", "r" }, + }, + "rom/dstest_block_server", "10"); + +local ext2svr = l:new_channel(); + +l:startv({ + caps = { + blocksvr = blocksvr, + ext2svr = ext2svr:svr(), + }, + log = { "ext2svr", "y" }, + }, + "rom/dstest_ext2_server", "blocksvr", "rom/e2test.fs", "10", "ext2svr"); + +-- Obtain user filesystems with umask 0022 (18). + +local open_for_user = 6; +local ext2svr_paulb = L4.cast(L4.Proto.Factory, ext2svr):create(open_for_user, 1000, 1000, 18); + +l:startv({ + caps = { + server = ext2svr_paulb, + }, + log = { "client", "g" }, + }, + -- program, directory to monitor + "rom/dstest_file_monitor", "home/paulb"); diff -r aa2eb23bd36d -r dc521e9dbd13 conf/dstest_file_monitor.list --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/dstest_file_monitor.list Sat Oct 02 23:57:02 2021 +0200 @@ -0,0 +1,27 @@ +entry dstest_file_monitor +roottask moe rom/dstest_file_monitor.cfg +module dstest_file_monitor.cfg +module e2test.fs +module l4re +module ned +module dstest_file_monitor +module dstest_ext2_server +module dstest_block_server +module lib4re-c.so +module lib4re-c-util.so +module lib4re.so +module lib4re-util.so +module libc_be_l4refile.so +module libc_be_l4re.so +module libc_be_socket_noop.so +module libc_support_misc.so +module libdl.so +module libipc.so +module libl4sys-direct.so +module libl4sys.so +module libl4util.so +module libld-l4.so +module libpthread.so +module libstdc++.so +module libsupc++.so +module libuc_c.so diff -r aa2eb23bd36d -r dc521e9dbd13 libfsserver/include/fsserver/notification.h --- a/libfsserver/include/fsserver/notification.h Fri Oct 01 01:16:14 2021 +0200 +++ b/libfsserver/include/fsserver/notification.h Sat Oct 02 23:57:02 2021 +0200 @@ -79,6 +79,8 @@ virtual void notify(unsigned int endpoint, notify_flags_t flags); + virtual void notify_all(notify_flags_t flags); + virtual void notify_others(unsigned int endpoint, notify_flags_t flags); virtual unsigned int subscribe(l4_cap_idx_t notifier, notify_flags_t flags); diff -r aa2eb23bd36d -r dc521e9dbd13 libfsserver/include/fsserver/opener_resource.h --- a/libfsserver/include/fsserver/opener_resource.h Fri Oct 01 01:16:14 2021 +0200 +++ b/libfsserver/include/fsserver/opener_resource.h Sat Oct 02 23:57:02 2021 +0200 @@ -52,6 +52,10 @@ offset_t *size, l4_cap_idx_t *cap, object_flags_t *object_flags); + /* Notification methods. */ + + virtual long notify_parent(const char *path); + public: explicit OpenerResource(FileObjectRegistry *registry); diff -r aa2eb23bd36d -r dc521e9dbd13 libfsserver/lib/files/opener_resource.cc --- a/libfsserver/lib/files/opener_resource.cc Fri Oct 01 01:16:14 2021 +0200 +++ b/libfsserver/lib/files/opener_resource.cc Sat Oct 02 23:57:02 2021 +0200 @@ -19,6 +19,8 @@ * Boston, MA 02110-1301, USA */ +#include + #include "opener_server.h" #include "opener_resource.h" #include "resource_server.h" @@ -46,6 +48,51 @@ +/* Obtain any active parent directory for a path, notifying its subscribers of + the file opening event. */ + +long OpenerResource::notify_parent(const char *path) +{ + char *sep = strrchr(path, (int) '/'); + DirectoryProvider *provider; + fileid_t fileid; + long err; + + /* For top-level paths, use the empty string to get the root directory. + Otherwise, obtain the parent directory path to obtain the file + identifier. */ + + if (sep == NULL) + err = get_fileid("", 0, &fileid); + else + { + char *parent = strndup(path, sep - path + 1); + + parent[sep - path] = '\0'; + err = get_fileid(parent, 0, &fileid); + free(parent); + } + + if (err) + return err; + + /* Obtain the provider of the parent directory. */ + + err = _registry->find_directory_provider(fileid, &provider); + + if (err) + return err; + + /* With any active provider, send a notification. + NOTE: This should also communicate which file was involved, probably + NOTE: using the file identifier of the opened file. */ + + provider->notify_all(NOTIFY_FILE_OPENED); + return L4_EOK; +} + + + /* Return an object for the given path and flags. */ long OpenerResource::open(const char *path, flags_t flags, offset_t *size, @@ -59,6 +106,10 @@ if (err) return err; + /* Notify listeners subscribed to the parent of the opened object. */ + + notify_parent(path); + /* Test for file and directory access. */ if (accessing_directory(path, flags, fileid)) diff -r aa2eb23bd36d -r dc521e9dbd13 libfsserver/lib/generic/notification.cc --- a/libfsserver/lib/generic/notification.cc Fri Oct 01 01:16:14 2021 +0200 +++ b/libfsserver/lib/generic/notification.cc Sat Oct 02 23:57:02 2021 +0200 @@ -159,6 +159,18 @@ ep.deferred = flags; } +/* Notify all endpoints. */ + +void NotificationSupport::notify_all(notify_flags_t flags) +{ + std::lock_guard guard(_lock); + + for (unsigned int i = 0; i < _endpoints.size(); i++) + _notify(i, flags); + + _deferred |= flags; +} + /* Notify the other endpoints. */ void NotificationSupport::notify_others(unsigned int endpoint, notify_flags_t flags) diff -r aa2eb23bd36d -r dc521e9dbd13 libsystypes/include/systypes/base.h --- a/libsystypes/include/systypes/base.h Fri Oct 01 01:16:14 2021 +0200 +++ b/libsystypes/include/systypes/base.h Sat Oct 02 23:57:02 2021 +0200 @@ -47,9 +47,10 @@ enum notify_flags { - NOTIFY_CONTENT_AVAILABLE = 1, - NOTIFY_SPACE_AVAILABLE = 2, - NOTIFY_PEER_CLOSED = 4 + NOTIFY_CONTENT_AVAILABLE = 1, /* reading files and pipes */ + NOTIFY_SPACE_AVAILABLE = 2, /* writing pipes */ + NOTIFY_PEER_CLOSED = 4, /* closing files and pipes */ + NOTIFY_FILE_OPENED = 8, /* opening files in directories */ }; /* Filesystem object properties. */ diff -r aa2eb23bd36d -r dc521e9dbd13 tests/Makefile --- a/tests/Makefile Fri Oct 01 01:16:14 2021 +0200 +++ b/tests/Makefile Sat Oct 02 23:57:02 2021 +0200 @@ -5,6 +5,7 @@ dstest_block_client dstest_block_client_simple \ dstest_ext2fs_client \ dstest_file_client \ + dstest_file_monitor \ dstest_file_readdir \ dstest_host_client \ dstest_pipe_client \ @@ -20,6 +21,8 @@ SRC_CC_dstest_file_client = dstest_file_client.cc +SRC_CC_dstest_file_monitor = dstest_file_monitor.cc + SRC_CC_dstest_file_readdir = dstest_file_readdir.cc SRC_CC_dstest_host_client = dstest_host_client.cc diff -r aa2eb23bd36d -r dc521e9dbd13 tests/dstest_file_monitor.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/dstest_file_monitor.cc Sat Oct 02 23:57:02 2021 +0200 @@ -0,0 +1,149 @@ +/* + * Test directory monitoring operations. + * + * Copyright (C) 2020, 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 +#include +#include + +#include +#include + + + +static file_t *open_object(char *filename, flags_t flags, bool have_uid, sys_uid_t uid) +{ + /* With a user, open a user-specific file opener. */ + + if (have_uid) + { + l4_cap_idx_t opener = client_open_for_user((user_t) {uid, uid, 0022}); + + if (l4_is_invalid_cap(opener)) + { + printf("Could not obtain opener for file.\n"); + return NULL; + } + + /* Invoke the open method to receive the reference. */ + + return client_open_using(filename, flags, opener); + } + else + { + return client_open(filename, flags); + } +} + + + +/* Open files in the directory given by filename. */ + +static void open_files(const char *filename, bool have_uid, sys_uid_t uid) +{ + char *buffer = (char *) calloc(strlen(filename) + 10, sizeof(char)); + + if (buffer == NULL) + { + printf("Could not allocate buffer.\n"); + return; + } + + for (int i = 0; i < 10; i++) + { + sprintf(buffer, "%s/file%02d", filename, i); + + open_object(buffer, O_CREAT | O_RDWR, have_uid, uid); + sleep(1); + } +} + +/* Monitor files in the given directory. */ + +static void monitor_files(file_t *directory) +{ + long err = client_subscribe(directory, NOTIFY_FILE_OPENED, client_notifier_task()); + + if (err) + { + printf("Could not subscribe to events on directory.\n"); + return; + } + + while (1) + { + /* Wait for notification of content. */ + + err = client_wait_file(directory, client_notifier_task()); + + if (err) + { + printf("Error waiting for notifications: %s\n", l4sys_errtostr(err)); + return; + } + + printf("Notified with conditions:%s\n", directory->notifications & NOTIFY_FILE_OPENED ? " file opened" : ""); + } +} + + + +int main(int argc, char *argv[]) +{ + if (argc < 2) + { + printf("Need a directory name and an optional user identifier (if used with a filesystem).\n"); + return 1; + } + + char *filename = argv[1]; + bool have_uid = (argc > 2) && strlen(argv[2]); + sys_uid_t uid = have_uid ? atoi(argv[2]) : 0; + + printf("Opening %s...\n", filename); + + file_t *directory = open_object(filename, O_DIRECTORY, have_uid, uid); + + if (directory == NULL) + { + printf("Could not open directory.\n"); + return 1; + } + + /* Schedule threads. */ + + std::thread *activities[2]; + + activities[0] = new std::thread(open_files, filename, have_uid, uid); + activities[1] = new std::thread(monitor_files, directory); + + for (int i = 0; i < 2; i++) + activities[i]->join(); + + return 0; +} + +// vim: tabstop=2 expandtab shiftwidth=2