summaryrefslogtreecommitdiff
path: root/libtreefs
diff options
context:
space:
mode:
Diffstat (limited to 'libtreefs')
-rw-r--r--libtreefs/Makefile40
-rw-r--r--libtreefs/defhooks.c80
-rw-r--r--libtreefs/dir-hooks.c136
-rw-r--r--libtreefs/dir-lookup.c305
-rw-r--r--libtreefs/fs-mutate.h30
-rw-r--r--libtreefs/fsys-getroot.c144
-rw-r--r--libtreefs/fsys-hooks.c91
-rw-r--r--libtreefs/fsys-startup.c36
-rw-r--r--libtreefs/fsys.c127
-rw-r--r--libtreefs/hooks.c59
-rw-r--r--libtreefs/mdir.c92
-rw-r--r--libtreefs/mig-decls.h41
-rw-r--r--libtreefs/nlist.c70
-rw-r--r--libtreefs/node-hooks.c176
-rw-r--r--libtreefs/rights.c96
-rw-r--r--libtreefs/s-dir.c112
-rw-r--r--libtreefs/s-file.c233
-rw-r--r--libtreefs/s-fsys.c77
-rw-r--r--libtreefs/s-io.c284
-rw-r--r--libtreefs/trans-help.c129
-rw-r--r--libtreefs/trans-start.c65
-rw-r--r--libtreefs/treefs-hooks.h401
-rw-r--r--libtreefs/treefs-s-hooks.h231
-rw-r--r--libtreefs/treefs.h472
24 files changed, 3527 insertions, 0 deletions
diff --git a/libtreefs/Makefile b/libtreefs/Makefile
new file mode 100644
index 00000000..89d95e9b
--- /dev/null
+++ b/libtreefs/Makefile
@@ -0,0 +1,40 @@
+# Makefile for libtreefs
+#
+# Copyright (C) 1995 Free Software Foundation, Inc.
+#
+# 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+dir := libtreefs
+makemode := library
+
+libname = libtreefs
+installhdrs = treefs.h
+# RPC stubs
+S_SRCS = s-file.c s-dir.c s-io.c s-fsys.c
+OTHERSRCS = defhooks.c dir-hooks.c dir-lookup.c fsys-getroot.c fsys-hooks.c \
+ fsys-startup.c hooks.c mdir.c nlist.c node-hooks.c rights.c \
+ trans-help.c trans-start.c
+SRCS = $(OTHERSRCS) $(S_SRCS)
+LCLHDRS = treefs.h fs-mutate.h
+
+MIGSTUBS = fsServer.o ioServer.o fsysServer.o
+OBJS = $(sort $(subst .c,.o,$(SRCS)) $(MIGSTUBS)
+
+MIGSFLAGS = -imacros fs-mutate.h
+MIGCOMSFLAGS = -prefix treefs_
+notify-MIGSFLAGS = -DSEQNOS
+
+include ../Makeconf
+
diff --git a/libtreefs/defhooks.c b/libtreefs/defhooks.c
new file mode 100644
index 00000000..bed0b550
--- /dev/null
+++ b/libtreefs/defhooks.c
@@ -0,0 +1,80 @@
+/* Default functions for the hook vector
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "treefs.h"
+#include "treefs-s-hooks.h"
+
+typedef void (*vf)();
+
+static error_t unsupp () { return EOPNOTSUPP; }
+static error_t nop () { return 0; }
+static int true () { return 1; }
+
+/* Most hooks return an error_t, so the default for anything not mentioned in
+ this array is to return EOPNOTSUPP. Any hooks returning different types,
+ or with some different default behavior should be mentioned here. */
+treefs_hook_vector_init_t treefs_default_hooks =
+{
+ /* directory rpcs */
+ [TREEFS_HOOK_S_DIR_LOOKUP] = (vf)_treefs_s_dir_lookup,
+
+ [TREEFS_HOOK_S_FSYS_GETROOT] = (vf)_treefs_s_fsys_getroot,
+ [TREEFS_HOOK_S_FSYS_SYNCFS] = (vf)nop,
+
+ /* Non-rpc fsys hooks */
+ [TREEFS_HOOK_FSYS_CREATE_NODE] = (vf)_treefs_fsys_create_node,
+ [TREEFS_HOOK_FSYS_DESTROY_NODE] = (vf)_treefs_fsys_destroy_node,
+ [TREEFS_HOOK_FSYS_GET_ROOT] = (vf)_treefs_fsys_get_root,
+
+ /* Node hooks */
+ [TREEFS_HOOK_NODE_TYPE] = (vf)_treefs_node_type,
+ [TREEFS_HOOK_NODE_UNLINKED] = (vf)true,
+ [TREEFS_HOOK_NODE_MOD_LINK_COUNT] = (vf)_treefs_node_mod_link_count,
+ [TREEFS_HOOK_DIR_LOOKUP] = (vf)_treefs_dir_lookup,
+ [TREEFS_HOOK_DIR_NOENT] = (vf)_treefs_dir_noent,
+ [TREEFS_HOOK_DIR_CREATE_CHILD] = (vf)_treefs_dir_create_child,
+ [TREEFS_HOOK_DIR_LINK] = (vf)_treefs_dir_link,
+ [TREEFS_HOOK_DIR_UNLINK] = (vf)_treefs_dir_unlink,
+ [TREEFS_HOOK_NODE_OWNED] = (vf)_treefs_node_owned,
+ [TREEFS_HOOK_NODE_ACCESS] = (vf)_treefs_node_access,
+ [TREEFS_HOOK_NODE_START_TRANSLATOR] = (vf)_treefs_node_start_translator,
+ [TREEFS_HOOK_NODE_INIT] = (vf)nop,
+ [TREEFS_HOOK_DIR_INIT] = (vf)nop,
+ [TREEFS_HOOK_NODE_INIT_PEROPEN] = (vf)nop,
+ [TREEFS_HOOK_NODE_INIT_HANDLE] = (vf)nop,
+ [TREEFS_HOOK_NODE_FINALIZE] = (vf)nop,
+ [TREEFS_HOOK_NODE_FINALIZE_PEROPEN] = (vf)nop,
+ [TREEFS_HOOK_NODE_FINALIZE_HANDLE] = (vf)nop,
+
+ /* Reference counting support */
+ [TREEFS_HOOK_NODE_NEW_REFS] = (vf)nop,
+ [TREEFS_HOOK_NODE_LOST_REFS] = (vf)nop,
+ [TREEFS_HOOK_NODE_TRY_DROPPING_WEAK_REFS] = (vf)nop,
+};
+
+void _treefs_init_defhooks()
+{
+ int i;
+ for (i = 0; i < TREEFS_NUM_HOOKS; i++)
+ if (!treefs_default_hooks[i])
+ treefs_default_hooks[i] = (vf)unsupp;
+}
diff --git a/libtreefs/dir-hooks.c b/libtreefs/dir-hooks.c
new file mode 100644
index 00000000..5c54039a
--- /dev/null
+++ b/libtreefs/dir-hooks.c
@@ -0,0 +1,136 @@
+/* Default hooks for directory nodes
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <sys/fcntl.h>
+
+#include "treefs.h"
+
+/* ---------------------------------------------------------------- */
+
+/* Return in CHILD a new node with one reference, presumably a possible child
+ of DIR, with a mode MODE. All attempts to create a new node go through
+ this hook, so it may be overridden to easily control creation (e.g.,
+ replacing it with a hook that always returns EPERM). Note that this
+ routine doesn't actually enter the child into the directory, or give the
+ node a non-zero link count, that should be done by the caller. */
+error_t
+_treefs_dir_create_child (struct treefs_node *dir,
+ mode_t mode, struct treefs_auth *auth,
+ struct treefs_node **child)
+{
+ error_t err;
+
+ if (!treefs_node_isdir (dir))
+ return ENOTDIR;
+
+ err = treefs_fsys_create_node (dir->fsys, dir, mode, auth, child);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+/* ---------------------------------------------------------------- */
+
+/* Lookup NAME in DIR, returning the result in CHILD; AUTH should be used to
+ do authentication. FLAGS is the open flags; if FLAGS contains O_CREAT,
+ and NAME is not found, then an entry should be created with a mode of
+ CREATE_MODE (which includes the S_IFMT bits, e.g., S_IFREG means a normal
+ file), unless O_EXCL is also set, in which case EEXIST should be returned.
+ Possible special errors returned include: EAGAIN -- result would be the
+ parent of our filesystem root. */
+error_t
+_treefs_dir_lookup (struct treefs_node *dir, char *name,
+ struct treefs_auth *auth,
+ int flags, int create_mode,
+ struct treefs_node **child)
+{
+ error_t err;
+
+ if (strcmp (name, "..") == 0 && dir == dir->fsys->root)
+ /* Whoops, the result is above our heads. */
+ err = EAGAIN;
+ else
+ /* See if we've got an in-core entry for this file. */
+ err = treefs_mdir_get (dir, name, child);
+
+ if (err == 0 && (flags & O_EXCL))
+ return EEXIST;
+
+ if (err == ENOENT)
+ /* See if there's some other way of getting this file. */
+ err = treefs_dir_noent (dir, name, auth, flags, create_mode, child);
+
+ if (err == ENOENT && (flags & O_CREAT))
+ /* No such file, but the user wants to create it. */
+ {
+ err = treefs_dir_create_child (dir, create_mode, auth, child);
+ if (!err)
+ {
+ err = treefs_dir_link (dir, name, *child, auth);
+ if (err)
+ treefs_node_unref (*child);
+ }
+ }
+
+ return err;
+}
+
+/* ---------------------------------------------------------------- */
+
+/* Link the node CHILD into DIR as NAME, using AUTH to check authentication.
+ DIR should be locked and CHILD shouldn't be. The default hook puts it
+ into DIR's in-core directory, and uses a reference to CHILD. */
+error_t
+_treefs_dir_link (struct treefs_node *dir, char *name,
+ struct treefs_node *child, struct treefs_auth *auth)
+{
+ struct treefs_node *old_child;
+ error_t err = treefs_node_mod_link_count (child, 1);
+ if (!err)
+ {
+ err = treefs_mdir_add (dir, name, child, &old_child);
+ if (err)
+ /* back out */
+ treefs_node_mod_link_count (child, -1);
+ else if (old_child)
+ treefs_node_mod_link_count (old_child, -1);
+ }
+ return err;
+}
+
+/* Remove the entry NAME from DIR, using AUTH to check authentication. DIR
+ should be locked. The default hook removes NAME from DIR's in-core
+ directory. */
+error_t
+_treefs_dir_unlink (struct treefs_node *dir, char *name,
+ struct treefs_auth *auth)
+{
+ struct treefs_node *old_child;
+ error_t err = treefs_mdir_remove (dir, name, &old_child);
+ if (!err && old_child)
+ {
+ treefs_node_mod_link_count (old_child, -1);
+ treefs_node_unref (old_child);
+ }
+ return err;
+}
diff --git a/libtreefs/dir-lookup.c b/libtreefs/dir-lookup.c
new file mode 100644
index 00000000..51c2cbd2
--- /dev/null
+++ b/libtreefs/dir-lookup.c
@@ -0,0 +1,305 @@
+/* Default treefs_s_dir_lookup hook
+
+ Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <fcntl.h>
+#include <string.h>
+
+#include <hurd/fsys.h>
+
+#include "treefs.h"
+#include "treefs-s-hooks.h"
+
+/* Default dir_lookup hook. This code was originally copied from diskfs. */
+error_t
+_treefs_s_dir_lookup (struct treefs_handle *h,
+ char *path, int flags, mode_t mode,
+ enum retry_type *retry, char *retry_name,
+ file_t *result, mach_msg_type_name_t *result_type)
+{
+ struct treefs_node *dir;
+ struct treefs_node *node;
+ unsigned symlink_expansions = 0;
+ error_t err = 0;
+ char *path_buf = 0;
+ int path_buf_len = 0;
+ int lastcomp = 0;
+ int mustbedir = 0;
+
+ flags &= O_HURD;
+ mode &= ~S_IFMT;
+
+ /* Skip leading slashes */
+ while (path[0] == '/')
+ path++;
+
+ *result_type = MACH_MSG_TYPE_MAKE_SEND;
+ *retry = FS_RETRY_NORMAL;
+ retry_name[0] = '\0';
+
+ if (path[0] == '\0')
+ {
+ mustbedir = 1;
+
+ /* Set things up in the state expected by the code from gotit: on. */
+ dir = 0;
+ node = h->po->node;
+ mutex_lock (&node->lock);
+ treefs_node_ref (node);
+ goto gotit;
+ }
+
+ dir = h->po->node;
+ mutex_lock (&dir->lock);
+ node = 0;
+
+ treefs_node_ref (dir); /* acquire a ref for later node_release */
+
+ do
+ {
+ char *nextname;
+
+ assert (!lastcomp);
+
+ /* Find the name of the next pathname component */
+ nextname = index (path, '/');
+
+ if (nextname)
+ {
+ *nextname++ = '\0';
+ while (*nextname == '/')
+ nextname++;
+ if (*nextname == '\0')
+ {
+ /* These are the rules for filenames ending in /. */
+ nextname = 0;
+ lastcomp = 1;
+ mustbedir = 1;
+
+ }
+ else
+ lastcomp = 0;
+ }
+ else
+ lastcomp = 1;
+
+ node = 0;
+
+ /* Lookup the next pathname component. */
+ if (!lastcomp)
+ err = treefs_dir_lookup (dir, path, h->auth, 0, 0, &node);
+ else
+ /* ... and in this case, the last. Note that the S_IFREG only
+ applies in the case of O_CREAT, which is turned off for
+ directories anyway. */
+ err =
+ treefs_dir_lookup (dir, path, h->auth, flags, mode | S_IFREG, &node);
+
+ /* If we get an error we're done */
+ if (err == EAGAIN)
+ {
+ if (h->po->parent_port != MACH_PORT_NULL)
+ {
+ *retry = FS_RETRY_REAUTH;
+ *result = h->po->parent_port;
+ *result_type = MACH_MSG_TYPE_COPY_SEND;
+ if (!lastcomp)
+ strcpy (retry_name, nextname);
+ err = 0;
+ goto out;
+ }
+ else
+ /* The global filesystem root... .. == . */
+ {
+ err = 0;
+ node = dir;
+ treefs_node_ref (node);
+ }
+ }
+
+ if (err)
+ goto out;
+
+ /* If this is translated, start the translator (if necessary)
+ and return. */
+ /* The check for `node != dir' simplifies this code a great
+ deal. Such a translator should already have been started,
+ so there's no lossage in doing it this way. */
+ if ((!lastcomp || !(flags & O_NOTRANS))
+ && node != dir)
+ {
+ file_t dir_port = MACH_PORT_NULL, child_fsys;
+
+ /* Be very careful not to hold an inode lock while fetching
+ a translator lock and vice versa. */
+
+ mutex_unlock (&node->lock);
+ mutex_unlock (&dir->lock);
+
+ do
+ {
+ err =
+ treefs_node_get_active_trans (node, dir, h->po->parent_port,
+ &dir_port, &child_fsys);
+ if (err == 0 && child_fsys != MACH_PORT_NULL)
+ {
+ err =
+ fsys_getroot (child_fsys, dir_port,
+ MACH_MSG_TYPE_COPY_SEND,
+ h->auth->uids, h->auth->nuids,
+ h->auth->gids, h->auth->ngids,
+ lastcomp ? flags : 0,
+ retry, retry_name, result);
+ /* If we got MACH_SEND_INVALID_DEST or MIG_SERVER_DIED, then
+ the server is dead. Zero out the old control port and try
+ everything again. */
+ if (err == MACH_SEND_INVALID_DEST || err == EMIG_SERVER_DIED)
+ treefs_node_drop_active_trans (node, child_fsys);
+ }
+ }
+ while (err == MACH_SEND_INVALID_DEST || err == EMIG_SERVER_DIED);
+
+ if (err || child_fsys)
+ {
+ /* We're done; return to the user. If there are more
+ components after this name, be sure to append them to the
+ user's retry path. */
+ if (!err && !lastcomp)
+ {
+ strcat (retry_name, "/");
+ strcat (retry_name, nextname);
+ }
+
+ *result_type = MACH_MSG_TYPE_MOVE_SEND;
+
+ treefs_node_unref (dir);
+ treefs_node_unref (node);
+ if (dir_port)
+ mach_port_deallocate (mach_task_self (), dir_port);
+
+ return err;
+ }
+
+ /* We're here if we tried the translator check, and it
+ failed. Lock everything back, and make sure we do it
+ in the right order. */
+ if (strcmp (path, "..") != 0)
+ {
+ mutex_unlock (&node->lock);
+ mutex_lock (&dir->lock);
+ mutex_lock (&node->lock);
+ }
+ else
+ mutex_lock (&dir->lock);
+ }
+
+ if (treefs_node_type (node) == S_IFLNK
+ && !(lastcomp && (flags & (O_NOLINK|O_NOTRANS))))
+ /* Handle symlink interpretation */
+ {
+ unsigned nextname_len = nextname ? strlen (nextname) + 1 : 0;
+ /* max space we currently have for the sym link */
+ unsigned sym_len = path_buf_len - nextname_len - 1;
+
+ if (symlink_expansions++ > node->fsys->max_symlinks)
+ {
+ err = ELOOP;
+ goto out;
+ }
+
+ err = treefs_node_get_symlink (node, path_buf, &sym_len);
+ if (err == E2BIG)
+ /* Symlink contents + extra path won't fit in our buffer, so
+ reallocate it and try again. */
+ {
+ path_buf_len = sym_len + nextname_len + 1;
+ path_buf = alloca (path_buf_len);
+ err = treefs_node_get_symlink (node, path_buf, &sym_len);
+ }
+ if (err)
+ goto out;
+
+ if (nextname)
+ {
+ path_buf[sym_len] = '/';
+ bcopy (nextname, path_buf + sym_len + 1, nextname_len - 1);
+ }
+ path_buf[nextname_len + sym_len] = '\0';
+
+ if (path_buf[0] == '/')
+ {
+ /* Punt to the caller. */
+ *retry = FS_RETRY_MAGICAL;
+ *result = MACH_PORT_NULL;
+ strcpy (retry_name, path_buf);
+ goto out;
+ }
+
+ path = path_buf;
+ if (lastcomp)
+ {
+ lastcomp = 0;
+ /* Symlinks to nonexistent files aren't allowed to cause
+ creation, so clear the flag here. */
+ flags &= ~O_CREAT;
+ }
+ treefs_node_release (node);
+ node = 0;
+ }
+ else
+ {
+ /* Handle normal nodes */
+ path = nextname;
+ if (node == dir)
+ treefs_node_unref (dir);
+ else
+ treefs_node_release (dir);
+ if (!lastcomp)
+ {
+ dir = node;
+ node = 0;
+ }
+ else
+ dir = 0;
+ }
+ } while (path && *path);
+
+ gotit:
+ /* At this point, node is the node to return. */
+
+ if (mustbedir && !treefs_node_isdir (node))
+ err = ENOTDIR;
+ if (err)
+ goto out;
+
+ err = treefs_node_create_right (node, flags, h->po->parent_port, h->auth,
+ result);
+
+ out:
+ if (node)
+ {
+ if (dir == node)
+ treefs_node_unref (node);
+ else
+ treefs_node_release (node);
+ }
+ if (dir)
+ treefs_node_release (dir);
+ return err;
+}
diff --git a/libtreefs/fs-mutate.h b/libtreefs/fs-mutate.h
new file mode 100644
index 00000000..6ddec3fa
--- /dev/null
+++ b/libtreefs/fs-mutate.h
@@ -0,0 +1,30 @@
+/* Automagic type transformation for our mig interfaces
+
+ Copyright (C) 1994 Free Software Foundation
+
+ 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Only CPP macro definitions should go in this file. */
+
+#define FILE_INTRAN treefs_handle_t treefs_begin_using_handle_port (file_t)
+#define FILE_DESTRUCTOR treefs_end_using_handle_port (treefs_handle_t)
+
+#define IO_INTRAN treefs_handle_t treefs_begin_using_handle_port (io_t)
+#define IO_DESTRUCTOR treefs_end_using_handle_port (treefs_handle_t)
+
+#define FILE_IMPORTS import "mig-decls.h";
+#define IO_IMPORTS import "mig-decls.h";
+#define FSYS_IMPORTS import "mig-decls.h";
+#define IFSOCK_IMPORTS import "mig-decls.h";
diff --git a/libtreefs/fsys-getroot.c b/libtreefs/fsys-getroot.c
new file mode 100644
index 00000000..986938cf
--- /dev/null
+++ b/libtreefs/fsys-getroot.c
@@ -0,0 +1,144 @@
+/*
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <fcntl.h>
+
+#include <hurd/fsys.h>
+
+#include "treefs.h"
+
+error_t
+_treefs_s_fsys_getroot (struct treefs_fsys *fsys,
+ mach_port_t dotdot,
+ uid_t *uids, unsigned nuids,
+ uid_t *gids, unsigned ngids,
+ int flags, retry_type *retry, char *retry_name,
+ file_t *result, mach_msg_type_name_t *result_type)
+{
+ error_t err;
+ mode_t type;
+ struct treefs_node *root;
+ struct treefs_auth *auth;
+
+ flags &= O_HURD;
+
+ err = treefs_fsys_get_root (fsys, &root);
+ if (err)
+ return err;
+
+ if (!(flags & O_NOTRANS))
+ /* Try starting up any translator on the root node. */
+ {
+ fsys_t child_fsys;
+
+ do
+ {
+ err =
+ treefs_node_get_active_trans (root, 0, 0, &dotdot, &child_fsys);
+ if (err == 0 && child_fsys != MACH_PORT_NULL)
+ /* We think there's an active translator; try contacting it. */
+ {
+ err =
+ fsys_getroot (child_fsys, dotdot, MACH_MSG_TYPE_COPY_SEND,
+ uids, nuids, gids, ngids,
+ flags, retry, retry_name, result);
+ /* If we got MACH_SEND_INVALID_DEST or MIG_SERVER_DIED, then
+ the server is dead. Zero out the old control port and try
+ everything again. */
+ if (err == MACH_SEND_INVALID_DEST || err == EMIG_SERVER_DIED)
+ treefs_node_drop_active_trans (root, control_port);
+ }
+ }
+ while (err == MACH_SEND_INVALID_DEST || err == MIG_SERVER_DIED);
+
+ /* If we got a translator, or an error trying, return immediately. */
+ if (err || child_fsys)
+ {
+ if (!err && *result != MACH_PORT_NULL)
+ *result_type = MACH_MSG_TYPE_MOVE_SEND;
+ else
+ *result_type = MACH_MSG_TYPE_COPY_SEND;
+
+ if (!err)
+ mach_port_deallocate (mach_task_self (), dotdot);
+ treefs_node_unref (root);
+
+ return err;
+ }
+ }
+
+ mutex_lock (&root->lock);
+
+ type = treefs_node_type (root);
+ if (type == S_IFLNK && !(flags & (O_NOLINK | O_NOTRANS)))
+ /* Handle symlink interpretation */
+ {
+ int sym_len = 1000;
+ char path_buf[sym_len + 1], *path = path_buf;
+
+ err = treefs_node_get_symlink (root, path, &sym_len);
+ if (err == E2BIG)
+ /* Symlink contents won't fit in our buffer, so
+ reallocate it and try again. */
+ {
+ path = alloca (sym_len + 1);
+ err = treefs_node_get_symlink (node, path, &sym_len);
+ }
+
+ if (err)
+ goto out;
+
+ if (*path == '/')
+ {
+ *retry = FS_RETRY_MAGICAL;
+ *result = MACH_PORT_NULL;
+ *result_type = MACH_MSG_TYPE_COPY_SEND;
+ mach_port_deallocate (mach_task_self (), dotdot);
+ }
+ else
+ {
+ *retry = FS_RETRY_REAUTH;
+ *result = dotdot;
+ *result_type = MACH_MSG_TYPE_COPY_SEND;
+ }
+
+ strcpy (retry_name, path);
+ goto out;
+ }
+
+ err = treefs_node_create_auth (root, uids, nuids, gids, ngids, &auth);
+ if (err)
+ goto out;
+
+ *retry = FS_RETRY_NORMAL;
+ *retry_name = '\0';
+ *result_type = MACH_MSG_TYPE_MAKE_SEND;
+
+ err = treefs_node_create_right (root, dotdot, flags, auth, result);
+
+ treefs_node_auth_unref (root, auth);
+
+ out:
+ treefs_node_release (root);
+
+ return err;
+}
diff --git a/libtreefs/fsys-hooks.c b/libtreefs/fsys-hooks.c
new file mode 100644
index 00000000..cb7fcfc6
--- /dev/null
+++ b/libtreefs/fsys-hooks.c
@@ -0,0 +1,91 @@
+/* Default hooks for filesystems
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "treefs.h"
+
+/* Called to get the root node of the a filesystem, with a reference,
+ returning it in ROOT, or return an error if it can't be had. The default
+ hook just returns FSYS->root or an error if it's NULL. Note that despite
+ the similar name, this is very different from fsys_s_getroot! FSYS must
+ not be locked. */
+error_t
+_treefs_fsys_get_root (struct treefs_fsys *fsys, struct treefs_node **root)
+{
+ mutex_lock (&fsys->lock);
+ *root = fsys->root;
+ if (*root != NULL)
+ treefs_node_ref (*root);
+ mutex_unlock (&fsys->lock);
+
+ return *root ? 0 : EOPNOTSUPP;
+}
+
+/* Called on a filesystem to create a new node in that filesystem, returning
+ it in NODE. DIR, if non-NULL, is the nominal parent directory, and MODE
+ and CRED are the desired mode and user info respectively. This hook
+ should also call node_init_stat & node_init to initialize the various user
+ bits. */
+error_t
+_treefs_fsys_create_node (struct treefs_fsys *fsys,
+ struct treefs_node *dir,
+ mode_t mode, struct treefs_protid *cred,
+ struct treefs_node **node)
+{
+ error_t err = treefs_create_node (fsys, node);
+
+ if (err)
+ return err;
+
+ err = treefs_node_init_stat (*node, dir, mode, cred);
+ if (!err)
+ err = treefs_node_init (*node, dir, mode, cred);
+ if (S_ISDIR (mode))
+ {
+ treefs_dir_init (*node, dir, mode, cred);
+ treefs_mdir_init (*node, dir, mode, cred);
+ }
+ if (err)
+ {
+ /* There shouldn't be any other state to free at this point --
+ node_init_stat shouldn't do more than init the stat structure, and
+ if node_init fails, it should clean up after itself. */
+ treefs_free_node (*node);
+ return err;
+ }
+
+ return 0;
+}
+
+/* Called on a filesystem to destroy a node in that filesystem. This call
+ should *really* destroy it, i.e., it's only called once all references are
+ gone. */
+void
+_treefs_fsys_destroy_node (struct treefs_fsys *fsys, struct treefs_node *node)
+{
+ if (treefs_node_isdir (node))
+ {
+ treefs_mdir_finalize (node);
+ treefs_dir_finalize (node);
+ }
+ treefs_node_finalize (node);
+ treefs_free_node (node);
+}
diff --git a/libtreefs/fsys-startup.c b/libtreefs/fsys-startup.c
new file mode 100644
index 00000000..fcee3535
--- /dev/null
+++ b/libtreefs/fsys-startup.c
@@ -0,0 +1,36 @@
+/* fsys startup RPC
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+error_t
+treefs_S_fsys_startup (mach_port_t child_boot_port, mach_port_t control_port,
+ mach_port_t *real, mach_msg_type_name_t *real_type)
+{
+ error_t err;
+ struct port_info *child_boot =
+ ports_check_port_type (child_boot_port, PT_TRANSBOOT);
+
+ assert (child_boot); /* XXX deal with exec server boot */
+ err = fshelp_handle_fsys_startup (child_boot, control_port, real, real_type);
+ ports_done_with_port (child_boot);
+
+ return err;
+}
diff --git a/libtreefs/fsys.c b/libtreefs/fsys.c
new file mode 100644
index 00000000..459d0d3b
--- /dev/null
+++ b/libtreefs/fsys.c
@@ -0,0 +1,127 @@
+/*
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "treefs.h"
+
+/* ---------------------------------------------------------------- */
+
+/* Create a basic node, with one reference and no user-specific fields
+ initialized, and return it in NODE */
+error_t
+treefs_create_node (struct treefs_fsys *fsys, struct treefs_node **node)
+{
+ struct treefs_node *n = malloc (sizeof (struct treefs_node));
+
+ if (n == NULL)
+ return ENOMEM;
+
+ n->fsys = fsys;
+ n->refs = 1;
+ n->light_refs = 0;
+ n->hooks = fsys->hooks;
+ n->children = NULL;
+ n->u = NULL;
+ mutex_init (&n->lock);
+ fshelp_init_trans_link (&n->active_trans);
+ fshelp_lock_init (&n->lock_box);
+
+ *node = n;
+ return 0;
+}
+
+/* Immediately destroy NODE, with no user-finalization. */
+error_t
+treefs_free_node (struct treefs_node *node)
+{
+ free (node);
+}
+
+/* ---------------------------------------------------------------- */
+
+/* Returns a new filesystem in FSYS. */
+error_t
+treefs_create_fsys (struct port_bucket *port_bucket,
+ treefs_hook_vector_t hook_overrides,
+ struct treefs_fsys **fsys)
+{
+ treefs_hook_vector_t hooks = treefs_default_hooks;
+
+ if (hook_overrides)
+ {
+ hooks = treefs_hooks_clone (hooks);
+ treefs_hooks_override (hooks, hooks_overrides);
+ }
+
+ *fsys =
+ ports_allocate_port (port_bucket, sizeof (struct trivfs_control),
+ treefs_fsys_port_class);
+ if (*fsys == NULL)
+ return ENOMEM;
+
+ mutex_init (&(*fsys)->lock);
+ (*fsys)->root = NULL;
+
+ (*fsys)->underlying_port = MACH_PORT_NULL;
+ bzero (&(*fsys)->underlying_stat, sizeof (struct stat));
+
+ (*fsys)->flags = treefs_default_flags;
+ (*fsys)->max_symlinks = treefs_default_max_symlinks;
+ (*fsys)->sync_interval = treefs_default_sync_interval;
+
+ (*fsys)->fs_type = treefs_default_fsys_type;
+ (*fsys)->fs_id = getpid();
+
+ (*fsys)->hooks = hooks;
+
+ (*fsys)->port_bucket = port_bucket;
+ (*fsys)->protid_ports_class = treefs_protid_port_class;
+
+ (*fsys)->u = NULL;
+
+ return 0;
+}
+
+
+void ACKACKACK()
+{
+ /* Create a fake root node to bootstrap the filesystem. */
+ err = treefs_create_node(*fsys, &fake_root);
+ if (err)
+ goto barf;
+
+ /* Remember stat info for the node we're mounted on. */
+ bzero (&(*fsys)->underlying_stat, sizeof (struct stat));
+ file_stat (realnode, &(*fsys)->underlying_stat);
+
+ /* Note that it points to *FSYS, but *FSYS's root doesn't point to it...
+ If the user wants this to be the real root, it's his responsility to
+ initialize if further and install it. */
+ fake_root->fsys = *fsys;
+ bcopy (&(*fsys)->underlying_stat, &fake_root->stat);
+ err = treefs_fsys_init (fake_root);
+ if (err)
+ goto barf;
+
+ /* See if the silly user has in fact done so. */
+ if ((*fsys)->root != fake_root)
+ treefs_free_node (fake_root);
+}
diff --git a/libtreefs/hooks.c b/libtreefs/hooks.c
new file mode 100644
index 00000000..b8ec103f
--- /dev/null
+++ b/libtreefs/hooks.c
@@ -0,0 +1,59 @@
+/* Functions for manipulating hook vectors.
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "treefs.h"
+
+#define HV_SIZE (sizeof (void (*)()) * TREEFS_NUM_HOOKS)
+
+/* Returns a copy of the treefs hook vector HOOKS, or a zero'd vector if HOOKS
+ is NULL. If HOOKS is NULL, treefs_default_hooks is used. If a memory
+ allocation error occurs, NULL is returned. */
+treefs_hook_vector_t
+treefs_hooks_clone (treefs_hook_vector_t hooks)
+{
+ treefs_hook_vector_t clone = malloc (HV_SIZE);
+ if (clone != NULL)
+ {
+ if (hooks == NULL)
+ hooks = treefs_default_hooks;
+ bcopy (hooks, clone, HV_SIZE);
+ }
+ return clone;
+}
+
+/* Copies each non-NULL entry in OVERRIDES into HOOKS. */
+void
+treefs_hooks_override (treefs_hook_vector_t hooks,
+ treefs_hook_vector_t overrides)
+{
+ int num;
+ for (num = 0; num < TREEFS_NUM_HOOKS; num++)
+ if (overrides[num] != NULL)
+ hooks[num] = overrides[num];
+}
+
+/* Sets the hook NUM in HOOKS to HOOK. */
+void
+treefs_hooks_set (treefs_hook_vector_t hooks, unsigned num, void (*hook)())
+{
+ hooks[num] = hook;
+}
diff --git a/libtreefs/mdir.c b/libtreefs/mdir.c
new file mode 100644
index 00000000..ddc1516a
--- /dev/null
+++ b/libtreefs/mdir.c
@@ -0,0 +1,92 @@
+/* Low-level directory manipulation functions
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Low level dir management routines. If called on a non-dir, ENOTDIR is
+ returned. */
+
+/* Add CHILD to DIR as NAME, replacing any existing entry. If OLD_CHILD is
+ NULL, and NAME already exists in dir, EEXIST is returned, otherwise, any
+ previous child is replaced and returned in OLD_CHILD. DIR should be
+ locked. */
+error_t
+treefs_mdir_add (struct treefs_node *dir, char *name,
+ struct treefs_node *child, struct treefs_node **old_child)
+{
+ if (!treefs_node_isdir (dir))
+ return ENOTDIR;
+ else
+ {
+ if (dir->children == NULL)
+ {
+ dir->children = treefs_make_node_list ();
+ if (dir->children == NULL)
+ return ENOMEM;
+ }
+ return treefs_node_list_add (dir->children, name, child, old_child);
+ }
+}
+
+/* Remove any entry in DIR called NAME. If there is no such entry, ENOENT is
+ returned. If OLD_CHILD is non-NULL, any removed entry is returned in it.
+ DIR should be locked. */
+error_t
+treefs_mdir_remove (struct treefs_node *dir, char *name,
+ struct treefs_node *old_child)
+{
+ if (!treefs_node_isdir (dir))
+ return ENOTDIR;
+ else if (dir->children == NULL)
+ /* Normally this shouldn't happen. */
+ return ENOENT;
+ else
+ return treefs_node_list_remove (dir->children, name, old_child);
+}
+
+/* Returns in CHILD any entry called NAME in DIR, or NULL (and ENOENT) if
+ there isn't such. DIR should be locked. */
+error_t
+treefs_mdir_get (struct treefs_node *dir, char *name,
+ struct treefs_node **child)
+{
+ if (!treefs_node_isdir (dir))
+ return ENOTDIR;
+ else if (dir->children == NULL)
+ /* Normally this shouldn't happen. */
+ return ENOENT;
+ else
+ return treefs_node_list_get (dir->children, name, child);
+}
+
+/* Call FUN on each child of DIR; if FUN returns a non-zero value at any
+ point, stop iterating and return that value immediately. */
+error_t
+treefs_mdir_for_each (struct treefs_node *dir,
+ error_t (*fun)(char *name, struct treefs_node *child))
+{
+ if (!treefs_node_isdir (dir))
+ return ENOTDIR;
+ else if (dir->children == NULL)
+ /* Normally this shouldn't happen. */
+ return 0;
+ else
+ return treefs_node_list_for_each (dir->children, fun);
+}
diff --git a/libtreefs/mig-decls.h b/libtreefs/mig-decls.h
new file mode 100644
index 00000000..0d051e9c
--- /dev/null
+++ b/libtreefs/mig-decls.h
@@ -0,0 +1,41 @@
+/* Type decls for mig-produced server stubs
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "treefs.h"
+
+/* For mig */
+typedef struct treefs_handle *treefs_handle_t;
+
+extern inline
+treefs_handle_t treefs_begin_using_handle_port(mach_port_t port)
+{
+ return
+ (struct treefs_handle *)
+ ports_lookup_port (0, port, treefs_fsys_port_class);
+}
+
+extern inline void
+treefs_end_using_handle_port (treefs_handle_t handle)
+{
+ if (handle != NULL)
+ ports_port_deref (&handle->pi);
+}
diff --git a/libtreefs/nlist.c b/libtreefs/nlist.c
new file mode 100644
index 00000000..326bb0f8
--- /dev/null
+++ b/libtreefs/nlist.c
@@ -0,0 +1,70 @@
+/* Functions for dealing with node lists
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "treefs.h"
+
+/* ---------------------------------------------------------------- */
+struct treefs_node_list
+{
+ unsigned short num_nodes, nodes_alloced;
+
+};
+
+/* Return a new node list, or NULL if a memory allocation error occurs. */
+struct treefs_node_list *
+treefs_make_node_list ()
+{
+ struct treefs_node_list *nl = malloc (sizeof (struct treefs_node_list));
+ if (!nl)
+ return NULL;
+
+ nl->nodes_alloced = 0;
+ nl->num_nodes = 0;
+
+ return nl;
+}
+
+/* Add NODE to LIST as NAME, replacing any existing entry. If OLD_NODE is
+ NULL, and an entry NAME already exists, EEXIST is returned, otherwise, any
+ previous child is replaced and returned in OLD_NODE. */
+error_t
+treefs_node_list_add (struct treefs_node_list *list, char *name,
+ struct treefs_node *node, struct treefs_node **old_node)
+{
+
+}
+
+/* Remove any entry in LIST called NAME. If there is no such entry, ENOENT is
+ returned. If OLD_NODE is non-NULL, any removed entry is returned in it. */
+error_t
+treefs_node_list_remove (struct treefs_node_list *list, char *name,
+ struct treefs_node **old_node)
+{
+}
+
+/* Returns in NODE any entry called NAME in LIST, or NULL (and ENOENT) if
+ there isn't such. */
+error_t
+treefs_node_list_get (struct treefs_node_list *list, char *name,
+ struct treefs_node **node)
+{
+}
diff --git a/libtreefs/node-hooks.c b/libtreefs/node-hooks.c
new file mode 100644
index 00000000..faffcd6a
--- /dev/null
+++ b/libtreefs/node-hooks.c
@@ -0,0 +1,176 @@
+/* Default hooks for nodes
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "treefs.h"
+
+/* ---------------------------------------------------------------- */
+/* These default hooks depend on stat information being correct. */
+
+/* Returns the type of NODE, as an S_IFMT value (e.g., S_IFDIR). The
+ default routine just looks at NODE's stat mode. */
+int
+_treefs_node_type (struct treefs_node *node)
+{
+ return node->stat.st_mode & S_IFMT;
+}
+
+/* Return TRUE if NODE is `unlinked' -- that is, can be deleted when all
+ (in-memory) references go away. */
+int
+_treefs_node_unlinked (struct treefs_node *node)
+{
+ return node->stat.st_nlinks == 0;
+}
+
+/* Changes the link count of NODE by CHANGE; if any error is returned, the
+ operation trying to change the link count will fail, so filesystems that
+ don't support real links can restrict it to 1 or 0. This is mostly used
+ by the in-core directory code when it makes a link. The default hook uses
+ the link field of NODE's stat entry. */
+error_t
+_treefs_node_mod_link_count (struct treefs_node *node, int change)
+{
+ node->stat.st_nlinks += change;
+}
+
+
+/* ---------------------------------------------------------------- */
+/* These default hooks depend on stat information being correct. */
+
+/* Returns the user and group that a newly started translator should be
+ authenticated as. The default just returns the owner/group of NODE. */
+error_t
+_treefs_node_get_trans_auth (struct treefs_node *node, uid_t *uid, gid_t *gid)
+{
+ *uid = node->stat.st_uid;
+ *gid = node->stat.st_gid;
+ return 0;
+}
+
+/* Check to see is the user identified by AUTH is permitted to do
+ operation OP on node NP. Op is one of S_IREAD, S_IWRITE, or S_IEXEC.
+ Return 0 if the operation is permitted and EACCES if not. */
+error_t
+_treefs_node_access (struct treefs_node *node,
+ int op, struct treefs_auth *auth)
+{
+ int gotit;
+ if (diskfs_auth_has_uid (auth, 0))
+ gotit = 1;
+ else if (auth->nuids == 0 && (node->stat.st_mode & S_IUSEUNK))
+ gotit = node->stat.st_mode & (op << S_IUNKSHIFT);
+ else if (!treefs_node_owned (node, auth))
+ gotit = node->stat.st_mode & op;
+ else if (treefs_auth_in_group (auth, node->stat.st_gid))
+ gotit = node->stat.st_mode & (op >> 3);
+ else
+ gotit = node->stat.st_mode & (op >> 6);
+ return gotit ? 0 : EACCES;
+}
+
+/* Check to see if the user identified by AUTH is permitted to do owner-only
+ operations on node NP; if so, return 0; if not, return EPERM. */
+error_t
+_treefs_node_owned (struct treefs_node *node, struct treefs_auth *auth)
+{
+ /* Permitted if the user is the owner, superuser, or if the user
+ is in the group of the file and has the group ID as their user
+ ID. (This last is colloquially known as `group leader'.) */
+ if (treefs_auth_has_uid (auth, node->stat.st_uid)
+ || treefs_auth_has_uid (auth, 0)
+ || (treefs_auth_in_group (auth, node->stat.st_gid)
+ && treefs_auth_has_uid (auth, node->stat.st_gid)))
+ return 0;
+ else
+ return EPERM;
+}
+
+/* ---------------------------------------------------------------- */
+
+error_t
+_treefs_node_init_stat (struct treefs_node *node, struct treefs_node *dir,
+ mode_t mode, struct treefs_auth *auth)
+{
+ if (auth->nuids)
+ node->stat.st_uid = auth->uids[0];
+ else
+ {
+ mode &= ~S_ISUID;
+ if (dir)
+ node->stat.st_uid = dir->stat.st_uid;
+ else
+ node->stat.st_uid = -1; /* XXX */
+ }
+
+ if (dir && diskfs_ingroup (dir->stat.st_gid, auth))
+ node->stat.st_gid = dir->stat.st_gid;
+ else if (auth->ngids)
+ node->stat.st_gid = auth->gids[0];
+ else
+ {
+ mode &= ~S_ISGID;
+ if (dir)
+ node->stat.st_gid = dir->stat.st_gid;
+ else
+ node->stat.st_gid = -1; /* XXX */
+ }
+
+ node->stat.st_rdev = 0;
+ node->stat.st_nlink = 0;
+ node->stat.st_mode = mode;
+
+ node->stat.st_blocks = 0;
+ node->stat.st_size = 0;
+ node->stat.st_flags = 0;
+
+ return 0;
+}
+
+/* ---------------------------------------------------------------- */
+
+/* Called when the new peropen structure PO is made for NODE, with the
+ authorization in AUTH, opened with the flags FLAGS. If an error is
+ returned, the open will fail with that error. The default hook does
+ explicit authorization checks against AUTH using treefs_node_access, and
+ otherwise does nothing. */
+error_t
+_treefs_init_peropen (struct treefs_node *node, struct treefs_peropen *po,
+ int flags, struct treefs_auth *auth)
+{
+ error_t err;
+
+ if (flags & O_READ)
+ err = treefs_node_access (node, S_IREAD, auth);
+ if (!err && (flags & O_EXEC))
+ err = treefs_node_access (node, S_IEXEC, auth);
+ if (!err && (flags & O_WRITE))
+ {
+ if (type == S_IFDIR)
+ err = EISDIR;
+ else if (auth->po->node->fsys->readonly)
+ err = EROFS;
+ else
+ err = treefs_node_access (node, S_IWRITE, auth);
+ }
+
+ return err;
+}
diff --git a/libtreefs/rights.c b/libtreefs/rights.c
new file mode 100644
index 00000000..f803b029
--- /dev/null
+++ b/libtreefs/rights.c
@@ -0,0 +1,96 @@
+/* Functions for making send rights in various ways
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Return in PORT a send right for a new protid, pointing at the peropen PO,
+ with rights initialized from AUTH. */
+error_t
+treefs_peropen_create_right (struct treefs_peropen *po,
+ struct treefs_auth *auth,
+ mach_port_t *port)
+{
+ struct treefs_node *node = po->node;
+ struct treefs_fsys *fsys = node->fsys;
+ struct treefs_handle *handle =
+ ports_allocate_port (fsys->port_bucket,
+ sizeof (struct treefs_handle),
+ fsys->handle_port_class);
+
+ if (handle == NULL)
+ return MACH_PORT_NULL;
+
+ handle->po = po;
+ po->refs++;
+ handle->auth = auth;
+ auth->refs++;
+
+ err = treefs_node_init_handle (node, handle);
+ if (err)
+ {
+ po->refs--;
+ auth->refs--;
+ }
+
+ *port = ports_get_right (handle);
+
+ return 0;
+}
+
+/* Return in PORT a send right for a new handle and a new peropen, pointing
+ at NODE, with rights initialized from AUTH. FLAGS and PARENT_PORT are used
+ to initialize the corresponding fields in the new peropen. */
+error_t
+treefs_node_create_right (struct treefs_node *node, int flags,
+ mach_port_t parent_port, struct treefs_auth *auth,
+ mach_port_t *port)
+{
+ struct treefs_peropen *po = malloc (sizeof (struct treefs_peropen));
+
+ if (po == NULL)
+ return ENOMEM;
+
+ /* Initialize the peropen structure. */
+ po->refs = 0;
+ po->node = node;
+ po->open_flags = flags;
+ po->user_lock_state = LOCK_UN;
+ po->parent_port = parent_port;
+ if (parent_port != MACH_PORT_NULL)
+ mach_port_mod_refs (mach_task_self (),
+ parent_port, MACH_PORT_RIGHT_SEND, 1);
+
+ treefs_node_ref (node);
+
+ err = treefs_node_init_peropen (node, po, flags, auth);
+ if (err)
+ goto puke;
+
+ err = treefs_peropen_create_right (po, auth, port);
+ if (err)
+ goto puke;
+
+ return 0;
+
+ puke:
+ treefs_node_unref (node);
+ free (po);
+ return err;
+}
diff --git a/libtreefs/s-dir.c b/libtreefs/s-dir.c
new file mode 100644
index 00000000..08c4eb99
--- /dev/null
+++ b/libtreefs/s-dir.c
@@ -0,0 +1,112 @@
+/* File_t rpc stubs for directories; see <hurd/fs.defs> for more info
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ Note that since the user overrides the builtin routines via hook vectors
+ instead of declaring his own stubs, it doesn't make a lot of sense to put
+ these routines in separate files like diskfs. This way should compile
+ faster; with dynamic libraries it won't matter in any case.
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+error_t
+treefs_S_dir_notice_changes (struct treefs_protid *cred,
+ mach_port_t notify)
+{
+ if (cred == NULL)
+ return EOPNOTSUPP;
+ return treefs_s_dir_notice_changes (cred, notify);
+}
+
+error_t
+treefs_S_dir_link (struct treefs_protid *dir_cred,
+ struct treefs_protid *file_cred,
+ char *name)
+{
+ if (cred == NULL)
+ return EOPNOTSUPP;
+ return treefs_s_dir_link (dir_cred, file_cred, name);
+}
+
+error_t
+treefs_S_dir_lookup (struct treefs_protid *cred,
+ char *path, int flags, mode_t mode,
+ enum retry_type *retry, char *retry_name,
+ file_t *result, mach_msg_type_name_t *result_type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_dir_lookup (cred, path, flags, mode, retry, retry_name,
+ result, result_type);
+}
+
+error_t
+treefs_S_dir_mkdir (struct treefs_protid *cred, char *name, mode_t mode)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_dir_mkdir (cred, name, mode);
+}
+
+error_t
+treefs_S_dir_mkfile (struct treefs_protid *cred,
+ int flags, mode_t mode,
+ mach_port_t *newnode, mach_msg_type_name_t *newnode_type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_dir_mkfile (cred, flags, mode, newnode, newnode_type);
+}
+
+error_t
+treefs_S_dir_readdir (struct treefs_protid *cred,
+ char **data, unsigned *datacnt,
+ int entry, int num_entries,
+ vm_size_t bufsiz, int *amt)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_dir_readdir (cred, data, datacnt,
+ entry, num_entries, bufsiz, amt);
+}
+
+error_t
+treefs_S_dir_rename (struct treefs_protid *cred, char *name,
+ struct treefs_protid *to_cred, char *to_name)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_dir_rename (cred, name, to_cred, to_name);
+}
+
+error_t
+treefs_S_dir_rmdir (struct treefs_protid *cred, char *name)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_dir_rmdir (cred, name);
+}
+
+error_t
+treefs_S_dir_unlink (struct treefs_protid *cred, char *name)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_dir_unlink (cred, name);
+}
diff --git a/libtreefs/s-file.c b/libtreefs/s-file.c
new file mode 100644
index 00000000..cd9144da
--- /dev/null
+++ b/libtreefs/s-file.c
@@ -0,0 +1,233 @@
+/* File_t rpc stubs; see <hurd/fs.defs> for more info
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ Note that since the user overrides the builtin routines via hook vectors
+ instead of declaring his own stubs, it doesn't make a lot of sense to put
+ these routines in separate files (like diskfs). This way should compile
+ faster, with dynamic libraries it won't matter in any case.
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+error_t
+treefs_S_file_check_access (struct treefs_protid *cred, int *type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_check_access (cred, type);
+}
+
+error_t
+treefs_S_file_chauthor (struct treefs_protid *cred, uid_t author)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_chauthor (cred, author);
+}
+
+error_t
+treefs_S_file_chflags (struct treefs_protid *cred, int flags)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_chflags (cred, flags);
+}
+
+error_t
+treefs_S_file_notice_changes (struct treefs_protid *cred, mach_port_t notify)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_notice_changes (cred, notify);
+}
+
+error_t
+treefs_S_file_chmod (struct treefs_protid *cred, mode_t mode)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ mode &= ~(S_IFMT | S_ISPARE);
+ return treefs_s_file_chmod (cred, mode);
+}
+
+error_t
+treefs_S_file_chown (struct treefs_protid *cred, uid_t uid, gid_t gid)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_chown (cred, uid, gid);
+}
+
+error_t
+treefs_S_file_exec (struct treefs_protid *cred,
+ task_t task, int flags,
+ char *argv, unsigned argv_len,
+ char *envp, unsigned envp_len,
+ mach_port_t *fds, unsigned fds_len,
+ mach_port_t *ports, unsigned ports_len,
+ int *ints, unsigned ints_len,
+ mach_port_t *dealloc, unsigned dealloc_len,
+ mach_port_t *destroy, unsigned destroy_len)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_exec (cred, task, flags, argv, argv_len, envp, envp_len,
+ fds, fds_len, ports, ports_len, ints, ints_len,
+ dealloc, dealloc_len, destroy, destroy_len);
+}
+
+error_t
+treefs_S_file_get_translator (struct treefs_protid *cred,
+ char **trans, unsigned *trans_len)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_get_translator (cred, trans, trans_len);
+}
+
+error_t
+treefs_S_file_get_translator_cntl (struct treefs_protid *cred,
+ mach_port_t *ctl,
+ mach_msg_type_name_t *ctl_type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_get_translator_cntl (cred, ctl, ctl_type);
+}
+
+error_t
+treefs_S_file_getcontrol (struct treefs_protid *cred,
+ mach_port_t *control,
+ mach_msg_type_name_t *control_type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_getcontrol (cred, control, control_type);
+}
+
+error_t
+treefs_S_file_getfh (struct treefs_protid *cred,
+ char **data, unsigned *data_len)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_getfh (cred, data, data_len);
+}
+
+error_t
+treefs_S_file_getlinknode (struct treefs_protid *cred,
+ file_t *port, mach_msg_type_name_t *port_type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_t (cred, port, port_type);
+}
+
+error_t
+treefs_S_file_invoke_translator (struct treefs_protid *cred,
+ int flags,
+ retry_type *retry, char *retry_name,
+ mach_port_t *retry_port,
+ mach_msg_type_name_t *retry_port_type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_invoke_translator (cred, flags, retry, retry_name,
+ retry_port, retry_port_type);
+}
+
+error_t
+treefs_S_file_lock_stat (struct treefs_protid *cred,
+ int *self_status, int *other_status)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_lock_stat (cred, self_status, other_status);
+}
+
+error_t
+treefs_S_file_lock (struct treefs_protid *cred, int flags)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_lock (cred, flags);
+}
+
+error_t
+treefs_S_file_pathconf (struct treefs_protid *cred, int name, int *value)
+ {
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_pathconf (cred, name, value);
+}
+
+error_t
+treefs_S_file_set_translator (struct treefs_protid *cred,
+ int passive_flags, int active_flags,
+ int killtrans_flags,
+ char *passive, unsigned passive_len,
+ fsys_t active)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_set_translator (cred, passive_flags, active_flags,
+ killtrans_flags, passive, passive_len,
+ active);
+}
+
+error_t
+treefs_S_file_statfs (struct treefs_protid *cred, fsys_statfsbuf_t *statbuf)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_statfs (cred, statbuf);
+}
+
+error_t
+treefs_S_file_sync (struct treefs_protid *cred, int wait)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_sync (cred, wait);
+}
+
+error_t
+treefs_S_file_syncfs (struct treefs_protid *cred, int wait, int recurse)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_syncfs (cred, wait, recurse);
+}
+
+error_t
+treefs_S_file_set_size (struct treefs_protid *cred, off_t size)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_set_size (cred, size);
+}
+
+error_t
+treefs_S_file_utimes (struct treefs_protid *cred,
+ time_value_t atime, time_value_t mtime)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_utimes (cred, atime, mtime);
+}
diff --git a/libtreefs/s-fsys.c b/libtreefs/s-fsys.c
new file mode 100644
index 00000000..c2b1835b
--- /dev/null
+++ b/libtreefs/s-fsys.c
@@ -0,0 +1,77 @@
+/* fsys_t rpc stubs; see <hurd/fsys.defs> for more info
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "treefs.h"
+
+#define CALL_FSYS_HOOK(hook, fsys_port, args...) \
+{ \
+ error_t _err; \
+ struct treefs_fsys *_fsys = (struct treefs_fsys *) \
+ ports_lookup_port (0, fsys_port, treefs_fsys_port_class); \
+ if (!_fsys) \
+ return EOPNOTSUPP; \
+ err = hook(_fsys , ##args); \
+ ports_port_deref (&_fsys->pi); \
+ return _err; \
+}
+
+error_t
+treefs_S_fsys_getroot (fsys_t fsys_port, mach_port_t dotdot,
+ uid_t *uids, unsigned nuids,
+ gid_t *gids, unsigned ngids,
+ int flags, retry_type *retry, char *retry_name,
+ file_t *result, mach_msg_type_name_t *result_type)
+{
+ CALL_FSYS_HOOK(treefs_s_fsys_getroot, fsys_port, dotdot, uids, nuids, gids,
+ ngids, flags, retry, retry_name, result, result_type);
+}
+
+error_t
+treefs_S_fsys_set_options (fsys_t fsys_port,
+ char *data, unsigned len, int recurse)
+{
+ CALL_FSYS_HOOK(treefs_s_fsys_set_options, fsys_port, data, len, recurse);
+}
+
+error_t
+treefs_S_fsys_goaway (fsys_t fsys_port, int flags)
+{
+ CALL_FSYS_HOOK(treefs_s_fsys_goaway, fsys_port, flags);
+}
+
+error_t
+treefs_S_fsys_getfile (mach_port_t fsys_port,
+ uid_t *gen_uids, unsigned ngen_uids,
+ gid_t *gen_gids, unsigned ngen_gids,
+ char *handle, unsigned handle_len,
+ mach_port_t *file, mach_msg_type_name_t *file_type)
+{
+ CALL_FSYS_HOOK(treefs_s_fsys_getfile, fsys_port, gen_uids, ngen_uids,
+ gen_gids, ngen_gids, handle, handle_len, file, file_type);
+}
+
+error_t
+treefs_S_fsys_syncfs (fsys_t fsys_port, int wait, int recurse)
+{
+ CALL_FSYS_HOOK(treefs_s_fsys_syncfs, fsys_port, wait, recurse);
+}
+
diff --git a/libtreefs/s-io.c b/libtreefs/s-io.c
new file mode 100644
index 00000000..6fdc504a
--- /dev/null
+++ b/libtreefs/s-io.c
@@ -0,0 +1,284 @@
+/* io_t rpc stubs; see <hurd/io.defs> for more info
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ Note that since the user overrides the builtin routines via hook vectors
+ instead of declaring his own stubs, it doesn't make a lot of sense to put
+ these routines in separate files (like diskfs). This way should compile
+ faster, with dynamic libraries it won't matter in any case.
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+error_t
+treefs_S_io_get_icky_async_id (struct treefs_protid *cred,
+ mach_port_t *id, mach_msg_type_name_t *id_type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_get_icky_async_id (cred, id, id_type);
+}
+
+error_t
+treefs_S_io_async (struct treefs_protid *cred,
+ mach_port_t notify,
+ mach_port_t *id, mach_msg_type_name_t *id_type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_async (cred, notify, id, id_type);
+}
+
+error_t
+treefs_S_io_duplicate (struct treefs_protid *cred,
+ mach_port_t *port,
+ mach_msg_type_name_t *port_type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_duplicate (cred, port, port_type);
+}
+
+error_t
+treefs_S_io_get_conch (struct treefs_protid *cred)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_get_conch (cred);
+}
+
+error_t
+treefs_S_io_interrupt (struct treefs_protid *cred)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_interrupt (cred);
+}
+
+error_t
+treefs_S_io_map_cntl (struct treefs_protid *cred,
+ memory_object_t *ctlobj,
+ mach_msg_type_name_t *ctlobj_type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_map_cntl (cred, ctlobj, ctlobj_type);
+}
+
+error_t
+treefs_S_io_map (struct treefs_protid *cred,
+ memory_object_t *rdobj, mach_msg_type_name_t *rd_type,
+ memory_object_t *wrobj, mach_msg_type_name_t *wr_type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_map (cred, rdobj, rd_type, wrobj, wr_type);
+}
+
+error_t
+treefs_S_io_get_openmodes (struct treefs_protid *cred, int *bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_get_openmodes (cred, bits);
+}
+
+error_t
+treefs_S_io_clear_some_openmodes (struct treefs_protid *cred, int bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_clear_some_openmodes (cred, bits);
+}
+
+error_t
+treefs_S_io_set_some_openmodes (struct treefs_protid *cred, int bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_set_some_openmodes (cred, bits);
+}
+
+error_t
+treefs_S_io_set_all_openmodes (struct treefs_protid *cred, int bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_set_all_openmodes (cred, bits);
+}
+
+error_t
+treefs_S_io_get_owner (struct treefs_protid *cred, pid_t *owner)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_get_owner (cred, owner);
+}
+
+error_t
+treefs_S_io_mod_owner (struct treefs_protid *cred, pid_t owner)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_mod_owner (cred, owner);
+}
+
+error_t
+treefs_S_io_prenotify (struct treefs_protid *cred,
+ vm_offset_t start, vm_offset_t end)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_prenotify (cred, start, end);
+}
+
+error_t
+treefs_S_io_read (struct treefs_protid *cred,
+ char **data,
+ mach_msg_type_number_t *data_len,
+ off_t offset,
+ mach_msg_type_number_t max)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_read (cred, data, data_len, offset, max);
+}
+
+error_t
+treefs_S_io_readable (struct treefs_protid *cred,
+ mach_msg_type_number_t *amount)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_readable (cred, amount);
+}
+
+error_t
+treefs_S_io_reauthenticate (struct treefs_protid *cred, mach_port_t rend_port)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_reauthenticate (cred, rend_port);
+}
+
+error_t
+treefs_S_io_release_conch (struct treefs_protid *cred)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_release_conch (cred);
+}
+
+error_t
+treefs_S_io_restrict_auth (struct treefs_protid *cred,
+ mach_port_t *newport,
+ mach_msg_type_name_t *newport_type,
+ uid_t *uids, unsigned nuids,
+ gid_t *gids, unsigned ngids)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_restrict_auth (cred, newport, newport_type,
+ uids, nuids, gids, ngids);
+}
+
+error_t
+treefs_S_io_seek (struct treefs_protid *cred,
+ off_t offset, int whence, off_t *new_offset)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_seek (cred, offset, whence, new_offset);
+}
+
+error_t
+treefs_S_io_select (struct treefs_protid *cred, int *type, int *tag)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_select (cred, type, tag);
+}
+
+error_t
+treefs_S_io_sigio (struct treefs_protid *cred)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_sigio (cred);
+}
+
+error_t
+treefs_S_io_stat (struct treefs_protid *cred, io_statbuf_t *statbuf)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_statbuf_t (cred, statbuf);
+}
+
+error_t
+treefs_S_io_readsleep (struct treefs_protid *cred)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_readsleep (cred);
+}
+
+error_t
+treefs_S_io_eofnotify (struct treefs_protid *cred)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_eofnotify (cred);
+}
+
+error_t
+treefs_S_io_postnotify (struct treefs_protid *cred,
+ vm_offset_t start, vm_offset_t end)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_postnotify (cred, start, end);
+}
+
+error_t
+treefs_S_io_readnotify (struct treefs_protid *cred)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_readnotify (cred);
+}
+
+error_t
+treefs_S_io_server_version (struct treefs_protid *cred,
+ char *server_name,
+ int *major, int *minor, int *edit)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_server_version (cred, server_version, major, minor, edit);
+}
+
+error_t
+treefs_S_io_write (struct treefs_protid *cred,
+ char *data, mach_msg_type_number_t data_len,
+ off_t offset, mach_msg_type_number_t *amount)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_write (cred, data, data_len, offset, amount);
+}
diff --git a/libtreefs/trans-help.c b/libtreefs/trans-help.c
new file mode 100644
index 00000000..b28e93e1
--- /dev/null
+++ b/libtreefs/trans-help.c
@@ -0,0 +1,129 @@
+/* Helper routines for dealing with translators
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "trivfs.h"
+
+/* Return the active translator control port for NODE. If there is no
+ translator, active or passive, MACH_PORT_NULL is returned in CONTROL_PORT.
+ If there is a translator, it is started if necessary, and returned in
+ CONTROL_PORT. *DIR_PORT should be a port right to use as the new
+ translators parent directory. If it is MACH_PORT_NULL, a port is created
+ from DIR and PARENT_PORT and stored in *DIR_PORT; otherwise DIR and
+ PARENT_PORT are not used. Neither NODE or DIR should be locked when
+ calling this function. */
+error_t
+treefs_node_get_active_trans (struct treefs_node *node,
+ struct treefs_node *dir,
+ mach_port_t parent_port,
+ mach_port_t *control_port,
+ mach_port_t *dir_port)
+{
+ /* Fill in dir_port */
+ void make_dir_port ()
+ {
+ mutex_lock (&dir->lock);
+ *dir_port = treefs_node_make_right (dir, 0, parent_port, 0);
+ mach_port_insert_right (mach_task_self (),
+ *dir_port, *dir_port, MACH_MSG_TYPE_MAKE_SEND);
+ mutex_unlock (&dir->lock);
+ }
+
+ mutex_lock (&node->active_trans.lock);
+
+ if (node->active_trans.control != MACH_PORT_NULL)
+ {
+ mach_port_t control = node->active_trans.control;
+ mach_port_mod_refs (mach_task_self (), control,
+ MACH_PORT_RIGHT_SEND, 1);
+ mutex_unlock (&node->active_trans.lock);
+
+ /* Now we have a copy of the translator port that isn't
+ dependent on the translator lock itself. Relock
+ the directory, make a port from it, and then call
+ fsys_getroot. */
+
+ if (*dir_port == MACH_PORT_NULL)
+ make_dir_port ();
+
+ *control_port = control;
+
+ return 0;
+ }
+
+ mutex_unlock (&node->active_trans.lock);
+
+ /* If we get here, then we have no active control port.
+ Check to see if there is a passive translator, and if so
+ repeat the translator check. */
+ mutex_lock (&node->lock);
+ if (!node->istranslated)
+ {
+ *control_port = MACH_PORT_NULL;
+ return 0;
+ }
+
+ err = treefs_node_get_translator (node, trans, &trans_len);
+ if (err == E2BIG)
+ {
+ trans = alloca (trans_len);
+ err = treefs_node_get_translator (node, trans, &trans_len);
+ }
+ if (err)
+ {
+ mutex_unlock (&node->lock);
+ return err;
+ }
+
+ if (*dir_port == MACH_PORT_NULL)
+ {
+ mutex_unlock (&node->lock);
+ make_dir_port ();
+ mutex_lock (&node->lock);
+ }
+
+ /* Try starting the translator (this unlocks NODE). */
+ err = treefs_start_translator (node, trans, trans_len, *dir_port);
+ if (err)
+ return err;
+
+ /* Try again now that we've started the translator... This call
+ should be tail recursive. */
+ return
+ treefs_node_get_active_trans (node, dir, parent_port,
+ control_port, dir_port);
+}
+
+/* Drop the active translator CONTROL_PORT on NODE, unless it's no longer the
+ current active translator, in which case just drop a reference to it. */
+void
+treefs_node_drop_active_trans (struct treefs_node *node,
+ mach_port_t control_port)
+{
+ mutex_lock (&node->active_trans.lock);
+ /* Only zero the control port if it hasn't changed. */
+ if (node->active_trans.control == control)
+ fshelp_translator_drop (&node->active_trans);
+ mutex_unlock (&node->active_trans.lock);
+
+ /* And we're done with this port. */
+ mach_port_deallocate (mach_task_self (), control_port);
+}
diff --git a/libtreefs/trans-start.c b/libtreefs/trans-start.c
new file mode 100644
index 00000000..1b0156bf
--- /dev/null
+++ b/libtreefs/trans-start.c
@@ -0,0 +1,65 @@
+/* Starting a passive translator
+
+ Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+
+ 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "treefs.h"
+
+#include <fcntl.h>
+
+int fshelp_transboot_port_type = PT_TRANSBOOT;
+
+/* Start the translator TRANS (of length TRANS_LEN) on NODE, which should be
+ locked, and will be unlocked when this function returns. PARENT_PORT is
+ a send right to use as the parent port passed to the translator. */
+error_t
+_treefs_node_start_translator (struct treefs_node *node,
+ char *trans, unsigned trans_len,
+ file_t parent_port)
+{
+ error_t err;
+ int mode = O_READ | O_EXEC;
+ struct treefs_auth *auth;
+ file_t node_port;
+ uid_t uid, gid;
+
+ err = treefs_node_get_trans_auth (node, &auth);
+ if (err)
+ return err;
+
+ if (!node->fsys->readonly && treefs_node_type (node) == S_IFREG)
+ mode |= O_WRITE;
+
+ /* Create the REALNODE port for the new filesystem. */
+ node_port = treefs_node_make_right (node, mode, parent_port, auth);
+ mach_port_insert_right (mach_task_self (), node_port, node_port,
+ MACH_MSG_TYPE_MAKE_SEND);
+
+
+ mutex_unlock (&node->lock);
+
+ /* XXXX Change libfshelp so that it take more than 1 uid/gid? */
+ uid = auth->nuids > 0 ? auth->uids[0] : -1;
+ gid = auth->ngids > 0 ? auth->gids[0] : -1;
+
+ err =
+ fshelp_start_translator (&node->active_trans, trans, trans_len,
+ parent_port, node_port, uid, gid);
+
+ treefs_node_auth_unref (node, auth);
+
+ return err;
+}
diff --git a/libtreefs/treefs-hooks.h b/libtreefs/treefs-hooks.h
new file mode 100644
index 00000000..3af4a546
--- /dev/null
+++ b/libtreefs/treefs-hooks.h
@@ -0,0 +1,401 @@
+/* Hooks in libtreefs (also see "treefs-s-hooks.h")
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __TREEFS_HOOKS_H__
+#define __TREEFS_HOOKS_H__
+
+#include "treefs.h"
+
+/* ---------------------------------------------------------------- */
+
+/* Hook indices */
+enum
+{
+ /* file rpcs */
+ TREEFS_HOOK_S_FILE_EXEC, TREEFS_HOOK_S_FILE_CHOWN,
+ TREEFS_HOOK_S_FILE_CHAUTHOR, TREEFS_HOOK_S_FILE_CHMOD,
+ TREEFS_HOOK_S_FILE_CHFLAGS, TREEFS_HOOK_S_FILE_UTIMES,
+ TREEFS_HOOK_S_FILE_SET_SIZE, TREEFS_HOOK_S_FILE_LOCK,
+ TREEFS_HOOK_S_FILE_LOCK_STAT, TREEFS_HOOK_S_FILE_ACCESS,
+ TREEFS_HOOK_S_FILE_NOTICE, TREEFS_HOOK_S_FILE_SYNC,
+ TREEFS_HOOK_S_FILE_GET_LINK_NODE,
+
+ /* io rpcs */
+ TREEFS_HOOK_S_IO_WRITE, TREEFS_HOOK_S_IO_READ, TREEFS_HOOK_S_IO_SEEK,
+ TREEFS_HOOK_S_IO_READABLE, TREEFS_HOOK_S_IO_SET_ALL_OPENMODES,
+ TREEFS_HOOK_S_IO_GET_OPENMODES, TREEFS_HOOK_S_IO_SET_SOME_OPENMODES,
+ TREEFS_HOOK_S_IO_CLEAR_SOME_OPENMODES, TREEFS_HOOK_S_IO_ASYNC,
+ TREEFS_HOOK_S_IO_MOD_OWNER, TREEFS_HOOK_S_IO_GET_OWNER,
+ TREEFS_HOOK_S_IO_GET_ICKY_ASYNC_ID, TREEFS_HOOK_S_IO_SELECT,
+ TREEFS_HOOK_S_IO_STAT, TREEFS_HOOK_S_IO_REAUTHENTICATE,
+ TREEFS_HOOK_S_IO_RESTRICT_AUTH, TREEFS_HOOK_S_IO_DUPLICATE,
+ TREEFS_HOOK_S_IO_SERVER_VERSION, TREEFS_HOOK_S_IO_MAP,
+ TREEFS_HOOK_S_IO_MAP_CNTL, TREEFS_HOOK_S_IO_RELEASE_CONCH,
+ TREEFS_HOOK_S_IO_EOFNOTIFY, TREEFS_HOOK_S_IO_PRENOTIFY,
+ TREEFS_HOOK_S_IO_POSTNOTIFY, TREEFS_HOOK_S_IO_READNOTIFY,
+ TREEFS_HOOK_S_IO_READSLEEP, TREEFS_HOOK_S_IO_SIGIO,
+
+ /* directory rpcs */
+ TREEFS_HOOK_S_DIR_LOOKUP, TREEFS_HOOK_S_DIR_READDIR, TREEFS_HOOK_S_DIR_MKDIR,
+ TREEFS_HOOK_S_DIR_RMDIR, TREEFS_HOOK_S_DIR_UNLINK, TREEFS_HOOK_S_DIR_LINK,
+ TREEFS_HOOK_S_DIR_RENAME, TREEFS_HOOK_S_DIR_MKFILE,
+ TREEFS_HOOK_S_DIR_NOTICE_CHANGES,
+
+ /* filesystem rpcs */
+ TREEFS_HOOK_S_FSYS_GETROOT, TREEFS_HOOK_S_FSYS_SET_OPTIONS,
+ TREEFS_HOOK_S_FSYS_SYNCFS, TREEFS_HOOK_S_FSYS_GETFILE, TREEFS_S_FSYS_GOAWAY,
+
+ /* Non-rpc fsys hooks */
+ TREEFS_HOOK_FSYS_CREATE_NODE, TREEFS_HOOK_FSYS_DESTROY_NODE,
+ TREEFS_HOOK_FSYS_GET_ROOT,
+
+ /* Node hooks */
+ TREEFS_HOOK_NODE_TYPE,
+ TREEFS_HOOK_NODE_UNLINKED, TREEFS_HOOK_NODE_MOD_LINK_COUNT,
+ TREEFS_HOOK_DIR_LOOKUP, TREEFS_HOOK_DIR_NOENT,
+ TREEFS_HOOK_DIR_CREATE_CHILD, TREEFS_HOOK_DIR_LINK, TREEFS_HOOK_DIR_UNLINK,
+ TREEFS_HOOK_NODE_OWNED, TREEFS_HOOK_NODE_ACCESS,
+ TREEFS_HOOK_NODE_GET_SYMLINK, TREEFS_HOOK_NODE_GET_PASSIVE_TRANS,
+ TREEFS_HOOK_NODE_START_TRANSLATOR, TREEFS_HOOK_NODE_GET_TRANS_AUTH,
+ TREEFS_HOOK_NODE_DROP, TREEFS_HOOK_NODE_INIT, TREEFS_HOOK_DIR_INIT,
+ TREEFS_HOOK_NODE_INIT_PEROPEN, TREEFS_HOOK_NODE_INIT_HANDLE,
+ TREEFS_HOOK_NODE_FINALIZE, TREEFS_HOOK_DIR_FINALIZE,
+ TREEFS_HOOK_NODE_FINALIZE_PEROPEN, TREEFS_HOOK_NODE_FINALIZE_HANDLE,
+
+ /* Reference counting support */
+ TREEFS_HOOK_NODE_NEW_REFS, TREEFS_HOOK_NODE_LOST_REFS,
+ TREEFS_HOOK_NODE_TRY_DROPPING_WEAK_REFS,
+
+ TREEFS_NUM_HOOKS
+};
+
+/* ---------------------------------------------------------------- */
+/* Hook calling/defining macros */
+
+/* Call the hook number HOOK in the hook vector HOOKS, whose function is of
+ type TYPE, with the args ARGS (my this is a useful comment). */
+#define TREEFS_CALL_HOOK(hooks, hook, type, args...) \
+ ((type *)(hooks)[hook])(args)
+#define TREEFS_CALL_HANDLE_HOOK(h, hook, type, args...) \
+ ({struct treefs_handle *_tfs_cn_h = (h); \
+ TREEFS_CALL_HOOK(_tfs_cn_h->po->node->hooks,hook,type, \
+ _tfs_cn_h , ##args);})
+#define TREEFS_CALL_NODE_HOOK(node, hook, type, args...) \
+ ({struct treefs_node *_tfs_cn_node = (node); \
+ TREEFS_CALL_HOOK(_tfs_cn_node->hooks,hook,type, _tfs_cn_node , ##args);})
+#define TREEFS_CALL_FSYS_HOOK(fsys, hook, type, args...) \
+ ({struct treefs_fsys *_tfs_cn_fsys = (fsys); \
+ TREEFS_CALL_HOOK(_tfs_cn_fsys->hooks,hook,type, _tfs_cn_fsys , ##args);})
+
+/* Shorthand form of TREEFS_CALL_*_HOOK (only used here). */
+#define _TREEFS_CHH(h, hook_id, type_id, args...) \
+ TREEFS_CALL_HANDLE_HOOK(h, TREEFS_HOOK_##hook_id, treefs_##type_id##_t , ##args)
+#define _TREEFS_CNH(node, hook_id, type_id, args...) \
+ TREEFS_CALL_NODE_HOOK(node, TREEFS_HOOK_##hook_id, treefs_##type_id##_t , ##args)
+#define _TREEFS_CFH(fsys, hook_id, type_id, args...) \
+ TREEFS_CALL_FSYS_HOOK(fsys, TREEFS_HOOK_##hook_id, treefs_##type_id##_t , ##args)
+
+/* Forward declare some structures used before definition. */
+struct treefs_node;
+struct treefs_fsys;
+struct treefs_auth;
+struct treefs_handle;
+struct treefs_peropen;
+
+/* Shorthand for declaring the various hook types (each hook has an
+ associated type so that a user can type-check his hook routine). */
+#define DNH(name_sym, ret_type, argtypes...) \
+ typedef ret_type treefs_##name_sym##_t (struct treefs_node * , ##argtypes);
+#define DFH(name_sym, ret_type, argtypes...) \
+ typedef ret_type treefs_##name_sym##_t (struct treefs_fsys * , ##argtypes);
+
+/* ---------------------------------------------------------------- */
+/* Non RPC hooks */
+
+/* Called to get the root node of the a filesystem, with a reference,
+ returning it in ROOT, or return an error if it can't be had. The default
+ hook just returns FSYS->root or an error if it's NULL. Note that despite
+ the similar name, this is very different from fsys_s_getroot! FSYS must
+ not be locked. */
+DFH(fsys_get_root, error_t, struct treefs_node **root)
+#define treefs_fsys_get_root(fsys, args...) \
+ _TREEFS_CFH(fsys, FSYS_GET_ROOT, fsys_get_root , ##args)
+
+/* Called on a filesystem to create a new node in that filesystem, returning
+ it, with one reference, in NODE. DIR, if non-NULL, is the nominal parent
+ directory, and MODE and AUTH are the desired mode and user info
+ respectively. This hook should also call node_init_stat & node_init to
+ initialize the various user bits. */
+DFH(fsys_create_node, error_t,
+ struct treefs_node *dir, mode_t mode, struct treefs_auth *auth,
+ struct treefs_node **node)
+#define treefs_fsys_create_node(fsys, args...) \
+ _TREEFS_CFH(fsys, FSYS_CREATE_NODE, fsys_create_node , ##args)
+
+/* Called on a filesystem to destroy a node in that filesystem. This call
+ should *really* destroy it -- i.e., it's only called once all references
+ are gone. */
+DFH(fsys_destroy_node, void, struct treefs_node *node)
+#define treefs_fsys_destroy_node(fsys, node) \
+ _TREEFS_CFH(fsys, FSYS_DESTROY_NODE, fsys_destroy_node , ##args)
+
+/* Returns the type of NODE, as an S_IFMT value (e.g., S_IFDIR). The
+ default routine just looks at NODE's stat mode. */
+DNH(node_type, int);
+#define treefs_node_type(node, args...) \
+ _TREEFS_CNH(node, NODE_TYPE, node_type , ##args)
+
+#define treefs_node_isdir(node) (treefs_node_type(node) == S_IFDIR)
+#define treefs_node_isreg(node) (treefs_node_type(node) == S_IFREG)
+
+/* Return TRUE if NODE is `unlinked' -- that is, can be deleted when all
+ (in-memory) references go away. */
+DNH(node_unlinked, int);
+#define treefs_node_unlinked(node, args...) \
+ _TREEFS_CNH(node, NODE_UNLINKED, node_unlinked , ##args)
+
+/* Changes the link count of NODE by CHANGE; if any error is returned, the
+ operation trying to change the link count will fail, so filesystems that
+ don't support real links can restrict it to 1 or 0. This is mostly used
+ by the in-core directory code when it makes a link. The default hook uses
+ the link field of NODE's stat entry. */
+DNH(node_mod_link_count, error_t, int change);
+#define treefs_node_mod_link_count(node, args...) \
+ _TREEFS_CNH(node, NODE_MOD_LINK_COUNT, node_mod_link_count , ##args)
+
+/* Lookup NAME in NODE, returning the result in CHILD; AUTH should be used to
+ do authentication. If FLAGS contains O_CREAT, and NAME is not found, then
+ an entry should be created with a mode of CREATE_MODE (which includes the
+ S_IFMT bits, e.g., S_IFREG means a normal file), unless O_EXCL is also
+ set, in which case EEXIST should be returned. Possible special errors
+ returned include: EAGAIN -- result would be the parent of our filesystem
+ root. Note that is a single-level lookup, unlike treefs_s_dir_lookup. */
+DNH(dir_lookup, error_t,
+ char *name, struct treefs_auth *auth, int flags, int create_mode,
+ struct treefs_node **child)
+#define treefs_dir_lookup(dir, args...) \
+ _TREEFS_CNH(dir, DIR_LOOKUP, dir_lookup , ##args)
+
+/* Called by the default implementation of treefs_dir_lookup (and possibly
+ user-versions as well) when a directory lookup returns ENOENT, before a
+ new node is created. This hook may return the desire node in CHILD and
+ return 0, or return an error code. Note that a returned node need not
+ actually be in the directory DIR, and indeed may be anonymous. */
+DNH(dir_noent, error_t,
+ char *name, struct treefs_auth *auth, int flags, int create_mode,
+ struct treefs_node **child);
+#define treefs_dir_noent(dir, args...) \
+ _TREEFS_CNH(dir, DIR_NOENT, dir_noent , ##args)
+
+/* Return in CHILD a new node with one reference, presumably a possible child
+ of DIR, with a mode MODE. All attempts to create a new node go through
+ this hook, so it may be overridden to easily control creation (e.g.,
+ replacing it with a hook that always returns EPERM). Note that this
+ routine doesn't actually enter the child into the directory, or give the
+ node a non-zero link count, that should be done by the caller. */
+DNH(dir_create_child, error_t,
+ mode_t mode, struct treefs_auth *auth, struct treefs_node **child);
+#define treefs_dir_create_child(dir, args...) \
+ _TREEFS_CNH(dir, DIR_CREATE_CHILD, dir_create_child , ##args)
+
+/* Link the node CHILD into DIR as NAME, using AUTH to check authentication.
+ DIR should be locked and CHILD shouldn't be. The default hook puts it
+ into DIR's in-core directory, and uses a reference to CHILD (this way, a
+ node can be linked to both in-core and out-of-core directories and the
+ permanent link-count will be right). */
+DNH(dir_link, error_t,
+ char *name, struct treefs_node *child, struct treefs_auth *auth)
+#define treefs_dir_link(dir, args...) \
+ _TREEFS_CNH(dir, DIR_LINK, dir_link , ##args)
+
+/* Remove the entry NAME from DIR, using AUTH to check authentication. DIR
+ should be locked. The default hook removes NAME from DIR's in-core
+ directory. */
+DNH(dir_unlink, error_t, char *name, struct treefs_auth *auth)
+#define treefs_dir_unlink(dir, args...) \
+ _TREEFS_CNH(dir, DIR_UNLINK, dir_unlink , ##args)
+
+/* Check to see if the user identified by AUTH is permitted to do owner-only
+ operations on node NP; if so, return 0; if not, return EPERM. */
+DNH(node_owned, error_t, struct treefs_auth *auth)
+#define treefs_node_owned(node, args...) \
+ _TREEFS_CNH(node, NODE_OWNED, node_owned , ##args)
+
+/* Check to see is the user identified by AUTH is permitted to do
+ operation OP on node NP. Op is one of S_IREAD, S_IWRITE, or S_IEXEC.
+ Return 0 if the operation is permitted and EACCES if not. */
+DNH(node_access, error_t, int opt, struct treefs_auth *auth)
+#define treefs_node_access(node, args...) \
+ _TREEFS_CNH(node, NODE_ACCESS, node_access , ##args)
+
+/* NODE now has no more references; clean all state. The
+ _treefs_node_refcnt_lock must be held, and will be released upon return.
+ NODE must be locked. */
+DNH(node_drop, error_t);
+#define treefs_node_drop(node, args...) \
+ _TREEFS_CNH(node, NODE_DROP, node_drop , ##args)
+
+/* Called when a new directory is created, after trees_node_init. If this
+ routine returns an error, the new node will be destroyed and the create
+ will fail. */
+DNH(dir_init, error_t)
+#define treefs_dir_init(dir, args...) \
+ _TREEFS_CNH(dir, DIR_INIT, dir_init , ##args)
+
+/* If NODE is a symlink, copies the contents into BUF, which should have at
+ least *LEN bytes available, and returns 0; if the symlink is too big,
+ E2BIG is returned. Either way, the actual length of the symlink is
+ returned in *LEN (so if it's too big, you can allocate an appropiately
+ sized buffer and try again). If NODE is not a symlink, EINVAL is
+ returned. */
+DNH(node_get_symlink, error_t, char *buf, int *len)
+#define treefs_node_get_symlink(node, args...) \
+ _TREEFS_CNH(node, NODE_GET_SYMLINK, node_get_symlink , ##args)
+
+/* If NODE has a passive translator, copies the contents into BUF, which
+ should have at least *LEN bytes available, and returns 0; if the string is
+ too big, E2BIG is returned. Either way, the actual length of the
+ translator string is returned in *LEN (so if it's too big, you can
+ allocate an appropiately sized buffer and try again). If NODE has no
+ passive translator, EINVAL is returned. */
+DNH(node_get_passive_trans, error_t, char *buf, int *len)
+#define treefs_node_get_passive_trans(node, args...) \
+ _TREEFS_CNH(node, NODE_GET_PASSIVE_TRANS, node_get_passive_trans , ##args)
+
+/* Returns the user and group that a newly started translator should be
+ authenticated as. The default just returns the owner/group of NODE. */
+DNH(node_get_trans_auth, error_t, uid_t *uid, gid_t *gid)
+#define treefs_node_get_trans_auth(node, args...) \
+ _TREEFS_CNH(node, NODE_GET_TRANS_AUTH, node_get_trans_auth , ##args)
+
+/* Start the translator TRANS (of length TRANS_LEN) on NODE, which should be
+ locked, and will be unlocked during the execution of this function.
+ PARENT_PORT should be a send right to use as the parent port passed to the
+ translator. */
+DNH(node_start_translator, error_t,
+ char *trans, unsigned trans_len, file_t parent_port)
+#define treefs_node_start_translator(node, args...) \
+ _TREEFS_CNH(node, NODE_START_TRANSLATOR, node_start_translator , ##args)
+
+/* Called to initialize a new node's stat entry, after all default fields are
+ filled in (but before node_init is called). */
+DNH(node_init_stat, error_t,
+ struct treefs_node *dir, mode_t mode, struct treefs_auth *auth)
+#define treefs_node_init_stat(node, args...) \
+ _TREEFS_CNH(node, NODE_INIT_STAT, node_init_stat , ##args)
+
+/* Called to initialize a new node, after all default fields are filled in.
+ If this routine returns an error, the new node will be destroyed and the
+ create will fail. */
+DNH(node_init, error_t,
+ struct treefs_node *dir, mode_t mode, struct treefs_auth *auth)
+#define treefs_node_init(node, args...) \
+ _TREEFS_CNH(node, NODE_INIT, node_init , ##args)
+
+/* Called to cleanup node-specific info in a node about to be destroyed. */
+DNH(node_finalize, void)
+#define treefs_node_finalize(node, args...) \
+ _TREEFS_CNH(node, NODE_FINALIZE, node_finalize , ##args)
+
+/* Called to cleanup node-specific directory info in a node about to be
+ destroyed. Called before node_finalize. */
+DNH(dir_finalize, void)
+#define treefs_dir_finalize(dir, args...) \
+ _TREEFS_CNH(dir, DIR_FINALIZE, dir_finalize , ##args)
+
+/* Called when the new peropen structure PO is made for NODE, with the
+ authorization in AUTH, opened with the flags FLAGS (note that this a copy
+ of PO->flags, which the hook may modify). If an error is returned, the
+ open will fail with that error. The default hook does explicit checks
+ against AUTH using treefs_node_access, and otherwise does nothing. */
+DNH(node_init_peropen, error_t,
+ struct treefs_peropen *po, int flags, struct treefs_auth *auth)
+#define treefs_node_init_peropen(node, args...) \
+ _TREEFS_CNH(node, NODE_INIT_PEROPEN, node_init_peropen , ##args)
+
+/* Called the peropen structure PO for NODE is being destroyed. */
+DNH(node_finalize_peropen, void, struct treefs_peropen *po)
+#define treefs_node_finalize_peropen(node, args...) \
+ _TREEFS_CNH(node, NODE_FINALIZE_PEROPEN, node_finalize_peropen , ##args)
+
+/* Called when a new handle structure is made for a node. The default does
+ nothing. */
+DNH(node_init_handle, void, struct treefs_handle *handle)
+#define treefs_node_init_handle(node, args...) \
+ _TREEFS_CNH(node, NODE_INIT_HANDLE, node_init_handle , ##args)
+
+/* Called when the handle HANDLE for NODE is being destroyed. */
+DNH(node_finalize_handle, void, struct treefs_handle *handle)
+#define treefs_node_finalize_handle(node, args...) \
+ _TREEFS_CNH(node, NODE_FINALIZE_HANDLE, node_finalize_handle , ##args)
+
+/* ---------------------------------------------------------------- */
+/* Ref counting stuff */
+
+/* NODE has just acquired a hard reference where it had none previously. It
+ is thus now OK again to have weak references without real users. NODE is
+ locked. */
+DNH(node_new_refs, void);
+#define treefs_node_new_refs(node, args...) \
+ _TREEFS_CNH(node, NODE_NEW_REFS, node_new_refs , ##args)
+
+/* NODE has some weak references but has just lost its last hard reference.
+ NP is locked. */
+DNH(node_lost_refs, void);
+#define treefs_node_lost_refs(node, args...) \
+ _TREEFS_CNH(node, NODE_LOST_REFS, node_lost_refs , ##args)
+
+/* NODE has some weak references, but has just lost its last hard references.
+ Take steps so that if any weak references can be freed, they are. NP is
+ locked as is the pager refcount lock. This function will be called after
+ treefs_node_lost_refs. */
+DNH(node_try_dropping_weak_refs, void);
+#define treefs_node_try_dropping_weak_refs(node, args...) \
+ _TREEFS_CNH(node, NODE_TRY_DROPPING_WEAK_REFS, node_try_dropping_weak_refs , ##args)
+
+/* Turn off our shorthand notation. */
+#undef DNH
+#undef DFH
+
+/* ---------------------------------------------------------------- */
+/* Default routines for some hooks (each is the default value for the hook
+ with the same name minus the leading underscore). When you add something
+ here, you should also add it to the initialize code in defhooks.c. */
+
+treefs_fsys_create_node_t _treefs_fsys_create_node;
+treefs_fsys_destroy_node_t _treefs_fsys_destroy_node;
+treefs_fsys_get_root_t _treefs_fsys_get_root;
+treefs_node_type_t _treefs_node_type;
+treefs_node_unlinked_t _treefs_node_unlinked;
+treefs_node_mod_link_count_t _treefs_node_mod_link_count;
+treefs_node_mod_link_count_t _treefs_mod_link_count;
+treefs_dir_lookup_t _treefs_dir_lookup;
+treefs_dir_noent_t _treefs_dir_noent;
+treefs_dir_create_child_t _treefs_dir_create_child;
+treefs_dir_link_t _treefs_dir_link;
+treefs_dir_unlink_t _treefs_dir_unlink;
+treefs_node_owned_t _treefs_node_owned;
+treefs_node_access_t _treefs_node_access;
+treefs_node_start_translator_t _treefs_node_start_translator;
+treefs_node_get_trans_auth_t _treefs_node_get_trans_auth;
+
+#endif /* __TREEFS_HOOKS_H__ */
diff --git a/libtreefs/treefs-s-hooks.h b/libtreefs/treefs-s-hooks.h
new file mode 100644
index 00000000..2ea9e7ab
--- /dev/null
+++ b/libtreefs/treefs-s-hooks.h
@@ -0,0 +1,231 @@
+/* RPC server hooks in libtreefs (also see "treefs-hooks.h")
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __TREEFS_S_HOOKS_H__
+#define __TREEFS_S_HOOKS_H__
+
+#include "treefs-hooks.h"
+
+/* Shorthand for declaring the various hook types (each hook has an
+ associated type so that a user can type-check his hook routine). */
+#define DHH(name_sym, ret_type, argtypes...) \
+ typedef ret_type treefs_##name_sym##_t (struct treefs_handle * , ##argtypes);
+#define DFH(name_sym, ret_type, argtypes...) \
+ typedef ret_type treefs_##name_sym##_t (struct treefs_fsys * , ##argtypes);
+
+/* ---------------------------------------------------------------- */
+/* Hooks for file RPCs. See <hurd/fs.defs> for more info. */
+
+DHH(s_file_exec, error_t,
+ task_t, int, char *, unsigned, char *, unsigned, mach_port_t *, unsigned,
+ mach_port_t *, unsigned, int *, unsigned,
+ mach_port_t *, unsigned, mach_port_t *, unsigned)
+#define treefs_s_file_exec(h, args...) \
+ _TREEFS_CHH(h, S_FILE_EXEC, s_file_exec , ##args)
+DHH(s_file_chown, error_t, uid_t, gid_t)
+#define treefs_s_file_chown(h, args...) \
+ _TREEFS_CHH(h, S_FILE_CHOWN, s_file_chown , ##args)
+DHH(s_file_chauthor, error_t, uid_t)
+#define treefs_s_file_chauthor(h, args...) \
+ _TREEFS_CHH(h, S_FILE_CHAUTHOR, s_file_chauthor , ##args)
+DHH(s_file_chmod, error_t, mode_t)
+#define treefs_s_file_chmod(h, args...) \
+ _TREEFS_CHH(h, S_FILE_CHMOD, s_file_chmod , ##args)
+DHH(s_file_chflags, error_t, int)
+#define treefs_s_file_chflags(h, args...) \
+ _TREEFS_CHH(h, S_FILE_CHFLAGS, s_file_chflags , ##args)
+DHH(s_file_utimes, error_t, time_value_t, time_value_t)
+#define treefs_s_file_utimes(h, args...) \
+ _TREEFS_CHH(h, S_FILE_UTIMES, s_file_utimes , ##args)
+DHH(s_file_truncate, error_t, off_t)
+#define treefs_s_file_truncate(h, args...) \
+ _TREEFS_CHH(h, S_FILE_TRUNCATE, s_file_truncate , ##args)
+DHH(s_file_lock, error_t, struct treefs_handle *, int)
+#define treefs_s_file_lock(h, args...) \
+ _TREEFS_CHH(h, S_FILE_LOCK, s_file_lock , ##args)
+DHH(s_file_lock_stat, error_t, int *, int *)
+#define treefs_s_file_lock_stat(h, args...) \
+ _TREEFS_CHH(h, S_FILE_LOCK_STAT, s_file_lock_stat , ##args)
+DHH(s_file_notice_changes, error_t, mach_port_t)
+#define treefs_s_file_notice_changes(h, args...) \
+ _TREEFS_CHH(h, S_FILE_NOTICE, s_file_notice_changes , ##args)
+DHH(s_file_sync, error_t, int)
+#define treefs_s_file_sync(h, args...) \
+ _TREEFS_CHH(h, S_FILE_SYNC, s_file_sync , ##args)
+DHH(s_file_getlinknode, error_t, file_t *, mach_msg_type_name_t *)
+#define treefs_s_file_getlinknode(h, args...) \
+ _TREEFS_CHH(h, S_FILE_GET_LINK_NODE, s_file_getlinknode , ##args)
+
+/* ---------------------------------------------------------------- */
+/* Hooks for IO rpcs. See <hurd/io.defs> for more info. */
+
+DHH(s_io_write, error_t, char *, unsigned, off_t, int *)
+#define treefs_s_io_write(h, args...) \
+ _TREEFS_CHH(h, S_IO_WRITE, s_io_write , ##args)
+DHH(s_io_read, error_t, char **, unsigned *, off_t, int)
+#define treefs_s_io_read(h, args...) \
+ _TREEFS_CHH(h, S_IO_READ, s_io_read , ##args)
+DHH(s_io_seek, error_t, off_t, int, off_t *)
+#define treefs_s_io_seek(h, args...) \
+ _TREEFS_CHH(h, S_IO_SEEK, s_io_seek , ##args)
+DHH(s_io_readable, error_t, unsigned *)
+#define treefs_s_io_readable(h, args...) \
+ _TREEFS_CHH(h, S_IO_READABLE, s_io_readable , ##args)
+DHH(s_io_set_all_openmodes, error_t, int)
+#define treefs_s_io_set_all_openmodes(h, args...) \
+ _TREEFS_CHH(h, S_IO_SET_ALL_OPENMODES, s_io_set_all_openmodes , ##args)
+DHH(s_io_get_openmodes, error_t, int *)
+#define treefs_s_io_get_openmodes(h, args...) \
+ _TREEFS_CHH(h, S_IO_GET_OPENMODES, s_io_get_openmodes , ##args)
+DHH(s_io_set_some_openmodes, error_t, int)
+#define treefs_s_io_set_some_openmodes(h, args...) \
+ _TREEFS_CHH(h, S_IO_SET_SOME_OPENMODES, s_io_set_some_openmodes , ##args)
+DHH(s_io_clear_some_openmodes, error_t, int)
+#define treefs_s_io_clear_some_openmodes(h, args...) \
+ _TREEFS_CHH(h, S_IO_CLEAR_SOME_OPENMODES, s_io_clear_some_openmodes , ##args)
+DHH(s_io_async, error_t, mach_port_t, mach_port_t *, mach_msg_type_name_t *)
+#define treefs_s_io_async(h, args...) \
+ _TREEFS_CHH(h, S_IO_ASYNC, s_io_async , ##args)
+DHH(s_io_mod_owner, error_t, pid_t)
+#define treefs_s_io_mod_owner(h, args...) \
+ _TREEFS_CHH(h, S_IO_MOD_OWNER, s_io_mod_owner , ##args)
+DHH(s_io_get_owner, error_t, pid_t *)
+#define treefs_s_io_get_owner(h, args...) \
+ _TREEFS_CHH(h, S_IO_GET_OWNER, s_io_get_owner , ##args)
+DHH(s_io_get_icky_async_id, error_t, mach_port_t *, mach_msg_type_name_t *)
+#define treefs_s_io_get_icky_async_id(h, args...) \
+ _TREEFS_CHH(h, S_IO_GET_ICKY_ASYNC_ID, s_io_get_icky_async_id , ##args)
+DHH(s_io_select, error_t, int *, int *)
+#define treefs_s_io_select(h, args...) \
+ _TREEFS_CHH(h, S_IO_SELECT, s_io_select , ##args)
+DHH(s_io_stat, error_t, io_statbuf_t *)
+#define treefs_s_io_stat(h, args...) \
+ _TREEFS_CHH(h, S_IO_STAT, s_io_stat , ##args)
+DHH(s_io_reauthenticate, error_t, mach_port_t *, mach_msg_type_name_t *)
+#define treefs_s_io_reauthenticate(h, args...) \
+ _TREEFS_CHH(h, S_IO_REAUTHENTICATE, s_io_reauthenticate , ##args)
+DHH(s_io_restrict_auth, error_t,
+ mach_port_t *, mach_msg_type_name_t *, uid_t *, int, gid_t *, int);
+#define treefs_s_io_restrict_auth(h, args...) \
+ _TREEFS_CHH(h, S_IO_RESTRICT_AUTH, s_io_restrict_auth , ##args)
+DHH(s_io_duplicate, error_t, mach_port_t *, mach_msg_type_name_t *)
+#define treefs_s_io_duplicate(h, args...) \
+ _TREEFS_CHH(h, S_IO_DUPLICATE, s_io_duplicate , ##args)
+DHH(s_io_server_version, error_t, char *, int *, int *, int *)
+#define treefs_s_io_server_version(h, args...) \
+ _TREEFS_CHH(h, S_IO_SERVER_VERSION, s_io_server_version , ##args)
+DHH(s_io_map, error_t, mach_port_t *, mach_msg_type_name_t *, mach_port_t *, mach_msg_type_name_t *)
+#define treefs_s_io_map(h, args...) \
+ _TREEFS_CHH(h, S_IO_MAP, s_io_map , ##args)
+DHH(s_io_map_cntl, error_t, mach_port_t *, mach_msg_type_name_t *)
+#define treefs_s_io_map_cntl(h, args...) \
+ _TREEFS_CHH(h, S_IO_MAP_CNTL, s_io_map_cntl , ##args)
+DHH(s_io_release_conch, error_t, struct treefs_handle *)
+#define treefs_s_io_release_conch(h, args...) \
+ _TREEFS_CHH(h, S_IO_RELEASE_CONCH, s_io_release_conch, ##args)
+DHH(s_io_eofnotify, error_t);
+#define treefs_s_io_eofnotify(h, args...) \
+ _TREEFS_CHH(h, S_IO_EOFNOTIFY, s_io_eofnotify , ##args)
+DHH(s_io_prenotify, error_t, vm_offset_t, vm_offset_t);
+#define treefs_s_io_prenotify(h, args...) \
+ _TREEFS_CHH(h, S_IO_PRENOTIFY, s_io_prenotify , ##args)
+DHH(s_io_postnotify, error_t, vm_offset_t, vm_offset_t);
+#define treefs_s_io_postnotify(h, args...) \
+ _TREEFS_CHH(h, S_IO_POSTNOTIFY, s_io_postnotify , ##args)
+DHH(s_io_readnotify, error_t);
+#define treefs_s_io_readnotify(h, args...) \
+ _TREEFS_CHH(h, S_IO_READNOTIFY, s_io_readnotify , ##args)
+DHH(s_io_readsleep, error_t);
+#define treefs_s_io_readsleep(h, args...) \
+ _TREEFS_CHH(h, S_IO_READSLEEP, s_io_readsleep , ##args)
+DHH(s_io_sigio, error_t);
+#define treefs_s_io_sigio(h, args...) \
+ _TREEFS_CHH(h, S_IO_SIGIO, s_io_sigio , ##args)
+
+/* ---------------------------------------------------------------- */
+/* Hooks for directory RPCs. See <hurd/fs.defs> for more info. */
+
+DHH(s_dir_lookup, error_t,
+ char *, int, mode_t, enum retry_type *, char *,
+ file_t *, mach_msg_type_name_t *);
+#define treefs_s_dir_lookup(h, args...) \
+ _TREEFS_CHH(h, S_DIR_LOOKUP, s_dir_lookup , ##args)
+DHH(s_dir_readdir, error_t, char **, unsigned, int, int, vm_size_t, int *);
+#define treefs_s_dir_readdir(h, args...) \
+ _TREEFS_CHH(h, S_DIR_READDIR, s_dir_readdir , ##args)
+DHH(s_dir_mkdir, error_t, char *, mode_t);
+#define treefs_s_dir_mkdir(h, args...) \
+ _TREEFS_CHH(h, S_DIR_MKDIR, s_dir_mkdir , ##args)
+DHH(s_dir_rmdir, error_t, char *);
+#define treefs_s_dir_rmdir(h, args...) \
+ _TREEFS_CHH(h, S_DIR_RMDIR, s_dir_rmdir , ##args)
+DHH(s_dir_unlink, error_t, char *);
+#define treefs_s_dir_unlink(h, args...) \
+ _TREEFS_CHH(h, S_DIR_UNLINK, s_dir_unlink , ##args)
+DHH(s_dir_link, error_t, file_t, char *);
+#define treefs_s_dir_link(h, args...) \
+ _TREEFS_CHH(h, S_DIR_LINK, s_dir_link , ##args)
+DHH(s_dir_rename, error_t, char *, file_t, char *);
+#define treefs_s_dir_rename(h, args...) \
+ _TREEFS_CHH(h, S_DIR_RENAME, s_dir_rename , ##args)
+DHH(s_dir_mkfile, error_t, int, mode_t, mach_port_t *, mach_msg_type_name_t *);
+#define treefs_s_dir_mkfile(h, args...) \
+ _TREEFS_CHH(h, S_DIR_MKFILE, s_dir_mkfile , ##args)
+DHH(s_dir_notice_changes, error_t, mach_port_t *, mach_msg_type_name_t *);
+#define treefs_s_dir_notice_changes(h, args...) \
+ _TREEFS_CHH(h, S_DIR_NOTICE_CHANGES, s_dir_notice_changes , ##args)
+
+/* ---------------------------------------------------------------- */
+/* fsys RPCs (called on the filesystem itself) */
+
+DFH(s_fsys_getroot, error_t,
+ mach_port_t, uid_t *, unsigned, gid_t *, unsigned, int,
+ retry_type *, char *, file_t *, mach_msg_type_name_t *)
+#define treefs_s_fsys_getroot(fsys, args...) \
+ _TREEFS_CFH(fsys, S_FSYS_GETROOT, s_fsys_getroot , ##args)
+DFH(s_fsys_set_options, error_t, char *, unsigned, int)
+#define treefs_s_fsys_set_options(fsys, args...) \
+ _TREEFS_CFH(fsys, S_FSYS_SET_OPTIONS, s_fsys_set_options , ##args)
+DFH(s_fsys_goaway, error_t, int)
+#define treefs_s_fsys_goaway(fsys, args...) \
+ _TREEFS_CFH(fsys, S_FSYS_GOAWAY, s_fsys_goaway , ##args)
+DFH(s_fsys_getfile, error_t,
+ uid_t *, unsigned, gid_t *, unsigned, char *, unsigned,
+ mach_port_t *, mach_msg_type_name_t *)
+#define treefs_s_fsys_getfile(fsys, args...) \
+ _TREEFS_CFH(fsys, S_FSYS_GETFILE, s_fsys_getfile , ##args)
+DFH(s_fsys_syncfs, error_t, int, int)
+#define treefs_s_fsys_syncfs(fsys, args...) \
+ _TREEFS_CFH(fsys, S_FSYS_SYNCFS, s_fsys_syncfs , ##args)
+
+/* Turn off our shorthand notation. */
+#undef DHH
+
+/* ---------------------------------------------------------------- */
+/* Default routines for some hooks (each is the default value for the hook
+ with the same name minus the leading underscore). When you add something
+ here, you should also add it to the initialize code in defhooks.c. */
+
+treefs_s_dir_lookup_t _treefs_s_dir_lookup;
+treefs_s_fsys_getroot_t _treefs_s_fsys_getroot;
+
+#endif /* __TREEFS_S_HOOKS_H__ */
diff --git a/libtreefs/treefs.h b/libtreefs/treefs.h
new file mode 100644
index 00000000..b0c26849
--- /dev/null
+++ b/libtreefs/treefs.h
@@ -0,0 +1,472 @@
+/* Hierarchial filesystem support
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __TREEFS_H__
+#define __TREEFS_H__
+
+#include <errno.h>
+#include <cthreads.h>
+#include <assert.h>
+
+#include <sys/stat.h>
+
+#include <hurd/hurd_types.h>
+#include <hurd/ports.h>
+#include <hurd/fshelp.h>
+
+/* Include the hook calling macros and non-rpc hook definitions (to get
+ those, include "trees-s-hooks.h"). */
+#include "treefs-hooks.h"
+
+/* ---------------------------------------------------------------- */
+
+typedef void (**treefs_hook_vector_t)();
+
+/* A list of nodes. */
+struct treefs_node_list;
+
+/* Each user port referring to a file points to one of these. */
+struct treefs_handle
+{
+ struct port_info pi;
+ struct treefs_auth *auth; /* User identification */
+ struct treefs_peropen *po; /* The io object itself */
+ void *u; /* for user use */
+};
+
+/* An authentication cookie. */
+struct treefs_auth
+{
+ int refs;
+ uid_t *uids, *gids;
+ int nuids, ngids;
+ int isroot;
+ void *u; /* for user use */
+};
+
+/* Bits the user is permitted to set with io_*_openmodes */
+#define TREEFS_SETTABLE_FLAGS (O_APPEND|O_ASYNC|O_FSYNC|O_NONBLOCK|O_NOATIME)
+
+/* Bits that are turned off after open */
+#define TREEFS_OPENONLY_FLAGS (O_CREAT|O_EXCL|O_NOLINK|O_NOTRANS|O_NONBLOCK)
+
+struct treefs_peropen
+{
+ int refs;
+ int open_flags;
+ int user_lock_state;
+
+ /* A port to the directory through which this open file was reached. */
+ mach_port_t parent_port;
+
+ void *u; /* for user use */
+
+ struct treefs_node *node;
+};
+
+/* A filesystem node in the tree. */
+struct treefs_node
+{
+ struct stat stat;
+ struct treefs_fsys *fsys;
+
+ struct trans_link active_trans;
+ char *passive_trans;
+ struct lock_box user_lock;
+
+ struct mutex lock;
+ unsigned refs, weak_refs;
+
+ /* Node ops */
+ treefs_hook_vector_t hooks;
+
+ /* If this node is a directory, then this is the directory state. */
+ struct treefs_node_list *children;
+
+ void *u; /* for user use */
+};
+
+struct treefs_node_list
+{
+ struct treefs_node **nodes;
+ unsigned short num_nodes, nodes_alloced;
+ char *names;
+ unsigned short names_len, names_alloced;
+};
+
+struct treefs_fsys
+{
+ struct port_info pi;
+ struct mutex lock;
+
+ /* The root node in this filesystem. */
+ struct treefs_node *root;
+
+ /* The port for the node which this filesystem is translating. */
+ mach_port_t underlying_port;
+ /* And stat info for it. */
+ struct stat underlying_stat;
+
+ /* Flags from the TREEFS_FSYS_ set. */
+ int flags;
+ /* Max number of symlink expansions allowed. */
+ unsigned max_symlinks;
+ /* Sync interval (in seconds). 0 means all operations should be
+ synchronous, any negative value means never sync. */
+ int sync_interval;
+
+ /* Values to return from a statfs. */
+ int fs_type;
+ int fs_id;
+
+ /* This is the hook vector that each new node in this filesystem starts out
+ with. */
+ treefs_hook_vector_t hooks;
+
+ /* The port bucket to which all of our ports belongs. */
+ struct ports_bucket *port_bucket;
+
+ /* Various classes of ports we know about. */
+ struct port_class *handle_port_class;
+
+ void *u; /* for user use */
+};
+
+/* Filesystem flags. */
+#define TREEFS_FSYS_READONLY 0x1
+
+/* ---------------------------------------------------------------- */
+/* In-core directory management routines (`mdir' == `memory dir'). These are
+ intended for keeping non-permanent directory state. If called on a
+ non-dir, ENOTDIR is returned. */
+
+/* Add CHILD to DIR as NAME, replacing any existing entry. If OLD_CHILD is
+ NULL, and NAME already exists in dir, EEXIST is returned, otherwise, any
+ previous child is replaced and returned in OLD_CHILD. DIR should be
+ locked. */
+error_t treefs_mdir_add (struct treefs_node *dir, char *name,
+ struct treefs_node *child,
+ struct treefs_node **old_child);
+
+/* Remove any entry in DIR called NAME. If there is no such entry, ENOENT is
+ returned. If OLD_CHILD is non-NULL, any removed entry is returned in it.
+ DIR should be locked. */
+error_t treefs_mdir_remove (struct treefs_node *dir, char *name,
+ struct treefs_node **old_child);
+
+/* Returns in NODE any entry called NAME in DIR, or NULL (and ENOENT) if
+ there isn't such. DIR should be locked. */
+error_t treefs_mdir_get (struct treefs_node *dir, char *name,
+ struct treefs_node **node);
+
+/* Call FUN on each child of DIR; if FUN returns a non-zero value at any
+ point, stop iterating and return that value immediately. */
+error_t treefs_mdir_for_each (struct treefs_node *dir,
+ error_t (*fun)(struct treefs_node *node));
+
+/* ---------------------------------------------------------------- */
+/* Functions for dealing with node lists. */
+
+/* Return a new node list, or NULL if a memory allocation error occurs. */
+struct treefs_node_list *treefs_make_node_list ();
+
+/* Add NODE to LIST as NAME, replacing any existing entry. If OLD_NODE is
+ NULL, and an entry NAME already exists, EEXIST is returned, otherwise, any
+ previous child is replaced and returned in OLD_NODE. */
+error_t treefs_node_list_add (struct treefs_node_list *list, char *name,
+ struct treefs_node *node,
+ struct treefs_node **old_node);
+
+/* Remove any entry in LIST called NAME. If there is no such entry, ENOENT is
+ returned. If OLD_NODE is non-NULL, any removed entry is returned in it. */
+error_t treefs_node_list_remove (struct treefs_node_list *list, char *name,
+ struct treefs_node **old_node);
+
+/* Returns in NODE any entry called NAME in LIST, or NULL (and ENOENT) if
+ there isn't such. */
+error_t treefs_node_list_get (struct treefs_node_list *list, char *name,
+ struct treefs_node **node);
+
+/* Call FUN on each node in LIST; if FUN returns a non-zero value at any
+ point, stop iterating and return that value immediately. */
+error_t treefs_node_list_for_each (struct treefs_node_list *list,
+ error_t (*fun)(char *name,
+ struct treefs_node *node));
+
+/* ---------------------------------------------------------------- */
+/* Functions for manipulating hook vectors. */
+
+typedef void (*treefs_hook_vector_init_t[TREEFS_NUM_HOOKS])();
+
+extern treefs_hook_vector_init_t treefs_default_hooks;
+
+/* Returns a copy of the treefs hook vector HOOKS, or a zero'd vector if HOOKS
+ is NULL. If HOOKS is NULL, treefs_default_hooks is used. If a memory
+ allocation error occurs, NULL is returned. */
+treefs_hook_vector_t treefs_hooks_clone (treefs_hook_vector_t hooks);
+
+/* Copies each non-NULL entry in OVERRIDES into HOOKS. */
+void treefs_hooks_override (treefs_hook_vector_t hooks,
+ treefs_hook_vector_t overrides);
+
+/* Sets the hook NUM in HOOKS to HOOK. */
+void treefs_hooks_set (treefs_hook_vector_t hooks,
+ unsigned num, void (*hook)());
+
+/* ---------------------------------------------------------------- */
+/* Reference counting function (largely stolen from diskfs). */
+
+extern spin_lock_t treefs_node_refcnt_lock;
+
+/* Add a hard reference to a node. If there were no hard
+ references previously, then the node cannot be locked
+ (because you must hold a hard reference to hold the lock). */
+extern inline void
+treefs_node_ref (struct treefs_node *node)
+{
+ int new_ref;
+ spin_lock (&treefs_node_refcnt_lock);
+ node->refs++;
+ new_ref = (node->refs == 1);
+ spin_unlock (&treefs_node_refcnt_lock);
+ if (new_ref)
+ {
+ mutex_lock (&node->lock);
+ treefs_node_new_refs (node);
+ mutex_unlock (&node->lock);
+ }
+}
+
+/* Unlock node NODE and release a hard reference; if this is the last
+ hard reference and there are no links to the file then request
+ weak references to be dropped. */
+extern inline void
+treefs_node_release (struct treefs_node *node)
+{
+ int tried_drop_weak_refs = 0;
+
+ loop:
+ spin_lock (&treefs_node_refcnt_lock);
+ assert (node->refs);
+ node->refs--;
+ if (node->refs + node->weak_refs == 0)
+ treefs_node_drop (node);
+ else if (node->refs == 0 && !tried_drop_weak_refs)
+ {
+ spin_unlock (&treefs_node_refcnt_lock);
+ treefs_node_lost_refs (node);
+ if (treefs_node_unlinked (node))
+ {
+ /* There are no links. If there are weak references that
+ can be dropped, we can't let them postpone deallocation.
+ So attempt to drop them. But that's a user-supplied
+ routine, which might result in further recursive calls to
+ the ref-counting system. So we have to reacquire our
+ reference around the call to forestall disaster. */
+ spin_unlock (&treefs_node_refcnt_lock);
+ node->refs++;
+ spin_unlock (&treefs_node_refcnt_lock);
+
+ treefs_node_try_dropping_weak_refs (node);
+
+ /* But there's no value in looping forever in this
+ routine; only try to drop weak references once. */
+ tried_drop_weak_refs = 1;
+
+ /* Now we can drop the reference back... */
+ goto loop;
+ }
+ }
+ else
+ spin_unlock (&treefs_node_refcnt_lock);
+ mutex_unlock (&node->lock);
+}
+
+/* Release a hard reference on NODE. If NODE is locked by anyone, then
+ this cannot be the last hard reference (because you must hold a
+ hard reference in order to hold the lock). If this is the last
+ hard reference and there are no links, then request weak references
+ to be dropped. */
+extern inline void
+treefs_node_unref (struct treefs_node *node)
+{
+ int tried_drop_weak_refs = 0;
+
+ loop:
+ spin_lock (&treefs_node_refcnt_lock);
+ assert (node->refs);
+ node->refs--;
+ if (node->refs + node->weak_refs == 0)
+ {
+ mutex_lock (&node->lock);
+ treefs_node_drop (node);
+ }
+ else if (node->refs == 0)
+ {
+ mutex_lock (&node->lock);
+ spin_unlock (&treefs_node_refcnt_lock);
+ treefs_node_lost_refs (node);
+ if (treefs_node_unlinked(node) && !tried_drop_weak_refs)
+ {
+ /* Same issue here as in nodeut; see that for explanation */
+ spin_unlock (&treefs_node_refcnt_lock);
+ node->refs++;
+ spin_unlock (&treefs_node_refcnt_lock);
+
+ treefs_node_try_dropping_weak_refs (node);
+ tried_drop_weak_refs = 1;
+
+ /* Now we can drop the reference back... */
+ mutex_unlock (&node->lock);
+ goto loop;
+ }
+ mutex_unlock (&node->lock);
+ }
+ else
+ spin_unlock (&treefs_node_refcnt_lock);
+}
+
+/* Add a weak reference to a node. */
+extern inline void
+treefs_node_ref_weak (struct treefs_node *node)
+{
+ spin_lock (&treefs_node_refcnt_lock);
+ node->weak_refs++;
+ spin_unlock (&treefs_node_refcnt_lock);
+}
+
+/* Unlock node NODE and release a weak reference */
+extern inline void
+treefs_node_release_weak (struct treefs_node *node)
+{
+ spin_lock (&treefs_node_refcnt_lock);
+ assert (node->weak_refs);
+ node->weak_refs--;
+ if (node->refs + node->weak_refs == 0)
+ treefs_node_drop (node);
+ else
+ {
+ spin_unlock (&treefs_node_refcnt_lock);
+ mutex_unlock (&node->lock);
+ }
+}
+
+/* Release a weak reference on NODE. If NODE is locked by anyone, then
+ this cannot be the last reference (because you must hold a
+ hard reference in order to hold the lock). */
+extern inline void
+treefs_node_unref_weak (struct treefs_node *node)
+{
+ spin_lock (&treefs_node_refcnt_lock);
+ assert (node->weak_refs);
+ node->weak_refs--;
+ if (node->refs + node->weak_refs == 0)
+ {
+ mutex_lock (&node->lock);
+ treefs_node_drop (node);
+ }
+ else
+ spin_unlock (&treefs_node_refcnt_lock);
+}
+
+/* ---------------------------------------------------------------- */
+
+/* Return in PORT a send right for a new handle, pointing at the peropen PO,
+ with rights initialized from AUTH. */
+error_t
+treefs_peropen_create_right (struct treefs_peropen *po,
+ struct treefs_auth *auth,
+ mach_port_t *port);
+
+/* Return a send right for a new handle and a new peropen, pointing at NODE,
+ with rights initialized from AUTH. MODE and PARENT_PORT are used to
+ initialize the corresponding fields in the new peropen. */
+error_t
+treefs_node_create_right (struct treefs_node *node, int flags,
+ mach_port_t parent_port, struct treefs_auth *auth,
+ mach_port_t *port);
+
+/* ---------------------------------------------------------------- */
+/* Auth functions; copied from diskfs. */
+
+/* Return nonzero iff the user identified by AUTH has uid UID. */
+extern inline int
+treefs_auth_has_uid (struct treefs_auth *auth, uid_t uid)
+{
+ int i;
+ for (i = 0; i < auth->nuids; i++)
+ if (auth->uids[i] == uid)
+ return 1;
+ return 0;
+}
+
+/* Return nonzero iff the user identified by AUTH has group GID. */
+extern inline int
+treefs_auth_in_group (struct treefs_auth *auth, gid_t gid)
+{
+ int i;
+ for (i = 0; i < auth->ngids; i++)
+ if (auth->gids[i] == gid)
+ return 1;
+ return 0;
+}
+
+/* ---------------------------------------------------------------- */
+/* Helper routines for dealing with translators. */
+
+/* Return the active translator control port for NODE. If there is no
+ translator, active or passive, MACH_PORT_NULL is returned in CONTROL_PORT.
+ If there is a translator, it is started if necessary, and returned in
+ CONTROL_PORT. *DIR_PORT should be a port right to use as the new
+ translators parent directory. If it is MACH_PORT_NULL, a port is created
+ from DIR and PARENT_PORT and stored in *DIR_PORT; otherwise DIR and
+ PARENT_PORT are not used. Neither NODE or DIR should be locked when
+ calling this function. */
+error_t treefs_node_get_active_trans (struct treefs_node *node,
+ struct treefs_node *dir,
+ mach_port_t parent_port,
+ mach_port_t *control_port,
+ mach_port_t *dir_port);
+
+/* Drop the active translator CONTROL_PORT on NODE, unless it's no longer the
+ current active translator, in which case just drop a reference to it. */
+void treefs_node_drop_active_trans (struct treefs_node *node,
+ mach_port_t control_port);
+
+/* ---------------------------------------------------------------- */
+/* Basic node creation. */
+
+/* Create a basic node, with one reference and no user-specific fields
+ initialized, and return it in NODE */
+error_t
+treefs_create_node (struct treefs_fsys *fsys, struct treefs_node **node);
+
+/* Immediately destroy NODE, with no user-finalization. */
+error_t treefs_free_node (struct treefs_node *node);
+
+/* ---------------------------------------------------------------- */
+/* Some global variables. */
+
+/* The port class used by treefs to make filesystem control ports. */
+struct port_class *treefs_fsys_port_class;
+
+#endif /* __TREEFS_H__ */