summaryrefslogtreecommitdiff
path: root/libtreefs/treefs.h
diff options
context:
space:
mode:
Diffstat (limited to 'libtreefs/treefs.h')
-rw-r--r--libtreefs/treefs.h472
1 files changed, 472 insertions, 0 deletions
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__ */