summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGianluca Guida <glguida@gmail.com>2005-05-29 16:37:07 +0000
committerGianluca Guida <glguida@gmail.com>2005-05-29 16:37:07 +0000
commit60e5cc0a61638f9ffd9be22f3fbecc66ae174e03 (patch)
tree167a30eb690aa42d83610679e679564f3f66cafa
parenta3076a2b40ebe183769eb8c163f5ecda107d955f (diff)
stow major fixes
-rw-r--r--ChangeLog60
-rw-r--r--Makefile57
-rw-r--r--lib.c18
-rw-r--r--lib.h5
-rw-r--r--main.c17
-rw-r--r--netfs.c71
-rw-r--r--node.c15
-rw-r--r--options.c18
-rw-r--r--stow-mutations.h27
-rw-r--r--stow-priv.h45
-rw-r--r--stow.c249
-rw-r--r--stow.h5
-rw-r--r--ulfs.c133
-rw-r--r--ulfs.h15
-rw-r--r--update.c97
-rw-r--r--update.h28
16 files changed, 767 insertions, 93 deletions
diff --git a/ChangeLog b/ChangeLog
index 9d4271e..b3f4ca3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
diff --git a/Makefile b/Makefile
index cdf157c..b180072 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/lib.c b/lib.c
index 12370f4..2f5de70 100644
--- a/lib.c
+++ b/lib.c
@@ -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
diff --git a/lib.h b/lib.h
index 37dae3f..be9a219 100644
--- a/lib.h
+++ b/lib.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
@@ -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. */
diff --git a/main.c b/main.c
index 2b8ebd2..999ead9 100644
--- a/main.c
+++ b/main.c
@@ -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;
}
diff --git a/netfs.c b/netfs.c
index 024a097..c1057ab 100644
--- a/netfs.c
+++ b/netfs.c
@@ -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);
diff --git a/node.c b/node.c
index 6ddc94d..a3d74ea 100644
--- a/node.c
+++ b/node.c
@@ -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,
diff --git a/options.c b/options.c
index d14b3ef..2354788 100644
--- a/options.c
+++ b/options.c
@@ -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 */
diff --git a/stow.c b/stow.c
index fc30206..11c257d 100644
--- a/stow.c
+++ b/stow.c
@@ -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;
}
diff --git a/stow.h b/stow.h
index 7643f66..54ff706 100644
--- a/stow.h
+++ b/stow.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
@@ -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 */
diff --git a/ulfs.c b/ulfs.c
index bfcae1e..1dad904 100644
--- a/ulfs.c
+++ b/ulfs.c
@@ -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;
}
diff --git a/ulfs.h b/ulfs.h
index 61e5496..dbb59d3 100644
--- a/ulfs.h
+++ b/ulfs.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
@@ -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 */