diff options
author | Gianluca Guida <glguida@gmail.com> | 2005-05-29 16:37:07 +0000 |
---|---|---|
committer | Gianluca Guida <glguida@gmail.com> | 2005-05-29 16:37:07 +0000 |
commit | 60e5cc0a61638f9ffd9be22f3fbecc66ae174e03 (patch) | |
tree | 167a30eb690aa42d83610679e679564f3f66cafa | |
parent | a3076a2b40ebe183769eb8c163f5ecda107d955f (diff) |
stow major fixes
-rw-r--r-- | ChangeLog | 60 | ||||
-rw-r--r-- | Makefile | 57 | ||||
-rw-r--r-- | lib.c | 18 | ||||
-rw-r--r-- | lib.h | 5 | ||||
-rw-r--r-- | main.c | 17 | ||||
-rw-r--r-- | netfs.c | 71 | ||||
-rw-r--r-- | node.c | 15 | ||||
-rw-r--r-- | options.c | 18 | ||||
-rw-r--r-- | stow-mutations.h | 27 | ||||
-rw-r--r-- | stow-priv.h | 45 | ||||
-rw-r--r-- | stow.c | 249 | ||||
-rw-r--r-- | stow.h | 5 | ||||
-rw-r--r-- | ulfs.c | 133 | ||||
-rw-r--r-- | ulfs.h | 15 | ||||
-rw-r--r-- | update.c | 97 | ||||
-rw-r--r-- | update.h | 28 |
16 files changed, 767 insertions, 93 deletions
@@ -1,3 +1,61 @@ +2005-05-29 Gianluca Guida <glguida@gmail.com> + + * Makefile: Added support for building mig stubs for stow feature. + (OBJS): Added update.o + (unionfs): Added fs_notifyServer.o to final linking. + (unionfs.static): Likewise. + (fs_notifyServer.o): New rule. + (clean): Remove fs_notifyServer.c and fs_notify_S.h when cleaning. + + * netfs.c (OFFSET_T): New macro. + (_get_node_size): New function. + (netfs_validate_stat): Call _get_node_size for root node. + + * node.c (node_unlink_file): New variable "removed". Return ENOENT + if no files unlinked. + + * ulfs.c: Include "unionfs", fcntl.h and "lib.h". + (ulfs_install, ulfs_uninstall): Rewritten. + (ulfs_for_each_under_priv, ulfs_check): New function. + (ulfs_register): Check that argument is a directory. + * ulfs.h: Removed field "prevp" from struct ulfs. + (ulfs_check): New declaration. + (ulfs_iterate, ulfs_iterate_unlocked): Don't use ulfs_chain_end. + * lib.c (check_dir): New function. + * lib.h: Added declaration of check_dir. + + * stow.c: Include "update.h", cthreads.h, hurd/port.h, + "stow-priv.h" and "ncache.h". + (stow_privdata) Added "lock" to struct. Removed "remove" to + struct. + (_stow_registermatchingdirs): Removed call to + debug_msg_send. Removed call to ulfs_unregister when + privdata->remove is set. Return error on ulfs_register failure + instead of exiting the program. + (_stow_scanstowentry): Removed call to ulfs_unregister when + privdata->remove is set. Lock privdata->lock and unlock at end. + (stow_port_bucket, stow_port_class): New variables. + (_stow_notify_init, begin_using_notify_ports) + (end_using_notify_ports, stow_S_file_changed, stow_S_dir_changed) + (_stow_notify_thread, stow_init): New functions. + (stow_diradd): Allocate "mypriv" instead of using stack. Call + _stow_notify_init. + * stow.h: Include "pattern.h". Declare + stow_init. + + * stow-priv.h: New file. + * stow-mutations.h: Likewise. + * update.c: Likewise. + * update.h: Likewise. + + * options.c: Include "update.h". + (argp_parse_common_options): Check stow_diradd return. Call + root_update_schedule instead of node_init_root and ncache_reset + when parsing_startup_options_finished is set. + + * main.c: Include "stow.h". Include "update.h". + (main): Call stow_init. Call root_update_init. + 2005-05-25 Gianluca Guida <glguida@gmail.com> * CAVEAT: New file. @@ -94,6 +152,6 @@ * node.c (node_create_root): call lnode_destroy, if node_create failed, not if lnode_create failed. Reported by Richard Smith. - Copyright 2002, 2003 Free Software Foundation, Inc. + Copyright 2002, 2003, 2005 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted provided the copyright notice and this notice are preserved. @@ -1,5 +1,5 @@ # Hurd unionfs -# Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. # Written by Jeroen Dekkers <jeroen@dekkers.cx>. # # This program is free software; you can redistribute it and/or modify @@ -17,22 +17,65 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. +CPP = gcc -E -x c +MIGCOM = mig -cc cat - /dev/null + CFLAGS += -Wall -g -O2 -D_FILE_OFFSET_BITS=64 -std=gnu99 \ -DDEBUG LDFLAGS += -lnetfs -lfshelp -liohelp -lthreads \ -lports -lihash -lshouldbeinlibc OBJS = main.o node.o lnode.o ulfs.o ncache.o netfs.o \ - lib.o options.o pattern.o stow.o + lib.o options.o pattern.o stow.o update.o + +MIGCOMSFLAGS = -prefix stow_ +fs_notify-MIGSFLAGS = -imacros ./stow-mutations.h + + +# How to build RPC stubs + +# We always need this setting, because libc does not include the bogus names. +MIGCOMFLAGS := -subrprefix __ + +# User settable variables: +# mig-sheader-prefix prepend to foo_S.h for name of foo.defs stub header +# MIGSFLAGS flags to CPP when building server stubs and headers +# foo-MIGSFLAGS same, but only for interface `foo' +# MIGCOMSFLAGS flags to MiG when building server stubs and headers +# foo-MIGCOMSFLAGS same, but only for interface `foo' +# MIGUFLAGS flags to CPP when building user stubs and headers +# foo-MIGUFLAGS same, but only for interface `foo' +# MIGCOMUFLAGS flags to MiG when building user stubs and headers +# foo-MIGCOMUFLAGS same, but only for interface `foo' +# CPPFLAGS flags to CPP + +# Implicit rules for building server and user stubs from mig .defs files. + +# These chained rules could be (and used to be) single rules using pipes. +# But it's convenient to be able to explicitly make the intermediate +# files when you want to deal with a problem in the MiG stub generator. +$(mig-sheader-prefix)%_S.h %Server.c: %.sdefsi + $(MIGCOM) $(MIGCOMFLAGS) $(MIGCOMSFLAGS) $($*-MIGCOMSFLAGS) \ + -sheader $(mig-sheader-prefix)$*_S.h -server $*Server.c \ + -user /dev/null -header /dev/null < $< + +%.sdefsi: %.defs + $(CPP) $(CPPFLAGS) $(MIGSFLAGS) $($*-MIGSFLAGS) -DSERVERPREFIX=S_ $< -o $@ + +vpath %.defs $(prefix)/include/hurd + + all: unionfs -unionfs: $(OBJS) - $(CC) -o $@ $(OBJS) $(LDFLAGS) +unionfs: $(OBJS) fs_notifyServer.o + $(CC) -o $@ $(OBJS) fs_notifyServer.o $(LDFLAGS) + +unionfs.static: $(OBJS) fs_notifyServer.o + $(CC) -static -o $@ $(OBJS) fs_notifyServer.o $(LDFLAGS) -unionfs.static: $(OBJS) - $(CC) -static -o $@ $(OBJS) $(LDFLAGS) +fs_notifyServer.o: fs_notifyServer.c .PHONY: clean clean: - rm -rf *.o unionfs + rm -rf *.o fs_notifyServer.c fs_notify_S.h unionfs @@ -1,5 +1,5 @@ /* Hurd unionfs - Copyright (C) 2001, 2002 Free Software Foundation, Inc. + Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc. Written by Moritz Schulte <moritz@duesseldorf.ccc.de>. This program is free software; you can redistribute it and/or @@ -32,6 +32,22 @@ messages. */ struct mutex debug_msg_lock = MUTEX_INITIALIZER; +/* Returns no error if PATH points to a directory. */ +error_t check_dir (char *path) +{ + struct stat filestat; + error_t err = 0; + + err = stat (path, &filestat); + if (err) + return err; + + if (!S_ISDIR (filestat.st_mode)) + return ENOTDIR; + + return 0; +} + /* Fetch directory entries for DIR; store the raw data as returned by the dir_readdir RPC in *DIRENT_DATA, the size of *DIRENT_DATA in *DIRENT_DATA_SIZE and a list of pointers to the dirent structures @@ -1,5 +1,5 @@ /* Hurd unionfs - Copyright (C) 2001, 2002 Free Software Foundation, Inc. + Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc. Written by Moritz Schulte <moritz@duesseldorf.ccc.de>. This program is free software; you can redistribute it and/or @@ -62,6 +62,9 @@ error_t for_each_subdir_priv (char *, error_t (*) (char *, char *, void *), error_t file_lookup (file_t dir, char *name, int flags0, int flags1, int mode, file_t *port, struct stat *stat); +/* Returns no error if directory. */ +error_t check_dir (char *path); + extern struct mutex debug_msg_lock; /* Support for debugging messages. */ @@ -1,5 +1,5 @@ /* Hurd unionfs - Copyright (C) 2001, 2002 Free Software Foundation, Inc. + Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc. Written by Moritz Schulte <moritz@duesseldorf.ccc.de>. This program is free software; you can redistribute it and/or @@ -28,13 +28,14 @@ #include <unistd.h> #include "version.h" - #include "unionfs.h" #include "ncache.h" #include "ulfs.h" #include "lnode.h" #include "node.h" #include "options.h" +#include "stow.h" +#include "update.h" char *netfs_server_name = "unionfs"; char *netfs_server_version = HURD_VERSION; @@ -67,6 +68,12 @@ main (int argc, char **argv) mach_port_t bootstrap_port; error_t err = 0; + root_update_init (); + + err = stow_init(); + if (err) + error (EXIT_FAILURE, err, "failed to initialize stow support"); + /* Argument parsing. */ argp_parse (&argp_startup, argc, argv, ARGP_IN_ORDER, 0, 0); @@ -104,15 +111,15 @@ main (int argc, char **argv) netfs_root_node->nn_stat.st_mode = S_IFDIR | (underlying_node_stat.st_mode & ~S_IFMT & ~S_ITRANS); netfs_root_node->nn_translated = netfs_root_node->nn_stat.st_mode; - + /* If the underlying node isn't a directory, enhance the stat information. */ if (! S_ISDIR (underlying_node_stat.st_mode)) { if (underlying_node_stat.st_mode & S_IRUSR) - netfs_root_node->nn_stat.st_mode |= S_IXUSR; + netfs_root_node->nn_stat.st_mode |= S_IRUSR; if (underlying_node_stat.st_mode & S_IRGRP) - netfs_root_node->nn_stat.st_mode |= S_IXGRP; + netfs_root_node->nn_stat.st_mode |= S_IRGRP; if (underlying_node_stat.st_mode & S_IROTH) netfs_root_node->nn_stat.st_mode |= S_IXOTH; } @@ -64,9 +64,66 @@ netfs_append_args (char **argz, size_t *argz_len) OPT_LONG (OPT_LONG_UNDERLYING)); } } + return err; } +#ifndef __USE_FILE_OFFSET64 +#define OFFSET_T __off_t /* Size in bytes. */ +#else +#define OFFSET_T __off64_t /* Size in bytes. */ +#endif + +static error_t +_get_node_size (struct node *dir, OFFSET_T *off) +{ + size_t size = 0; + error_t err; + int count = 0; + node_dirent_t *dirent_start, *dirent_current; + node_dirent_t *dirent_list = NULL; + int first_entry = 2; + + int bump_size (const char *name) + { + size_t new_size = size + DIRENT_LEN (strlen (name)); + + size = new_size; + count ++; + return 1; + } + + err = node_entries_get (dir, &dirent_list); + if (err) + return err; + + for (dirent_start = dirent_list, count = 2; + dirent_start && first_entry > count; + dirent_start = dirent_start->next, count++); + + count = 0; + + /* Make space for the `.' and `..' entries. */ + if (first_entry == 0) + bump_size ("."); + if (first_entry <= 1) + bump_size (".."); + + /* See how much space we need for the result. */ + for (dirent_current = dirent_start; + dirent_current; + dirent_current = dirent_current->next) + if (! bump_size (dirent_current->dirent->d_name)) + break; + + free (dirent_list); + + *off = size; + + return 0; +} + + /* Make sure that NP->nn_stat is filled with current information. CRED identifies the user responsible for the operation. */ error_t @@ -94,6 +151,11 @@ netfs_validate_stat (struct node *np, struct iouser *cred) err = ENOENT; /* FIXME? */ } } + else + { + _get_node_size (np, &np->nn_stat.st_size); + } + return err; } @@ -242,13 +304,13 @@ netfs_attempt_unlink (struct iouser *user, struct node *dir, err = node_lookup_file (dir, name, 0, &p, &statbuf); if (err) - return err; + return err; port_dealloc (p); err = fshelp_checkdirmod (&dir->nn_stat, &statbuf, user); if (err) - return err; + return err; err = node_unlink_file (dir, name); @@ -310,6 +372,7 @@ netfs_attempt_mkdir (struct iouser *user, struct node *dir, port_dealloc (p); exit: + return err; } @@ -327,13 +390,13 @@ netfs_attempt_rmdir (struct iouser *user, err = node_lookup_file (dir, name, 0, &p, &statbuf); if (err) - return err; + return err; port_dealloc (p); err = fshelp_checkdirmod (&dir->nn_stat, &statbuf, user); if (err) - return err; + return err; err = node_dir_remove (dir, name); @@ -230,6 +230,7 @@ error_t node_unlink_file (node_t *dir, char *name) { error_t err = 0; + int removed = 0; /* Using reverse iteration still have issues. Infact, we could be deleting a file in some underlying filesystem, and keeping those @@ -245,8 +246,17 @@ node_unlink_file (node_t *dir, char *name) err = dir_unlink (node_ulfs->port, name); if ((err) && (err != ENOENT)) break; + + if (!err) + removed++; + + /* Ignore ENOENT. */ + err = 0; } + if (!removed) + err = ENOENT; + return err; } @@ -482,6 +492,7 @@ node_create_root (node_t **root_node) /* Initialize the ports to the underlying filesystems for the root node. */ + error_t node_init_root (node_t *node) { @@ -490,7 +501,7 @@ node_init_root (node_t *node) int i = 0; mutex_lock (&ulfs_lock); - + err = node_ulfs_init (node); if (err) { @@ -506,7 +517,7 @@ node_init_root (node_t *node) err = ulfs_get_num (i, &ulfs); if (err) - break; + break; if (ulfs->path) node_ulfs->port = file_name_lookup (ulfs->path, @@ -1,5 +1,5 @@ /* Hurd unionfs - Copyright (C) 2001, 2002 Free Software Foundation, Inc. + Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc. Written by Moritz Schulte <moritz@duesseldorf.ccc.de>. This program is free software; you can redistribute it and/or @@ -32,6 +32,7 @@ #include "version.h" #include "pattern.h" #include "stow.h" +#include "update.h" /* This variable is set to a non-zero value after parsing of the startup options. Whenever the argument parser is later called to @@ -103,8 +104,9 @@ argp_parse_common_options (int key, char *arg, struct argp_state *state) break; case OPT_STOW: /* --stow */ - stow_diradd (arg, ulfs_flags, &ulfs_patternlist, ulfs_remove); - + err = stow_diradd (arg, ulfs_flags, &ulfs_patternlist, ulfs_remove); + if (err) + error (EXIT_FAILURE, err, "stow_diradd"); ulfs_modified = 1; ulfs_flags = ulfs_remove = 0; ulfs_match = 0; @@ -134,12 +136,14 @@ argp_parse_common_options (int key, char *arg, struct argp_state *state) ulfs_flags = ulfs_remove = 0; if (ulfs_modified && parsing_startup_options_finished) { - err = node_init_root (netfs_root_node); - if (err) - error (EXIT_FAILURE, err, "failed to initialize root node"); + root_update_schedule (); + } + else + { + ncache_reset (); } - ncache_reset (); ulfs_modified = 0; + if (! parsing_startup_options_finished) parsing_startup_options_finished = 1; break; diff --git a/stow-mutations.h b/stow-mutations.h new file mode 100644 index 0000000..d36280d --- /dev/null +++ b/stow-mutations.h @@ -0,0 +1,27 @@ +/* stow-mutations.h - MIG mutations unionfs. + Copyright (C) 2005 Free Software Foundation, Inc. + Written by Gianluca Guida <glguida@gmail.com>. + + This file is part of the GNU Hurd. + + The GNU Hurd 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, or (at + your option) any later version. + + The GNU Hurd 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + +/* Only CPP macro definitions should go in this file. */ + +#define FS_NOTIFY_INTRAN stow_notify_t begin_using_notify_port (fs_notify_t) +#define FS_NOTIFY_DESTRUCTOR end_using_notify_port (stow_notify_t) + +#define FS_NOTIFY_IMPORTS import "stow-priv.h"; + diff --git a/stow-priv.h b/stow-priv.h new file mode 100644 index 0000000..2212ac9 --- /dev/null +++ b/stow-priv.h @@ -0,0 +1,45 @@ +/* Hurd unionfs + Copyright (C) 2005 Free Software Foundation, Inc. + Written by Gianluca Guida <glguida@gmail.com>. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. */ + +#ifndef __STOW_PRIVDATA_H__ +#define __STOW_PRIVDATA_H__ + +#include <hurd/ports.h> + +struct stow_notify +{ + struct port_info pi; + + char *dir_name; + struct stow_privdata *priv; +}; +typedef struct stow_notify *stow_notify_t; + + +/* Called by MiG to translate ports into stow_notify_t. mutations.h + arranges for this to happen for the fs_notify interfaces. */ +stow_notify_t begin_using_notify_port (fs_notify_t port); + + +/* Called by MiG after server routines have been run; this balances + begin_using_notify_port, and is arranged for the fs_notify + interfaces by mutations.h. */ +void end_using_notify_port (stow_notify_t cred); + +#endif /* STOW_PRIVDATA_H */ @@ -1,5 +1,5 @@ /* Hurd unionfs - Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc. + Copyright (C) 2005 Free Software Foundation, Inc. Written by Gianluca Guida <glguida@gmail.com>. This program is free software; you can redistribute it and/or @@ -17,6 +17,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ + /* Stow mode for unionfs. */ #define _GNU_SOURCE @@ -27,12 +28,13 @@ #include "ulfs.h" #include "lib.h" #include "pattern.h" +#include "update.h" struct stow_privdata { struct patternlist *patternlist; int flags; - int remove; + struct mutex lock; }; static error_t @@ -44,32 +46,18 @@ _stow_registermatchingdirs (char *arg, char *dirpath, void *priv) struct stow_privdata *privdata = (struct stow_privdata *) priv ; err = patternlist_match (privdata->patternlist, arg); - if (err) return err; filepath = make_filepath (dirpath, arg); - debug_msg_send ("adding %s\n", filepath); - - - if (privdata->remove) - { - err = ulfs_unregister (filepath); - if (err == ENOENT) - /* It is not a fatal error, when the user tries to remove - a filesystem, which is not used by unionfs. */ - err = 0; - } - else - err = ulfs_register (filepath, privdata->flags); + err = ulfs_register (filepath, privdata->flags); if (err) - error (EXIT_FAILURE, err, "ulfs_register"); + return err; free (filepath); - + return 0; - } static error_t @@ -88,48 +76,193 @@ _stow_scanstowentry (char *arg, char *dirpath, void *priv) free (tmp); } + mutex_lock (&privdata->lock); + if (patternlist_isempty (privdata->patternlist)) { - if (privdata->remove) + + err = ulfs_register (filepath, privdata->flags); + if (err) { - err = ulfs_unregister (filepath); - if (err == ENOENT) - /* It is not a fatal error, when the user tries to remove - a filesystem, which is not used by unionfs. */ - err = 0; + mutex_unlock (&privdata->lock); + return err; } - else - err = ulfs_register (filepath, privdata->flags); - if (err) - error (EXIT_FAILURE, err, "ulfs_register"); + } else { err = for_each_subdir_priv (filepath, _stow_registermatchingdirs, priv); + if (err) + { + mutex_unlock (&privdata->lock); + free (filepath); + return err; + } } free (filepath); - + mutex_unlock (&privdata->lock); return err; } + +/* Implement server for fs_notify. */ + +#include <cthreads.h> +#include <hurd/port.h> + +#include "stow-priv.h" +#include "ncache.h" + +struct port_bucket *stow_port_bucket; +struct port_class *stow_port_class; + +static error_t +_stow_notify_init(char *dir_name, void *priv) +{ + error_t err; + file_t dir_port; + mach_port_t notify_port; + stow_notify_t stow_notify_port; + + err = ports_create_port (stow_port_class, stow_port_bucket, + sizeof (*stow_notify_port), + &stow_notify_port); + if (err) + return err; + + stow_notify_port->dir_name = dir_name; + stow_notify_port->priv = priv; + + dir_port = file_name_lookup (dir_name, 0, 0); + if (!port_valid (dir_port)) + { + return ENOENT; /* ? */ + } + + notify_port = ports_get_right (stow_notify_port); + + if (!port_valid (notify_port)) + { + port_dealloc (dir_port); + return EACCES; /* ? */ + } + + err = dir_notice_changes (dir_port, notify_port, + MACH_MSG_TYPE_MAKE_SEND); + if (err) + { + port_dealloc (dir_port); + port_dealloc (notify_port); + return err; + } + + return err; +} + +/* Called by MiG to translate ports into stow_notify_t. mutations.h + arranges for this to happen for the fs_notify interfaces. */ +stow_notify_t +begin_using_notify_port (fs_notify_t port) +{ + return ports_lookup_port (stow_port_bucket, port, stow_port_class); +} + +/* Called by MiG after server routines have been run; this balances + begin_using_notify_port, and is arranged for the fs_notify + interfaces by mutations.h. */ +void +end_using_notify_port (stow_notify_t cred) +{ + if (cred) + ports_port_deref (cred); +} + +/* We don't ask for file_changes, but this function has to be defined . */ +kern_return_t +stow_S_file_changed (stow_notify_t notify, natural_t tickno, + file_changed_type_t change, loff_t start, + loff_t end) +{ + return EOPNOTSUPP; +} + +/* Called when we receive a dir_changed message. */ +kern_return_t +stow_S_dir_changed (stow_notify_t notify, natural_t tickno, + dir_changed_type_t change, string_t name) +{ + error_t err; + + if (!notify || !notify->dir_name || !notify->priv) + return EOPNOTSUPP; + + switch (change) + { + case DIR_CHANGED_NULL: + break; + case DIR_CHANGED_NEW: + root_update_disable (); + + err = _stow_scanstowentry (name, notify->dir_name, notify->priv); + if (err) + debug_msg_send ("scanstowentry: %s\n", strerror (err)); + + root_update_schedule (); + root_update_enable (); + break; + + case DIR_CHANGED_UNLINK: + root_update_schedule (); + break; + + default: + debug_msg_send ("unsupported dir change notify"); + return EINVAL; + } + + return 0; +} + +/* This is the server thread waiting for dir_changed messages. */ +static void +_stow_notify_thread() +{ + int stow_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp) + { + int stow_fs_notify_server (mach_msg_header_t *inp, + mach_msg_header_t *outp); + + return (stow_fs_notify_server (inp, outp)); + } + + do + { + ports_manage_port_operations_multithread (stow_port_bucket, + stow_demuxer, + 1000 * 60 * 2, + 1000 * 60 * 10, + 0); + } + while (1); +} + + + +/* Interface to unionfs. */ + error_t -stow_diradd (char *dir, int flags, struct patternlist *patternlist, int remove) +stow_diradd (char *dir, int flags, struct patternlist *patternlist) { error_t err; - struct stow_privdata mypriv = - { - .patternlist = patternlist, - .flags = flags, - .remove = remove - }; + struct stow_privdata *mypriv; int dir_len; dir_len = strlen(dir); if (dir_len == 0) { - error (EXIT_FAILURE, ARGP_ERR_UNKNOWN, "stow_diradd"); + return EOPNOTSUPP; } if (dir[dir_len - 1 ] != '/') @@ -139,7 +272,7 @@ stow_diradd (char *dir, int flags, struct patternlist *patternlist, int remove) tmp = (char *) malloc (dir_len + 1); if (tmp == NULL) - error (EXIT_FAILURE, ENOMEM, "stow_diradd"); + return ENOMEM; strncpy (tmp, dir, dir_len); @@ -148,8 +281,44 @@ stow_diradd (char *dir, int flags, struct patternlist *patternlist, int remove) dir = tmp; } - err = for_each_subdir_priv (dir, _stow_scanstowentry, (void *)&mypriv); + mypriv = malloc (sizeof (struct stow_privdata)); + if (!mypriv) + { + free (dir); + return ENOMEM; + } + + mypriv->patternlist = patternlist; + mypriv->flags = flags; + mutex_init (&mypriv->lock); + + err = for_each_subdir_priv (dir, _stow_scanstowentry, (void *)mypriv); + if (err) + { + /* FIXME: rescan and delete previous inserted things. */ + return err; + } + + err = _stow_notify_init (dir, mypriv); + assert (!err); return err; +} +error_t +stow_init (void) +{ + error_t err = 0; + + stow_port_bucket = ports_create_bucket (); + if (!stow_port_bucket) + return errno; + + stow_port_class = ports_create_class (NULL, NULL); + if (!stow_port_class) + return errno; + + cthread_detach (cthread_fork ( (cthread_fn_t)_stow_notify_thread, 0)); + + return err; } @@ -1,5 +1,5 @@ /* Hurd unionfs - Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc. + Copyright (C) 2005 Free Software Foundation, Inc. Written by Gianluca Guida <glguida@gmail.com>. This program is free software; you can redistribute it and/or @@ -22,6 +22,9 @@ #ifndef _STOW_H #define _STOW_H +#include "pattern.h" + +error_t stow_init (void); error_t stow_diradd (char *, int, struct patternlist *, int); #endif /* _STOW_H */ @@ -1,5 +1,5 @@ /* Hurd unionfs - Copyright (C) 2001, 2002 Free Software Foundation, Inc. + Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc. Written by Moritz Schulte <moritz@duesseldorf.ccc.de>. This program is free software; you can redistribute it and/or @@ -26,6 +26,10 @@ #include <error.h> #include <string.h> +#include "unionfs.h" +#include <fcntl.h> + +#include "lib.h" #include "ulfs.h" /* The start of the ulfs chain. */ @@ -65,7 +69,6 @@ ulfs_create (char *path, ulfs_t **ulfs) ulfs_new->flags = 0; ulfs_new->next = NULL; ulfs_new->prev = NULL; - ulfs_new->prevp = NULL; *ulfs = ulfs_new; } } @@ -86,14 +89,9 @@ ulfs_install (ulfs_t *ulfs) { ulfs->next = ulfs_chain_start; ulfs->prev = NULL; - ulfs->prevp = &ulfs_chain_start; - if (ulfs_chain_start) - { - ulfs_chain_start->prev = ulfs; - ulfs_chain_start->prevp = &ulfs->next; - } - else - ulfs_chain_end = ulfs; + + if (ulfs->next) + ulfs->next->prev = ulfs; ulfs_chain_start = ulfs; } @@ -102,14 +100,14 @@ ulfs_install (ulfs_t *ulfs) void ulfs_uninstall (ulfs_t *ulfs) { - *ulfs->prevp = ulfs->next; + if (ulfs == ulfs_chain_start) + ulfs_chain_start = ulfs->next; + if (ulfs->next) - { - ulfs->next->prev = ulfs->prev; - ulfs->next->prevp = &ulfs->next; - } - else - ulfs_chain_end = ulfs->prev; + ulfs->next->prev = ulfs->prev; + + if (ulfs->prev) + ulfs->prev->next = ulfs->next; } /* Get an ulfs element by it's index. */ @@ -128,6 +126,7 @@ ulfs_get_num (int num, ulfs_t **ulfs) err = 0; *ulfs = u; } + return err; } @@ -150,13 +149,49 @@ ulfs_get_path (char *path, ulfs_t **ulfs) return err; } +error_t +ulfs_for_each_under_priv (char *path_under, + error_t (*func) (char *, char *, void *), + void *priv) +{ + error_t err = 0; + ulfs_t *u; + size_t length; + + length = strlen (path_under); + + for (u = ulfs_chain_start; u; u = u->next) + { + if (!u->path) + continue; + + if (memcmp (u->path, path_under, length)) + continue; + + /* This ulfs is under path_under. */ + func ((char *)(u->path + length), path_under, priv); + } + + return err; +} + /* Register a new underlying filesystem. */ error_t ulfs_register (char *path, int flags) { ulfs_t *ulfs; error_t err; - + + if (path) + { + err = check_dir (path); + if (err) + { + fprintf(stderr, "%s is not a directory\n", path); + return err; + } + } + mutex_lock (&ulfs_lock); err = ulfs_create (path, &ulfs); if (! err) @@ -169,6 +204,67 @@ ulfs_register (char *path, int flags) return err; } +/* Check for deleted ulfs entries. */ +/* FIXME: Ugly as hell. Rewrite the whole ulfs.c */ +void +ulfs_check () +{ + ulfs_t *u; + file_t p; + + struct ulfs_destroy + { + ulfs_t *ulfs; + + struct ulfs_destroy *next; + } *ulfs_destroy_q = NULL; + + mutex_lock (&ulfs_lock); + + u = ulfs_chain_start; + while (u) + { + + if (u->path) + p = file_name_lookup (u->path, O_READ | O_DIRECTORY, 0); + else + p = underlying_node; + + if (! port_valid (p)) + { + struct ulfs_destroy *ptr; + + /* Add to destroy list. */ + ptr = malloc (sizeof (struct ulfs_destroy)); + assert (ptr); + + ptr->ulfs = u; + + ptr->next = ulfs_destroy_q; + ulfs_destroy_q = ptr; + } + + u = u->next; + } + + while (ulfs_destroy_q) + { + struct ulfs_destroy *ptr; + + ptr = ulfs_destroy_q; + ulfs_destroy_q = ptr->next; + + ulfs_uninstall (ptr->ulfs); + ulfs_destroy (ptr->ulfs); + ulfs_num--; + + free (ptr); + } + + mutex_unlock (&ulfs_lock); + +} + /* Unregister an underlying filesystem. */ error_t ulfs_unregister (char *path) @@ -185,5 +281,6 @@ ulfs_unregister (char *path) ulfs_num--; } mutex_unlock (&ulfs_lock); + return err; } @@ -1,5 +1,5 @@ /* Hurd unionfs - Copyright (C) 2001, 2002 Free Software Foundation, Inc. + Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc. Written by Moritz Schulte <moritz@duesseldorf.ccc.de>. This program is free software; you can redistribute it and/or @@ -27,7 +27,7 @@ typedef struct ulfs { char *path; int flags; - struct ulfs *next, *prev, **prevp; + struct ulfs *next, *prev; } ulfs_t; /* Flags. */ @@ -60,15 +60,18 @@ error_t ulfs_get_num (int num, ulfs_t **ulfs); /* Get an ulfs element by the associated path. */ error_t ulfs_get_path (char *path, ulfs_t **ulfs); +/* Removes invalid ulfs entries. */ +void ulfs_check (void); + #define ulfs_iterate \ for (ulfs_t *ulfs = (mutex_lock (&ulfs_lock), \ - ulfs_chain_end); \ + ulfs_chain_start); \ ulfs || (mutex_unlock (&ulfs_lock), 0); \ - ulfs = ulfs->prev) + ulfs = ulfs->next) #define ulfs_iterate_unlocked \ - for (ulfs_t *ulfs = ulfs_chain_end; \ + for (ulfs_t *ulfs = ulfs_chain_start; \ ulfs; \ - ulfs = ulfs->prev) + ulfs = ulfs->next) #endif diff --git a/update.c b/update.c new file mode 100644 index 0000000..8ec6688 --- /dev/null +++ b/update.c @@ -0,0 +1,97 @@ +/* Hurd unionfs + Copyright (C) 2005 Free Software Foundation, Inc. + Written by Gianluca Guida <glguida@gmail.com>. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. */ + +/* Update thread: A clean way to solve locking issues of + root node update. */ + +#define _GNU_SOURCE + +#include <errno.h> +#include <string.h> +#include <cthreads.h> +#include <rwlock.h> + +#include "ncache.h" +#include "node.h" +#include "ulfs.h" + +/* Reader lock is used by threads that are going to + add/remove an ulfs; writer lock is hold by the + update thread. */ +static struct rwlock update_rwlock; +static struct condition update_wakeup; +static struct mutex update_lock; + +static void +_root_update_thread () +{ + error_t err; + + while (1) + { + if (hurd_condition_wait (&update_wakeup, &update_lock)) + mutex_unlock (&update_lock); + + rwlock_writer_lock (&update_rwlock); + + do + { + ulfs_check(); + err = node_init_root (netfs_root_node); + } + while (err == ENOENT); + + if (err) + { + fprintf (stderr, "update thread: got a %s\n", strerror (err)); + } + + ncache_reset (); + + rwlock_writer_unlock (&update_rwlock); + } +} + +void +root_update_schedule () +{ + condition_signal (&update_wakeup); +} + +void +root_update_disable () +{ + rwlock_reader_lock (&update_rwlock); +} + +void +root_update_enable () +{ + rwlock_reader_unlock (&update_rwlock); +} + +void +root_update_init() +{ + mutex_init (&update_lock); + rwlock_init (&update_rwlock); + condition_init (&update_wakeup); + + cthread_detach (cthread_fork ( (cthread_fn_t)_root_update_thread, 0)); +} diff --git a/update.h b/update.h new file mode 100644 index 0000000..6ebd6fc --- /dev/null +++ b/update.h @@ -0,0 +1,28 @@ +/* Hurd unionfs + Copyright (C) 2005 Free Software Foundation, Inc. + Written by Gianluca Guida <glguida@gmail.com>. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. */ + +#ifndef _UDPATE_H +#define _UPDATE_H + +void root_update_schedule (); +void root_update_disable (); +void root_update_enable (); +void root_update_init (); + +#endif /* UPDATE_H */ |