summaryrefslogtreecommitdiff
path: root/unionfs/lnode.c
diff options
context:
space:
mode:
Diffstat (limited to 'unionfs/lnode.c')
-rw-r--r--unionfs/lnode.c184
1 files changed, 184 insertions, 0 deletions
diff --git a/unionfs/lnode.c b/unionfs/lnode.c
new file mode 100644
index 00000000..9b242bba
--- /dev/null
+++ b/unionfs/lnode.c
@@ -0,0 +1,184 @@
+/* Hurd unionfs
+ Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+ Written by Moritz Schulte <moritz@duesseldorf.ccc.de>.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or * (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA. */
+
+/* `light node' management. See unionfs.h for an explanation of light
+ nodes. */
+
+#define _GNU_SOURCE
+
+#include <hurd/netfs.h>
+#include <error.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lnode.h"
+#include "lib.h"
+#include "unionfs.h"
+
+/* Create a new light node as an entry with the name NAME and store it
+ in *NODE. The new node is not locked and contains a single
+ reference. */
+error_t
+lnode_create (char *name, lnode_t **node)
+{
+ lnode_t *node_new = malloc (sizeof (lnode_t));
+ error_t err = 0;
+
+ debug_msg ("lnode_create for name: %s", name);
+
+ if (! node_new)
+ err = ENOMEM;
+ else
+ {
+ char *name_cp = NULL;
+
+ if (name)
+ name_cp = strdup (name);
+ if (name && (! name_cp))
+ {
+ err = ENOMEM;
+ free (node_new);
+ }
+ else
+ {
+ node_new->name = name_cp;
+ node_new->name_len = name_cp ? strlen (name_cp) : 0;
+ node_new->flags = 0;
+ node_new->node = NULL;
+ node_new->next = NULL;
+ node_new->prevp = NULL;
+ node_new->dir = NULL;
+ node_new->entries = NULL;
+ node_new->references = 1;
+ mutex_init (&node_new->lock);
+ mutex_lock (&node_new->lock);
+ *node = node_new;
+ }
+ }
+ return err;
+}
+
+/* Destroy a light node. */
+void
+lnode_destroy (lnode_t *node)
+{
+ debug_msg ("lnode_destroy for name: %s", node->name);
+ free (node->name);
+ free (node);
+}
+
+/* Install the node in the node tree; add a reference to DIR, which
+ must be locked. */
+void
+lnode_install (lnode_t *dir, lnode_t *node)
+{
+ lnode_ref_add (dir);
+ node->next = dir->entries;
+ node->prevp = &dir->entries;
+ if (dir->entries)
+ dir->entries->prevp = &node->next;
+ dir->entries = node;
+ node->dir = dir;
+}
+
+/* Uninstall the node from the node tree; remove a reference from the
+ lnode containing NODE. */
+void
+lnode_uninstall (lnode_t *node)
+{
+ lnode_ref_remove (node->dir);
+ *node->prevp = node->next;
+ if (node->next)
+ node->next->prevp = &node->next;
+}
+
+/* Add a reference to NODE, which must be locked. */
+void
+lnode_ref_add (lnode_t *node)
+{
+ node->references++;
+}
+
+/* Remove a reference to NODE, which must be locked. If that was the
+ last reference, destroy the node, otherwise simply unlock NODE. */
+void
+lnode_ref_remove (lnode_t *node)
+{
+ assert (node->references);
+ if (! --node->references)
+ {
+ lnode_uninstall (node);
+ lnode_destroy (node);
+ }
+ else
+ mutex_unlock (&node->lock);
+}
+
+/* Get a light node by it's name. The looked up node is locked and
+ got one reference added. */
+error_t
+lnode_get (lnode_t *dir, char *name,
+ lnode_t **node)
+{
+ error_t err = 0;
+ lnode_t *n;
+
+ for (n = dir->entries; n && strcmp (n->name, name); n = n->next);
+ if (n)
+ {
+ mutex_lock (&n->lock);
+ lnode_ref_add (n);
+ *node = n;
+ }
+ else
+ err = ENOENT;
+
+ return err;
+}
+
+/* Construct the full path for a given light node. */
+error_t
+lnode_path_construct (lnode_t *node,
+ char **path)
+{
+ error_t err = 0;
+ int p_len = 1;
+ lnode_t *n;
+ char *p;
+
+ for (n = node; n && n->dir; n = n->dir)
+ p_len += n->name_len + (n->dir->dir ? 1 : 0);
+
+ p = malloc (p_len);
+ if (! p)
+ err = ENOMEM;
+ else
+ {
+ *(p + --p_len) = 0;
+ for (n = node; n && n->dir; n = n->dir)
+ {
+ p_len -= n->name_len;
+ strncpy (p + p_len, n->name, n->name_len);
+ if (n->dir->dir)
+ *(p + --p_len) = '/';
+ }
+ *path = p;
+ }
+ return err;
+}