1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/conf/dstest_file_monitor.cfg Sat Oct 02 23:57:02 2021 +0200
1.3 @@ -0,0 +1,40 @@
1.4 +-- vim:set ft=lua:
1.5 +
1.6 +local L4 = require("L4");
1.7 +
1.8 +local l = L4.default_loader;
1.9 +
1.10 +local blocksvr = l:new_channel();
1.11 +
1.12 +l:startv({
1.13 + caps = {
1.14 + server = blocksvr:svr(),
1.15 + },
1.16 + log = { "blocksvr", "r" },
1.17 + },
1.18 + "rom/dstest_block_server", "10");
1.19 +
1.20 +local ext2svr = l:new_channel();
1.21 +
1.22 +l:startv({
1.23 + caps = {
1.24 + blocksvr = blocksvr,
1.25 + ext2svr = ext2svr:svr(),
1.26 + },
1.27 + log = { "ext2svr", "y" },
1.28 + },
1.29 + "rom/dstest_ext2_server", "blocksvr", "rom/e2test.fs", "10", "ext2svr");
1.30 +
1.31 +-- Obtain user filesystems with umask 0022 (18).
1.32 +
1.33 +local open_for_user = 6;
1.34 +local ext2svr_paulb = L4.cast(L4.Proto.Factory, ext2svr):create(open_for_user, 1000, 1000, 18);
1.35 +
1.36 +l:startv({
1.37 + caps = {
1.38 + server = ext2svr_paulb,
1.39 + },
1.40 + log = { "client", "g" },
1.41 + },
1.42 + -- program, directory to monitor
1.43 + "rom/dstest_file_monitor", "home/paulb");
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/conf/dstest_file_monitor.list Sat Oct 02 23:57:02 2021 +0200
2.3 @@ -0,0 +1,27 @@
2.4 +entry dstest_file_monitor
2.5 +roottask moe rom/dstest_file_monitor.cfg
2.6 +module dstest_file_monitor.cfg
2.7 +module e2test.fs
2.8 +module l4re
2.9 +module ned
2.10 +module dstest_file_monitor
2.11 +module dstest_ext2_server
2.12 +module dstest_block_server
2.13 +module lib4re-c.so
2.14 +module lib4re-c-util.so
2.15 +module lib4re.so
2.16 +module lib4re-util.so
2.17 +module libc_be_l4refile.so
2.18 +module libc_be_l4re.so
2.19 +module libc_be_socket_noop.so
2.20 +module libc_support_misc.so
2.21 +module libdl.so
2.22 +module libipc.so
2.23 +module libl4sys-direct.so
2.24 +module libl4sys.so
2.25 +module libl4util.so
2.26 +module libld-l4.so
2.27 +module libpthread.so
2.28 +module libstdc++.so
2.29 +module libsupc++.so
2.30 +module libuc_c.so
3.1 --- a/libfsserver/include/fsserver/notification.h Fri Oct 01 01:16:14 2021 +0200
3.2 +++ b/libfsserver/include/fsserver/notification.h Sat Oct 02 23:57:02 2021 +0200
3.3 @@ -79,6 +79,8 @@
3.4
3.5 virtual void notify(unsigned int endpoint, notify_flags_t flags);
3.6
3.7 + virtual void notify_all(notify_flags_t flags);
3.8 +
3.9 virtual void notify_others(unsigned int endpoint, notify_flags_t flags);
3.10
3.11 virtual unsigned int subscribe(l4_cap_idx_t notifier, notify_flags_t flags);
4.1 --- a/libfsserver/include/fsserver/opener_resource.h Fri Oct 01 01:16:14 2021 +0200
4.2 +++ b/libfsserver/include/fsserver/opener_resource.h Sat Oct 02 23:57:02 2021 +0200
4.3 @@ -52,6 +52,10 @@
4.4 offset_t *size, l4_cap_idx_t *cap,
4.5 object_flags_t *object_flags);
4.6
4.7 + /* Notification methods. */
4.8 +
4.9 + virtual long notify_parent(const char *path);
4.10 +
4.11 public:
4.12 explicit OpenerResource(FileObjectRegistry *registry);
4.13
5.1 --- a/libfsserver/lib/files/opener_resource.cc Fri Oct 01 01:16:14 2021 +0200
5.2 +++ b/libfsserver/lib/files/opener_resource.cc Sat Oct 02 23:57:02 2021 +0200
5.3 @@ -19,6 +19,8 @@
5.4 * Boston, MA 02110-1301, USA
5.5 */
5.6
5.7 +#include <string.h>
5.8 +
5.9 #include "opener_server.h"
5.10 #include "opener_resource.h"
5.11 #include "resource_server.h"
5.12 @@ -46,6 +48,51 @@
5.13
5.14
5.15
5.16 +/* Obtain any active parent directory for a path, notifying its subscribers of
5.17 + the file opening event. */
5.18 +
5.19 +long OpenerResource::notify_parent(const char *path)
5.20 +{
5.21 + char *sep = strrchr(path, (int) '/');
5.22 + DirectoryProvider *provider;
5.23 + fileid_t fileid;
5.24 + long err;
5.25 +
5.26 + /* For top-level paths, use the empty string to get the root directory.
5.27 + Otherwise, obtain the parent directory path to obtain the file
5.28 + identifier. */
5.29 +
5.30 + if (sep == NULL)
5.31 + err = get_fileid("", 0, &fileid);
5.32 + else
5.33 + {
5.34 + char *parent = strndup(path, sep - path + 1);
5.35 +
5.36 + parent[sep - path] = '\0';
5.37 + err = get_fileid(parent, 0, &fileid);
5.38 + free(parent);
5.39 + }
5.40 +
5.41 + if (err)
5.42 + return err;
5.43 +
5.44 + /* Obtain the provider of the parent directory. */
5.45 +
5.46 + err = _registry->find_directory_provider(fileid, &provider);
5.47 +
5.48 + if (err)
5.49 + return err;
5.50 +
5.51 + /* With any active provider, send a notification.
5.52 + NOTE: This should also communicate which file was involved, probably
5.53 + NOTE: using the file identifier of the opened file. */
5.54 +
5.55 + provider->notify_all(NOTIFY_FILE_OPENED);
5.56 + return L4_EOK;
5.57 +}
5.58 +
5.59 +
5.60 +
5.61 /* Return an object for the given path and flags. */
5.62
5.63 long OpenerResource::open(const char *path, flags_t flags, offset_t *size,
5.64 @@ -59,6 +106,10 @@
5.65 if (err)
5.66 return err;
5.67
5.68 + /* Notify listeners subscribed to the parent of the opened object. */
5.69 +
5.70 + notify_parent(path);
5.71 +
5.72 /* Test for file and directory access. */
5.73
5.74 if (accessing_directory(path, flags, fileid))
6.1 --- a/libfsserver/lib/generic/notification.cc Fri Oct 01 01:16:14 2021 +0200
6.2 +++ b/libfsserver/lib/generic/notification.cc Sat Oct 02 23:57:02 2021 +0200
6.3 @@ -159,6 +159,18 @@
6.4 ep.deferred = flags;
6.5 }
6.6
6.7 +/* Notify all endpoints. */
6.8 +
6.9 +void NotificationSupport::notify_all(notify_flags_t flags)
6.10 +{
6.11 + std::lock_guard<std::mutex> guard(_lock);
6.12 +
6.13 + for (unsigned int i = 0; i < _endpoints.size(); i++)
6.14 + _notify(i, flags);
6.15 +
6.16 + _deferred |= flags;
6.17 +}
6.18 +
6.19 /* Notify the other endpoints. */
6.20
6.21 void NotificationSupport::notify_others(unsigned int endpoint, notify_flags_t flags)
7.1 --- a/libsystypes/include/systypes/base.h Fri Oct 01 01:16:14 2021 +0200
7.2 +++ b/libsystypes/include/systypes/base.h Sat Oct 02 23:57:02 2021 +0200
7.3 @@ -47,9 +47,10 @@
7.4
7.5 enum notify_flags
7.6 {
7.7 - NOTIFY_CONTENT_AVAILABLE = 1,
7.8 - NOTIFY_SPACE_AVAILABLE = 2,
7.9 - NOTIFY_PEER_CLOSED = 4
7.10 + NOTIFY_CONTENT_AVAILABLE = 1, /* reading files and pipes */
7.11 + NOTIFY_SPACE_AVAILABLE = 2, /* writing pipes */
7.12 + NOTIFY_PEER_CLOSED = 4, /* closing files and pipes */
7.13 + NOTIFY_FILE_OPENED = 8, /* opening files in directories */
7.14 };
7.15
7.16 /* Filesystem object properties. */
8.1 --- a/tests/Makefile Fri Oct 01 01:16:14 2021 +0200
8.2 +++ b/tests/Makefile Sat Oct 02 23:57:02 2021 +0200
8.3 @@ -5,6 +5,7 @@
8.4 dstest_block_client dstest_block_client_simple \
8.5 dstest_ext2fs_client \
8.6 dstest_file_client \
8.7 + dstest_file_monitor \
8.8 dstest_file_readdir \
8.9 dstest_host_client \
8.10 dstest_pipe_client \
8.11 @@ -20,6 +21,8 @@
8.12
8.13 SRC_CC_dstest_file_client = dstest_file_client.cc
8.14
8.15 +SRC_CC_dstest_file_monitor = dstest_file_monitor.cc
8.16 +
8.17 SRC_CC_dstest_file_readdir = dstest_file_readdir.cc
8.18
8.19 SRC_CC_dstest_host_client = dstest_host_client.cc
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
9.2 +++ b/tests/dstest_file_monitor.cc Sat Oct 02 23:57:02 2021 +0200
9.3 @@ -0,0 +1,149 @@
9.4 +/*
9.5 + * Test directory monitoring operations.
9.6 + *
9.7 + * Copyright (C) 2020, 2021 Paul Boddie <paul@boddie.org.uk>
9.8 + *
9.9 + * This program is free software; you can redistribute it and/or
9.10 + * modify it under the terms of the GNU General Public License as
9.11 + * published by the Free Software Foundation; either version 2 of
9.12 + * the License, or (at your option) any later version.
9.13 + *
9.14 + * This program is distributed in the hope that it will be useful,
9.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
9.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9.17 + * GNU General Public License for more details.
9.18 + *
9.19 + * You should have received a copy of the GNU General Public License
9.20 + * along with this program; if not, write to the Free Software
9.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
9.22 + * Boston, MA 02110-1301, USA
9.23 + */
9.24 +
9.25 +#include <l4/re/env.h>
9.26 +#include <l4/sys/err.h>
9.27 +
9.28 +#include <thread>
9.29 +
9.30 +#include <stdio.h>
9.31 +#include <string.h>
9.32 +#include <stdlib.h>
9.33 +#include <unistd.h>
9.34 +
9.35 +#include <fsclient/client.h>
9.36 +#include <systypes/fcntl.h>
9.37 +
9.38 +
9.39 +
9.40 +static file_t *open_object(char *filename, flags_t flags, bool have_uid, sys_uid_t uid)
9.41 +{
9.42 + /* With a user, open a user-specific file opener. */
9.43 +
9.44 + if (have_uid)
9.45 + {
9.46 + l4_cap_idx_t opener = client_open_for_user((user_t) {uid, uid, 0022});
9.47 +
9.48 + if (l4_is_invalid_cap(opener))
9.49 + {
9.50 + printf("Could not obtain opener for file.\n");
9.51 + return NULL;
9.52 + }
9.53 +
9.54 + /* Invoke the open method to receive the reference. */
9.55 +
9.56 + return client_open_using(filename, flags, opener);
9.57 + }
9.58 + else
9.59 + {
9.60 + return client_open(filename, flags);
9.61 + }
9.62 +}
9.63 +
9.64 +
9.65 +
9.66 +/* Open files in the directory given by filename. */
9.67 +
9.68 +static void open_files(const char *filename, bool have_uid, sys_uid_t uid)
9.69 +{
9.70 + char *buffer = (char *) calloc(strlen(filename) + 10, sizeof(char));
9.71 +
9.72 + if (buffer == NULL)
9.73 + {
9.74 + printf("Could not allocate buffer.\n");
9.75 + return;
9.76 + }
9.77 +
9.78 + for (int i = 0; i < 10; i++)
9.79 + {
9.80 + sprintf(buffer, "%s/file%02d", filename, i);
9.81 +
9.82 + open_object(buffer, O_CREAT | O_RDWR, have_uid, uid);
9.83 + sleep(1);
9.84 + }
9.85 +}
9.86 +
9.87 +/* Monitor files in the given directory. */
9.88 +
9.89 +static void monitor_files(file_t *directory)
9.90 +{
9.91 + long err = client_subscribe(directory, NOTIFY_FILE_OPENED, client_notifier_task());
9.92 +
9.93 + if (err)
9.94 + {
9.95 + printf("Could not subscribe to events on directory.\n");
9.96 + return;
9.97 + }
9.98 +
9.99 + while (1)
9.100 + {
9.101 + /* Wait for notification of content. */
9.102 +
9.103 + err = client_wait_file(directory, client_notifier_task());
9.104 +
9.105 + if (err)
9.106 + {
9.107 + printf("Error waiting for notifications: %s\n", l4sys_errtostr(err));
9.108 + return;
9.109 + }
9.110 +
9.111 + printf("Notified with conditions:%s\n", directory->notifications & NOTIFY_FILE_OPENED ? " file opened" : "");
9.112 + }
9.113 +}
9.114 +
9.115 +
9.116 +
9.117 +int main(int argc, char *argv[])
9.118 +{
9.119 + if (argc < 2)
9.120 + {
9.121 + printf("Need a directory name and an optional user identifier (if used with a filesystem).\n");
9.122 + return 1;
9.123 + }
9.124 +
9.125 + char *filename = argv[1];
9.126 + bool have_uid = (argc > 2) && strlen(argv[2]);
9.127 + sys_uid_t uid = have_uid ? atoi(argv[2]) : 0;
9.128 +
9.129 + printf("Opening %s...\n", filename);
9.130 +
9.131 + file_t *directory = open_object(filename, O_DIRECTORY, have_uid, uid);
9.132 +
9.133 + if (directory == NULL)
9.134 + {
9.135 + printf("Could not open directory.\n");
9.136 + return 1;
9.137 + }
9.138 +
9.139 + /* Schedule threads. */
9.140 +
9.141 + std::thread *activities[2];
9.142 +
9.143 + activities[0] = new std::thread(open_files, filename, have_uid, uid);
9.144 + activities[1] = new std::thread(monitor_files, directory);
9.145 +
9.146 + for (int i = 0; i < 2; i++)
9.147 + activities[i]->join();
9.148 +
9.149 + return 0;
9.150 +}
9.151 +
9.152 +// vim: tabstop=2 expandtab shiftwidth=2