summaryrefslogtreecommitdiff
path: root/lnode.c
diff options
context:
space:
mode:
authorSergiu Ivanov <unlimitedscolobb@gmail.com>2008-07-13 20:26:34 +0300
committerSergiu Ivanov <unlimitedscolobb@gmail.com>2008-07-13 20:26:34 +0300
commitc9c70745fbdb4be82796f94e5601109d9071bb46 (patch)
treeb0ec5e62a5f9ee77bc7f52f90a4bba47e74448a7 /lnode.c
Copied the skeleton for mirroring a directory from filterfs.
At the moment nsmux is only capable of creating a read-only mirror of the given directory.
Diffstat (limited to 'lnode.c')
-rw-r--r--lnode.c305
1 files changed, 305 insertions, 0 deletions
diff --git a/lnode.c b/lnode.c
new file mode 100644
index 000000000..285d947bb
--- /dev/null
+++ b/lnode.c
@@ -0,0 +1,305 @@
+/*----------------------------------------------------------------------------*/
+/*lnode.c*/
+/*----------------------------------------------------------------------------*/
+/*Implementation of policies of management of 'light nodes'*/
+/*----------------------------------------------------------------------------*/
+/*Based on the code of unionfs translator.*/
+/*----------------------------------------------------------------------------*/
+/*Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc.
+ Written by Sergiu Ivanov <unlimitedscolobb@gmail.com>.
+
+ 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.*/
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+#define _GNU_SOURCE
+/*----------------------------------------------------------------------------*/
+#include "lnode.h"
+#include "debug.h"
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/*--------Functions-----------------------------------------------------------*/
+/*Adds a reference to the `lnode` (which must be locked)*/
+void
+lnode_ref_add
+ (
+ lnode_t * node
+ )
+ {
+ /*Increment the number of references*/
+ ++node->references;
+ }/*lnode_ref_add*/
+/*----------------------------------------------------------------------------*/
+/*Removes a reference from `node` (which must be locked). If that was the last
+ reference, destroy the node*/
+void
+lnode_ref_remove
+ (
+ lnode_t * node
+ )
+ {
+ /*Fail if the node is not referenced by anybody*/
+ assert(node->references);
+
+ /*Decrement the number of references to `node`*/
+ --node->references;
+
+ /*If there are no references remaining*/
+ if(node->references == 0)
+ {
+ /*uninstall the node from the directory it is in and destroy it*/
+ lnode_uninstall(node);
+ lnode_destroy(node);
+ }
+ else
+ /*simply unlock the node*/
+ mutex_unlock(&node->lock);
+ }/*lnode_ref_remove*/
+/*----------------------------------------------------------------------------*/
+/*Creates a new lnode with `name`; the new node is locked and contains
+ a single reference*/
+error_t
+lnode_create
+ (
+ char * name,
+ lnode_t ** node /*put the result here*/
+ )
+ {
+ /*Allocate the memory for the node*/
+ lnode_t * node_new = malloc(sizeof(lnode_t));
+
+ /*If the memory has not been allocated*/
+ if(!node_new)
+ {
+ /*stop*/
+ return ENOMEM;
+ }
+
+ /*The copy of the name*/
+ char * name_cp = NULL;
+
+ /*If the name exists*/
+ if(name)
+ {
+ /*duplicate it*/
+ name_cp = strdup(name);
+
+ /*If the name has not been duplicated*/
+ if(!name_cp)
+ {
+ /*free the node*/
+ free(node_new);
+
+ /*stop*/
+ return ENOMEM;
+ }
+ }
+
+ /*Setup the new node*/
+ memset(node_new, 0, sizeof(lnode_t));
+ node_new->name = name_cp;
+ node_new->name_len = (name_cp) ? (strlen(name_cp)) : (0);
+
+ /*Setup one reference to this lnode*/
+ node_new->references = 1;
+
+ /*Initialize the mutex and acquire a lock on this lnode*/
+ mutex_init(&node_new->lock);
+ mutex_lock(&node_new->lock);
+
+ /*Store the result in the second parameter*/
+ *node = node_new;
+
+ /*Return success*/
+ return 0;
+ }/*lnode_create*/
+/*----------------------------------------------------------------------------*/
+/*Destroys the given lnode*/
+void
+lnode_destroy
+ (
+ lnode_t * node /*destroy this*/
+ )
+ {
+ /*Destroy the name of the node*/
+ free(node->name);
+
+ /*Destroy the node itself*/
+ free(node);
+ }/*lnode_destroy*/
+/*----------------------------------------------------------------------------*/
+/*Constructs the full path for the given lnode and stores the result both in
+ the parameter and inside the lnode (the same string, actually)*/
+error_t
+lnode_path_construct
+ (
+ lnode_t * node,
+ char ** path /*store the path here*/
+ )
+ {
+ error_t err = 0;
+
+ /*The final path*/
+ char * p;
+
+ /*The final length of the path*/
+ int p_len = 0;
+
+ /*A temporary pointer to an lnode*/
+ lnode_t * n;
+
+ /*While the root node of the proxy filesystem has not been reached*/
+ for(n = node; n && n->dir; n = n->dir)
+ /*add the length of the name of `n` to `p_len` make some space for
+ the delimiter '/', if we are not approaching the root node*/
+ /*p_len += n->name_len + ((n->dir->dir) ? (1) : (0));*/
+ /*There is some path to our root node, so we will anyway have to
+ add a '/'*/
+ p_len += n->name_len + 1;
+
+ /*Include the space for the path to the root node of the proxy
+ (n is now the root of the filesystem)*/
+ p_len += strlen(n->path) + 1;
+
+ /*Try to allocate the space for the string*/
+ p = malloc(p_len * sizeof(char));
+ if(!p)
+ err = ENOMEM;
+ /*If memory allocation has been successful*/
+ else
+ {
+ /*put a terminal 0 at the end of the path*/
+ p[--p_len] = 0;
+
+ /*While the root node of the proxy filesystem has not been reached*/
+ for(n = node; n && n->dir; n = n->dir)
+ {
+ /*compute the position where the name of `n` is to be inserted*/
+ p_len -= n->name_len;
+
+ /*copy the name of the node into the path (omit the terminal 0)*/
+ strncpy(p + p_len, n->name, n->name_len);
+
+ /*If we are not at the root node of the proxy filesystem, add the
+ separator*/
+ /*if(n->dir->dir)
+ p[--p_len] = '/';*/
+ /*we anyway have to add the separator slash*/
+ p[--p_len] = '/';
+ }
+
+ /*put the path to the root node at the beginning of the first path
+ (n is at the root now)*/
+ strncpy(p, n->path, strlen(n->path));
+
+ /*destroy the former path in lnode, if it exists*/
+ if(node->path)
+ free(node->path);
+
+ /*store the new path inside the lnode*/
+ node->path = p;
+
+ /*store the path in the parameter*/
+ if(path)
+ *path = p;
+ }
+
+ /*Return the result of operations*/
+ return err;
+ }/*lnode_path_construct*/
+/*----------------------------------------------------------------------------*/
+/*Gets a light node by its name, locks it and increments its refcount*/
+error_t
+lnode_get
+ (
+ lnode_t * dir, /*search here*/
+ char * name, /*search for this name*/
+ lnode_t ** node /*put the result here*/
+ )
+ {
+ error_t err = 0;
+
+ /*The pointer to the required lnode*/
+ lnode_t * n;
+
+ /*Find `name` among the names of entries in `dir`*/
+ for(n = dir->entries; n && (strcmp(n->name, name) != 0); n = n->next);
+
+ /*If the search has been successful*/
+ if(n)
+ {
+ /*lock the node*/
+ mutex_lock(&n->lock);
+
+ /*increment the refcount of the found lnode*/
+ lnode_ref_add(n);
+
+ /*put a pointer to `n` into the parameter*/
+ *node = n;
+ }
+ else
+ err = ENOENT;
+
+ /*Return the result of operations*/
+ return err;
+ }/*lnode_get*/
+/*----------------------------------------------------------------------------*/
+/*Install the lnode into the lnode tree: add a reference to `dir` (which must
+ be locked)*/
+void
+lnode_install
+ (
+ lnode_t * dir, /*install here*/
+ lnode_t * node /*install this*/
+ )
+ {
+ /*Install `node` into the list of entries in `dir`*/
+ node->next = dir->entries;
+ node->prevp = &dir->entries; /*this node is the first on the list*/
+ if(dir->entries)
+ dir->entries->prevp = &node->next; /*here `prevp` gets the value
+ corresponding to its meaning*/
+ dir->entries = node;
+
+ /*Add a new reference to dir*/
+ lnode_ref_add(dir);
+
+ /*Setup the `dir` link in node*/
+ node->dir = dir;
+ }/*lnode_install*/
+/*----------------------------------------------------------------------------*/
+/*Unistall the node from the node tree; remove a reference from the lnode
+ containing `node`*/
+void
+lnode_uninstall
+ (
+ lnode_t * node
+ )
+ {
+ /*Remove a reference from the parent*/
+ lnode_ref_remove(node->dir);
+
+ /*Make the next pointer in the previous element point to the element,
+ which follows `node`*/
+ *node->prevp = node->next;
+
+ /*If the current node is not the last one, connect the list after removal
+ of the current node*/
+ if(node->next)
+ node->next->prevp = &node->next;
+ }/*lnode_uninstall*/
+/*----------------------------------------------------------------------------*/