summaryrefslogtreecommitdiff
path: root/libtreefs/dir-hooks.c
diff options
context:
space:
mode:
Diffstat (limited to 'libtreefs/dir-hooks.c')
-rw-r--r--libtreefs/dir-hooks.c136
1 files changed, 136 insertions, 0 deletions
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;
+}