diff options
Diffstat (limited to 'libtreefs')
-rw-r--r-- | libtreefs/Makefile | 40 | ||||
-rw-r--r-- | libtreefs/defhooks.c | 80 | ||||
-rw-r--r-- | libtreefs/dir-hooks.c | 136 | ||||
-rw-r--r-- | libtreefs/dir-lookup.c | 305 | ||||
-rw-r--r-- | libtreefs/fs-mutate.h | 30 | ||||
-rw-r--r-- | libtreefs/fsys-getroot.c | 144 | ||||
-rw-r--r-- | libtreefs/fsys-hooks.c | 91 | ||||
-rw-r--r-- | libtreefs/fsys-startup.c | 36 | ||||
-rw-r--r-- | libtreefs/fsys.c | 127 | ||||
-rw-r--r-- | libtreefs/hooks.c | 59 | ||||
-rw-r--r-- | libtreefs/mdir.c | 92 | ||||
-rw-r--r-- | libtreefs/mig-decls.h | 41 | ||||
-rw-r--r-- | libtreefs/nlist.c | 70 | ||||
-rw-r--r-- | libtreefs/node-hooks.c | 176 | ||||
-rw-r--r-- | libtreefs/rights.c | 96 | ||||
-rw-r--r-- | libtreefs/s-dir.c | 112 | ||||
-rw-r--r-- | libtreefs/s-file.c | 233 | ||||
-rw-r--r-- | libtreefs/s-fsys.c | 77 | ||||
-rw-r--r-- | libtreefs/s-io.c | 284 | ||||
-rw-r--r-- | libtreefs/trans-help.c | 129 | ||||
-rw-r--r-- | libtreefs/trans-start.c | 65 | ||||
-rw-r--r-- | libtreefs/treefs-hooks.h | 401 | ||||
-rw-r--r-- | libtreefs/treefs-s-hooks.h | 231 | ||||
-rw-r--r-- | libtreefs/treefs.h | 472 |
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__ */ |