The below patch monitors the backing store for changes (if it's a separate file rather than the underlying node) and updates the presented directory hierarchy when a change is detected.
diff --git a/Makefile b/Makefile index d646475..747739e 100644 --- a/Makefile +++ b/Makefile @@ -3,15 +3,15 @@ CFLAGS = `pkg-config libxml-2.0 --cflags` -ggdb3 -O0 -std=c99 -D_FILE_OFFSET_BIT WARN = -Wall -Wextra -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -Wno-long-long -Winit-self -Wmissing-prototypes -Wstrict-prototypes -Wconversion -pedantic COMPILE=$(CC) $(CFLAGS) $(WARN) LDFLAGS = `pkg-config libxml-2.0 --libs` -lnetfs -liohelp -lfshelp -lports -OBJS = fs.o xmlfs.o xml.o netfs.o fsutils.o +OBJS = fs.o xmlfs.o xml.o netfs.o fsutils.o monitor.o BINARY = xmlfs all: $(OBJS) - $(CC) -o $(BINARY) $(OBJS) $(LDFLAGS) + @$(CC) -o $(BINARY) $(OBJS) $(LDFLAGS) .c.o: - $(COMPILE) -c $< + @$(COMPILE) -c $< clean: - rm -f *.o core *.obj *~ $(BINARY) + @rm -f *.o core *.obj *~ $(BINARY) fs_notify.c diff --git a/fs.c b/fs.c index d59385b..09415a5 100644 --- a/fs.c +++ b/fs.c @@ -50,7 +50,7 @@ xmlfs_create (file_t fd, struct xmlfs *thexmlfs) /* Build an XML tree from the file */ thexmlfs->doc = xmlReadFd ((int) fd, NULL, NULL, XML_PARSE_NOCDATA); - + if (thexmlfs->doc == NULL) error (-1, 0, "E: (%s, %d): couldn't parse", __FILE__, __LINE__); diff --git a/monitor.c b/monitor.c new file mode 100644 index 0000000..1a441ca --- /dev/null +++ b/monitor.c @@ -0,0 +1,86 @@ +#include "monitor.h" +#include "xmlfs.h" + +#include <hurd.h> +#include <hurd/ports.h> +#include <hurd/fs.h> +#include <stdio.h> +#include <stdlib.h> +#include <cthreads.h> + +static struct port_bucket *bucket; +static struct port_class *class; + +static void (*handler) (void*); +static void *params; + +int +notice_change (mach_msg_header_t *inp, mach_msg_header_t *outp) +{ + (void) inp; + (void) outp; + + DEBUG ("Entering %s\n", __PRETTY_FUNCTION__); + + if (handler != NULL) + (*handler) (params); + + return 0; +} + +any_t +managefork (any_t param) +{ + (void) param; + + ports_manage_port_operations_one_thread (bucket, notice_change, 0); + + /* Never reached */ + return 0; +} + +/* Only works with one file for now. TODO: work with multiple files */ +error_t +set_file_monitor (file_t thefile, void (*thehandler) (void*), void *theparams) +{ + mach_port_t notify; + error_t err; + notice_t noticedata; + cthread_t noticethread; + + if (thefile == MACH_PORT_NULL) + error (1, 0, "Null file port given\n"); + + if (handler != NULL || params != NULL) + DEBUG ("NOTICE: Overwrote previous handler.\n"); + + handler = thehandler; + params = theparams; + + bucket = ports_create_bucket (); + class = ports_create_class (NULL, NULL); + + DEBUG ("Entering %s\n", __PRETTY_FUNCTION__); + + /* Try to open a port and monitor changes */ + DEBUG ("INFO: Attempting to open port\n"); + err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, ¬ify); + if (err) + return err; + + DEBUG ("INFO: Attempting to start change notifer\n"); + err = file_notice_changes (thefile, notify, MACH_MSG_TYPE_MAKE_SEND); + if (err) + return err; + + /* Add to the bucket */ + DEBUG ("INFO: Attempting to add to bucket\n"); + err = ports_import_port (class, bucket, notify, sizeof (notice_t), ¬icedata); + if (err) + return err; + + /* Monitor changes */ + noticethread = cthread_fork (&managefork, NULL); + + return 0; +} diff --git a/monitor.h b/monitor.h new file mode 100644 index 0000000..0587241 --- /dev/null +++ b/monitor.h @@ -0,0 +1,41 @@ +#ifndef __MONITOR_H__ +#define __MONITOR_H__ + +/* Use GNU extentions */ +#define _GNU_SOURCE 1 + +#include <hurd.h> +#include <hurd/ports.h> + +typedef struct +{ + struct port_info pi; + + int changes; + char filename[1024]; /* Hard filename length limit of 1024, TODO: better solution */ +} notice_t; + +/* Called when the monitored file is changed. All parameters are discarded, and the + * handler function is called with the set parameter(s). */ +int +notice_change (mach_msg_header_t *inp, mach_msg_header_t *outp); + +/* Start monitoring for file changes, this should be called by a separate thread + * as it will never return. + * Parameter is discarded. */ +any_t +managefork (any_t param); + +/* Start the monitoring. Currently only one file can be monitored.] + * + * thefile: A previously opened file_t. A filename is not passed, as this allows the monitoring + * of ports, as well as files. + * + * thehandler: A function to be called when the file changes. + * + * theparams: Parameter(s) to be passed to the handler function when called. + */ +error_t +set_file_monitor (file_t thefile, void (*thehandler) (void*), void *theparams); + +#endif diff --git a/xmlfs.c b/xmlfs.c index bd39dec..da4e5d3 100644 --- a/xmlfs.c +++ b/xmlfs.c @@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ +#include "monitor.h" #include "xmlfs.h" #include "version.h" @@ -75,13 +76,30 @@ error_t parse_opt (int key, char *arg, struct argp_state *state) return 0; } +void +rebuild_xmlfs (void* param) +{ + file_t xmlfile; + error_t err; + + (void) param; + + DEBUG ("NOTICE: Reloading XML file\n"); + + xmlfile = (file_t) open (xmlfilename, O_READ); + + err = xmlfs_create (xmlfile, xmlfs); + if (err) + error (1, err, "Cannot update filesystem"); +} + int main (int argc, char **argv) { - mach_port_t bootstrap, underlying_node; + mach_port_t bootstrap, underlying_node, xmlport; io_statbuf_t underlying_stat; - file_t xmlfile; error_t err; + file_t xmlfile; xmlfilename = NULL; debug = NULL; @@ -108,10 +126,16 @@ main (int argc, char **argv) if (!xmlfilename) /* Try to open the underlying node, which is incidently our default XML file. */ - xmlfile = (file_t) openport (underlying_node, O_READ); + { + xmlfile = (file_t) openport (underlying_node, O_READ); + xmlport = MACH_PORT_NULL; + } else - xmlfile = (file_t) open (xmlfilename, O_READ); - + { + xmlfile = (file_t) open (xmlfilename, O_READ); + xmlport = file_name_lookup (xmlfilename, 0, 0); + } + xmlfs = malloc (sizeof (struct xmlfs)); err = xmlfs_create (xmlfile, xmlfs); @@ -123,6 +147,16 @@ main (int argc, char **argv) if (err) error (1, err, "Cannot create filesystem"); + /* Monitor changes on the underlying XML file */ + DEBUG ("INFO: Starting file change monitor\n"); + + if (xmlport != MACH_PORT_NULL) + { + err = set_file_monitor (xmlport, &rebuild_xmlfs, NULL); + if (err) + error (1, err, "Cannot start file change monitor\n"); + } + DEBUG ("INFO: Entering main loop\n"); netfs_server_loop (); diff --git a/xmlfs.h b/xmlfs.h index d47613e..fa5aeb2 100644 --- a/xmlfs.h +++ b/xmlfs.h @@ -62,6 +62,9 @@ extern struct xmlfs *xmlfs; error_t xmlfs_create (file_t, struct xmlfs *); +/* Rebuild the XMLFS data structure */ +void rebuild_xmlfs (void* param); + /* Parse an option from the argv array */ error_t parse_opt (int key, char *arg, struct argp_state *state); -- Michael Walker (http://www.barrucadu.co.uk) Arch Hurd Developer; GNU Webmaster; FSF member #8385 http://www.archhurd.org http://www.gnu.org http://www.fsf.org