summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergiu Ivanov <unlimitedscolobb@gmail.com>2008-09-07 22:36:45 +0300
committerSergiu Ivanov <unlimitedscolobb@gmail.com>2008-09-07 22:36:45 +0300
commitdd5f567d830707ca1530e8e3c2ef7b1c6b4b3862 (patch)
tree0b468f7df0a4aaba9a4c09762825932ac530a4f5
parent13fa6563250dcd4b2d1a54f15aba1bb7d8aace28 (diff)
Added proxy nodes, optimized node management policy
Now, when 'file,,x' is requested, nsmux will create a proxy node and will set the translator 'x' on this node, not on the real filesystem node. Also, nsmux will not create nodes for simple file looks, instead it will simply return the port to the required file, thus avoiding the necessity to handle IO operations inside itself.
-rw-r--r--debug.h2
-rw-r--r--lib.c28
-rw-r--r--lib.h13
-rw-r--r--lnode.c168
-rw-r--r--lnode.h54
-rw-r--r--ncache.c2
-rw-r--r--ncache.h3
-rw-r--r--node.c511
-rw-r--r--node.h71
-rw-r--r--nsmux.c876
-rw-r--r--nsmux.h43
-rw-r--r--options.c2
-rw-r--r--options.h2
13 files changed, 1260 insertions, 515 deletions
diff --git a/debug.h b/debug.h
index c04b5be3d..d4e79cea7 100644
--- a/debug.h
+++ b/debug.h
@@ -5,7 +5,7 @@
/*----------------------------------------------------------------------------*/
/*Based on the code of unionfs translator.*/
/*----------------------------------------------------------------------------*/
-/*Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc.
+/*Copyright (C) 2001, 2002, 2005, 2008 Free Software Foundation, Inc.
Written by Sergiu Ivanov <unlimitedscolobb@gmail.com>.
This program is free software; you can redistribute it and/or
diff --git a/lib.c b/lib.c
index aa0ff0be8..c05e08eae 100644
--- a/lib.c
+++ b/lib.c
@@ -5,7 +5,7 @@
/*----------------------------------------------------------------------------*/
/*Based on the code of unionfs translator.*/
/*----------------------------------------------------------------------------*/
-/*Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc.
+/*Copyright (C) 2001, 2002, 2005, 2008 Free Software Foundation, Inc.
Written by Sergiu Ivanov <unlimitedscolobb@gmail.com>.
This program is free software; you can redistribute it and/or
@@ -28,6 +28,8 @@
#define _GNU_SOURCE 1
/*----------------------------------------------------------------------------*/
#include <sys/mman.h>
+#include <fcntl.h>
+#include <hurd/fshelp.h>
/*----------------------------------------------------------------------------*/
#include "lib.h"
#include "debug.h"
@@ -191,3 +193,27 @@ file_lookup
return err;
}/*file_lookup*/
/*----------------------------------------------------------------------------*/
+/*Checks whether `user` has the right to open the node described by `stat` with
+ `flags`*/
+error_t
+check_open_permissions
+ (
+ struct iouser * user,
+ io_statbuf_t * stat,
+ int flags
+ )
+ {
+ error_t err = 0;
+
+ /*Cheks user's permissions*/
+ if(flags & O_READ)
+ err = fshelp_access(stat, S_IREAD, user);
+ if(!err && (flags & O_WRITE))
+ err = fshelp_access(stat, S_IWRITE, user);
+ if(!err && (flags & O_EXEC))
+ err = fshelp_access(stat, S_IEXEC, user);
+
+ /*Return the result of the check*/
+ return err;
+ }/*check_open_permissions*/
+/*----------------------------------------------------------------------------*/
diff --git a/lib.h b/lib.h
index 6335efcfe..776d475e2 100644
--- a/lib.h
+++ b/lib.h
@@ -5,7 +5,7 @@
/*----------------------------------------------------------------------------*/
/*Based on the code of unionfs translator.*/
/*----------------------------------------------------------------------------*/
-/*Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc.
+/*Copyright (C) 2001, 2002, 2005, 2008 Free Software Foundation, Inc.
Written by Sergiu Ivanov <unlimitedscolobb@gmail.com>.
This program is free software; you can redistribute it and/or
@@ -32,6 +32,7 @@
#include <hurd.h>
#include <dirent.h>
#include <stddef.h>
+#include <hurd/iohelp.h>
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
@@ -79,4 +80,14 @@ file_lookup
io_statbuf_t * stat /*store the stat information here*/
);
/*----------------------------------------------------------------------------*/
+/*Checks whether `user` has the right to open the node described by `stat` with
+ `flags`*/
+error_t
+check_open_permissions
+ (
+ struct iouser * user,
+ io_statbuf_t * stat,
+ int flags
+ );
+/*----------------------------------------------------------------------------*/
#endif /*__LIB_H__*/
diff --git a/lnode.c b/lnode.c
index aed83a0f5..2e6d34eb5 100644
--- a/lnode.c
+++ b/lnode.c
@@ -5,7 +5,7 @@
/*----------------------------------------------------------------------------*/
/*Based on the code of unionfs translator.*/
/*----------------------------------------------------------------------------*/
-/*Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc.
+/*Copyright (C) 2001, 2002, 2005, 2008 Free Software Foundation, Inc.
Written by Sergiu Ivanov <unlimitedscolobb@gmail.com>.
This program is free software; you can redistribute it and/or
@@ -29,6 +29,7 @@
/*----------------------------------------------------------------------------*/
#include "lnode.h"
#include "debug.h"
+#include "node.h"
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
@@ -138,9 +139,19 @@ lnode_destroy
/*Destroy the name of the node*/
free(node->name);
- /*If there is a list of translators*/
- if(node->trans)
- free(node->trans);
+ /*While the list of proxies has not been freed*/
+ node_list_t p;
+ for(p = node->proxies; p;)
+ {
+ /*shift the pointer to the head of the list forward*/
+ node->proxies = node->proxies->next;
+
+ /*drop the current cell in the list*/
+ free(p);
+
+ /*store the current proxy*/
+ p = node->proxies;
+ }
/*Destroy the node itself*/
free(node);
@@ -307,70 +318,111 @@ lnode_uninstall
node->next->prevp = &node->next;
}/*lnode_uninstall*/
/*----------------------------------------------------------------------------*/
-/*Constructs a list of translators that were set on the ancestors of `node`*/
+/*Makes the specified lnode aware of another proxy. Both `node` and `proxy`
+ must be locked*/
error_t
-lnode_list_translators
+lnode_add_proxy
(
lnode_t * node,
- char ** trans, /*the malloced list of 0-separated strings*/
- size_t * ntrans /*the number of elements in `trans`*/
+ node_t * proxy
)
{
- /*The size of block of memory for the list of translators*/
- size_t sz = 0;
-
- /*Used for tracing the lineage of `node`*/
- lnode_t * ln = node;
-
- /*Used in computing the lengths of lists of translators in every node
- we will go through and for constructing the final list of translators*/
- char * p;
-
- /*The current position in *data (used in filling out the list of
- translators)*/
- char * transp;
-
- /*The length of the current translator name*/
- size_t complen;
-
- size_t i;
-
- /*Trace the lineage of the `node` (including itself) and compute the
- total length of the list of translators*/
- for(; ln; sz += ln->translen, ln = ln->dir);
-
- /*Try to allocate a block of memory sufficient for storing the list of
- translators*/
- *trans = malloc(sz);
- if(!*trans)
+ /*TODO: Make the list of proxies finite*/
+
+ /*Create an new cell in the list of proxies*/
+ node_list_t p = malloc(sizeof(node_list_t));
+ if(!p)
return ENOMEM;
+
+ /*If the supplied node references an lnode already
+ (this should always happen, though)*/
+ if(proxy->nn->lnode)
+ /*remove the reference held by the node to that lnode*/
+ lnode_ref_remove(proxy->nn->lnode);
+
+ /*Connect the proxy to the lnode*/
+ proxy->nn->lnode = node;
+
+ /*Store the pointer to the proxy in the new cell*/
+ p->node = proxy;
+
+ /*Add the new cell to the list of proxies*/
+ p->next = node->proxies;
+ node->proxies = p;
- /*No translators at first*/
- *ntrans = 0;
+ /*Count a new reference to this lnode*/
+ lnode_ref_add(node);
- /*Again trace the lineage of the `node` (including itself)*/
- for(transp = *trans + sz, ln = node; ln; ln = ln->dir)
+ /*Everything is OK here*/
+ return 0;
+ }/*lnode_add_proxy*/
+/*----------------------------------------------------------------------------*/
+/*Removes the specified proxy from the list of proxies of the supplied lnode.
+ `proxy` must not be locked*/
+void
+lnode_remove_proxy
+ (
+ lnode_t * node,
+ node_t * proxy
+ )
+ {
+ /*A pointer to a cell in the list of proxies*/
+ node_list_t p;
+
+ /*Lock the lnode*/
+ mutex_lock(&node->lock);
+
+ /*If the first cell in the list contains a reference to `proxy`*/
+ if(node->proxies->node == proxy)
{
- /*Go through each translator name in the list of names*/
- for(i = 0, p = ln->trans + ln->translen - 2; i < ln->ntrans; ++i)
- {
- /*position p at the beginning of the current component and
- compute its length at the same time*/
- for(complen = 0; *p; --p, ++complen);
- --p;
-
- /*move the current position backwards*/
- transp -= complen + 1;
+ /*store a pointer to the head of the list*/
+ p = node->proxies;
+
+ /*shift the head of the list forward*/
+ node->proxies = node->proxies->next;
+
+ /*destroy the former head*/
+ free(p);
+
+ /*remove a reference from the supplied lnode*/
+ lnode_ref_remove(node);
+
+ /*stop right here*/
+ mutex_unlock(&node->lock);
+ return;
+ }
- /*copy the current translator name into the list*/
- strcpy(transp, p + 2);
-
- /*we've got another translator*/
- ++*ntrans;
- }
+ /*Another pointer to a cell in the list*/
+ node_list_t q;
+
+ /*Go through the list of proxy nodes of the given lnode*/
+ for(p = node->proxies; p->next; p = p->next)
+ {
+ /*If the next cell does not contain a reference to the same node,
+ as specified in the parameter, skip this entry*/
+ if(p->next->node != proxy)
+ continue;
+
+ /*store a copy of the next element*/
+ q = p->next;
+
+ /*unregister the next element from the list*/
+ p->next = q->next;
+
+ /*remove the unregistered element*/
+ free(q);
+
+ /*stop looping*/
+ break;
}
+
+ /*Remove a reference from the supplied lnode*/
+ lnode_ref_remove(node);
- /*Everything OK*/
- return 0;
- }/*lnode_list_translators*/
+
+ /*Unlock the node*/
+ mutex_unlock(&node->lock);
+
+ return;
+ }/*lnode_remove_proxy*/
/*----------------------------------------------------------------------------*/
diff --git a/lnode.h b/lnode.h
index 674102523..08a70adef 100644
--- a/lnode.h
+++ b/lnode.h
@@ -5,7 +5,7 @@
/*----------------------------------------------------------------------------*/
/*Based on the code of unionfs translator.*/
/*----------------------------------------------------------------------------*/
-/*Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc.
+/*Copyright (C) 2001, 2002, 2005, 2008 Free Software Foundation, Inc.
Written by Sergiu Ivanov <unlimitedscolobb@gmail.com>.
This program is free software; you can redistribute it and/or
@@ -35,14 +35,25 @@
/*--------Macros--------------------------------------------------------------*/
/*The possible flags in an lnode*/
#define FLAG_LNODE_DIR 0x00000001 /*the lnode is a directory*/
-#define FLAG_LNODE_TRANSLATED 0x00000002 /*all appropriate translators
- have already been set on this node*/
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
+/*--------Types---------------------------------------------------------------*/
/*A candy synonym for the fundamental libnetfs node*/
typedef struct node node_t;
/*----------------------------------------------------------------------------*/
+/*A list of lnodes*/
+struct node_element
+ {
+ /*the node associated with the current entry*/
+ node_t * node;
+
+ /*the next element in the list*/
+ struct node_element * next;
+ };/*struct node_element*/
+/*----------------------------------------------------------------------------*/
+typedef struct node_element * node_list_t;
+/*----------------------------------------------------------------------------*/
/*The light node*/
struct lnode
{
@@ -56,26 +67,19 @@ struct lnode
/*the full path to the lnode*/
char * path;
- /*the malloced set of translators which have to be stacked upon this node
- and upon its children; the corresponding translators will have to decide
- on their own whether to accept directories or not*/
- char * trans;
-
- /*the number of translators listed in `translators`*/
- size_t ntrans;
-
- /*the length of the list of translators (in bytes)*/
- size_t translen;
-
/*the associated flags*/
int flags;
/*the number of references to this lnode*/
int references;
- /*the reference to the real node*/
+ /*the reference to the real netfs node*/
node_t * node;
+ /*the references to the proxy nodes of this lnode;
+ lnodes do not hold references to */
+ node_list_t proxies;
+
/*the next lnode and the pointer to this lnode from the previous one*/
struct lnode * next, **prevp;
@@ -85,7 +89,7 @@ struct lnode
/*the beginning of the list of entries contained in this lnode (directory)*/
struct lnode * entries;
- /*a lock*/
+ /*the lock, protecting this lnode*/
struct mutex lock;
};/*struct lnode*/
/*----------------------------------------------------------------------------*/
@@ -159,13 +163,23 @@ lnode_uninstall
lnode_t * node
);
/*----------------------------------------------------------------------------*/
-/*Constructs a list of translators that were set on the ancestors of `node`*/
+/*Makes the specified lnode aware of another proxy. Both `node` and `proxy`
+ must be locked*/
error_t
-lnode_list_translators
+lnode_add_proxy
(
lnode_t * node,
- char ** trans, /*the malloced list of 0-separated strings*/
- size_t * ntrans /*the number of elements in `trans`*/
+ node_t * proxy
+ );
+/*----------------------------------------------------------------------------*/
+/*Removes the specified proxy from the list of proxies of the supplied lnode.
+ `proxy` must not be locked*/
+void
+lnode_remove_proxy
+ (
+ lnode_t * node,
+ node_t * proxy
);
/*----------------------------------------------------------------------------*/
#endif /*__LNODE_H__*/
+
diff --git a/ncache.c b/ncache.c
index 12462d316..5d39c0d38 100644
--- a/ncache.c
+++ b/ncache.c
@@ -5,7 +5,7 @@
/*----------------------------------------------------------------------------*/
/*Based on the code of unionfs translator.*/
/*----------------------------------------------------------------------------*/
-/*Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc.
+/*Copyright (C) 2001, 2002, 2005, 2008 Free Software Foundation, Inc.
Written by Sergiu Ivanov <unlimitedscolobb@gmail.com>.
This program is free software; you can redistribute it and/or
diff --git a/ncache.h b/ncache.h
index 124d514e6..fd08158b1 100644
--- a/ncache.h
+++ b/ncache.h
@@ -5,7 +5,7 @@
/*----------------------------------------------------------------------------*/
/*Based on the code of unionfs translator.*/
/*----------------------------------------------------------------------------*/
-/*Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc.
+/*Copyright (C) 2001, 2002, 2005, 2008 Free Software Foundation, Inc.
Written by Sergiu Ivanov <unlimitedscolobb@gmail.com>.
This program is free software; you can redistribute it and/or
@@ -40,6 +40,7 @@
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
+/*--------Types---------------------------------------------------------------*/
/*A cache chain*/
struct ncache
{
diff --git a/node.c b/node.c
index a37803e15..fc3bc2aa7 100644
--- a/node.c
+++ b/node.c
@@ -5,7 +5,7 @@
/*----------------------------------------------------------------------------*/
/*Based on the code of unionfs translator.*/
/*----------------------------------------------------------------------------*/
-/*Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc.
+/*Copyright (C) 2001, 2002, 2005, 2008 Free Software Foundation, Inc.
Written by Sergiu Ivanov <unlimitedscolobb@gmail.com>.
This program is free software; you can redistribute it and/or
@@ -33,6 +33,12 @@
#include <sys/mman.h>
#include <stdio.h>
#include <argz.h>
+#include <hurd/fsys.h>
+
+
+/*!!!!!!!REMOVE THIS!!!!!!*/
+#include <sys/file.h>
+
/*----------------------------------------------------------------------------*/
#include "debug.h"
#include "node.h"
@@ -63,6 +69,9 @@ node_create
/*Create a new netnode*/
netnode_t * netnode_new = malloc(sizeof(netnode_t));
+ /*Reset the memory allocated for the new netnode (just in case :-) )*/
+ memset(netnode_new, 0, sizeof(netnode_t));
+
/*If the memory could not be allocated*/
if(netnode_new == NULL)
err = ENOMEM;
@@ -86,12 +95,18 @@ node_create
/*link the lnode to the new node*/
lnode->node = node_new;
- lnode_ref_add(lnode);
-
+
/*setup the references in the newly created node*/
node_new->nn->lnode = lnode;
+ lnode_ref_add(lnode);
+
+ /*setup the information in the netnode*/
node_new->nn->flags = 0;
node_new->nn->ncache_next = node_new->nn->ncache_prev = NULL;
+
+ /*initialize the list of translators*/
+ node_new->nn->trans = NULL;
+ node_new->nn->ntrans = node_new->nn->translen = 0;
/*store the result of creation in the second parameter*/
*node = node_new;
@@ -101,6 +116,64 @@ node_create
return err;
}/*node_create*/
/*----------------------------------------------------------------------------*/
+/*Derives a new proxy from `lnode`*/
+error_t
+node_create_proxy
+ (
+ lnode_t * lnode,
+ node_t ** node /*store the result here*/
+ )
+ {
+ error_t err = 0;
+
+ /*Create a new netnode*/
+ netnode_t * netnode_new = malloc(sizeof(netnode_t));
+
+ /*Reset the memory allocated for the new netnode. We do this here
+ since lnode_add_proxy will try to reference the `lnode` in this netnode
+ and will do bad writes to memory.*/
+ memset(netnode_new, 0, sizeof(netnode_t));
+
+ /*If the memory could not be allocated*/
+ if(netnode_new == NULL)
+ err = ENOMEM;
+ else
+ {
+ /*create a new node from the netnode*/
+ node_t * node_new = netfs_make_node(netnode_new);
+
+ /*If the creation failed*/
+ if(node_new == NULL)
+ {
+ /*set the error code*/
+ err = ENOMEM;
+
+ /*destroy the netnode created above*/
+ free(netnode_new);
+
+ /*stop*/
+ return err;
+ }
+
+ /*add this new node to the list of proxies of `lnode`*/
+ lnode_add_proxy(lnode, node_new);
+
+ /*setup the information in the netnode*/
+ node_new->nn->flags = 0;
+ node_new->nn->ncache_next = node_new->nn->ncache_prev = NULL;
+
+ /*initialize the list of translators*/
+ node_new->nn->trans = NULL;
+ node_new->nn->ntrans = node_new->nn->translen = 0;
+
+ /*store the result of creation in the second parameter*/
+ *node = node_new;
+ }
+
+ /*Return the result of operations*/
+ return err;
+ }/*node_create_proxy*/
+/*----------------------------------------------------------------------------*/
/*Destroys the specified node and removes a light reference from the
associated light node*/
void
@@ -116,19 +189,23 @@ node_destroy
if(np->nn->port != MACH_PORT_NULL)
PORT_DEALLOC(np->nn->port);
- /*If the given node is not the root node and there are translators
- to kill*/
- if(np->nn->lnode->dir && np->nn->lnode->trans)
+ /*If there are translators to kill*/
+ if(np->nn->lnode->dir && np->nn->trans)
{
/*kill all translators on the underlying nodes*/
- node_kill_all_translators(np);
+ node_kill_translators(np);
}
/*Lock the lnode corresponding to the current node*/
mutex_lock(&np->nn->lnode->lock);
- /*Orphan the light node*/
- np->nn->lnode->node = NULL;
+ /*If the node to be destroyed is a real netfs node*/
+ if(np->nn->lnode->node == np)
+ /*orphan the light node*/
+ np->nn->lnode->node = NULL;
+ else
+ /*remove a reference to this node from the list of proxies*/
+ lnode_remove_proxy(np->nn->lnode, np);
/*Remove a reference from the lnode*/
lnode_ref_remove(np->nn->lnode);
@@ -632,22 +709,24 @@ node_unlink_file
return err;
}/*node_unlink_file*/
/*----------------------------------------------------------------------------*/
-/*Sets the given translator on the supplied node*/
-/*This function will normally be called from netfs_attempt_lookup, therefore
- it's better that the caller should provide the parent node for `node`.*/
+/*Sets the given translators on the specified node*/
error_t
-node_set_translator
+node_set_translators
(
- node_t * dir,
- node_t * node,
- const char * trans /*set this on `name`*/
+ struct protid * diruser,
+ node_t * np,
+ char * trans, /*set these on `node`*/
+ size_t ntrans,
+ int flags,
+ mach_port_t * port
)
{
error_t err;
-
- /*A port for opened to the file*/
mach_port_t p;
-
+
+ /*An unauthenticated port to the directory containing `np`*/
+ mach_port_t unauth_dir;
+
/*A copy (possibly extended) of the name of the translator*/
char * ext;
@@ -655,10 +734,62 @@ node_set_translator
char * argz = NULL;
size_t argz_len = 0;
+ /*The pointer to the name of the translator we are going to start now*/
+ char * str;
+
+ /*The index of the translator in the list of strings*/
+ size_t idx;
+
/*The control port for the active translator*/
mach_port_t active_control;
+
+ /*A new element in the list of control ports*/
+ port_el_t * p_el;
+
+ /*A copy of the user information, supplied in `user`*/
+ struct iouser * user;
+
+ /*A protid for the supplied node*/
+ struct protid * newpi;
- /*Opens a port to the file at the request of fshelp_start_translator*/
+ /*Identity information about the current process (for fsys_getroot)*/
+ uid_t * uids;
+ size_t nuids;
+
+ gid_t * gids;
+ size_t ngids;
+
+ /*The retry information returned by fsys_getroot*/
+ string_t retry_name;
+ mach_port_t retry_port;
+
+ /*Try to get the number of effective UIDs*/
+ nuids = geteuids(0, 0);
+ if(nuids < 0)
+ return EPERM;
+
+ /*Allocate some memory for the UIDs on the stack*/
+ uids = alloca(nuids * sizeof(uid_t));
+
+ /*Fetch the UIDs themselves*/
+ nuids = geteuids(nuids, uids);
+ if(nuids < 0)
+ return EPERM;
+
+ /*Try to get the number of effective GIDs*/
+ ngids = getgroups(0, 0);
+ if(ngids < 0)
+ return EPERM;
+
+ /*Allocate some memory for the GIDs on the stack*/
+ gids = alloca(ngids * sizeof(gid_t));
+
+ /*Fetch the GIDs themselves*/
+ ngids = getgroups(ngids, gids);
+ if(ngids < 0)
+ return EPERM;
+
+ /*Opens the port on which to set the new translator*/
error_t
open_port
(
@@ -666,21 +797,58 @@ node_set_translator
mach_port_t * underlying,
mach_msg_type_name_t * underlying_type,
task_t task,
- void * cookie /*some additional information, not used here*/
+ void * cookie /*if 0, open the port to the node; otherwise get the port
+ of the topmost translator on the node*/
)
{
- /*Lookup the file we are working with*/
- p = file_name_lookup_under
- (dir->nn->port, node->nn->lnode->name, flags, 0);
- if(p == MACH_PORT_NULL)
- return errno;
+ /*No errors at first*/
+ err = 0;
+
+ /*If a port to the node is wanted*/
+ if((int)cookie == 0)
+ {
+ /*check, whether the user has the permissions to open this node*/
+ err = check_open_permissions(diruser->user, &np->nn_stat, flags);
+ if(err)
+ return err;
+
+ /*duplicate the supplied user*/
+ err = iohelp_dup_iouser(&user, diruser->user);
+ if(err)
+ return err;
+
+ /*create a protid for this node*/
+ newpi = netfs_make_protid
+ (netfs_make_peropen(np, flags, diruser->po), user);
+ if(!newpi)
+ {
+ iohelp_free_iouser(user);
+ return errno;
+ }
+ LOG_MSG("node_set_translators.open_port: PASSED");
+
+ /*obtain the resulting port right and set its type appropriately*/
+ *underlying = p = ports_get_send_right(newpi);
+ *underlying_type = MACH_MSG_TYPE_COPY_SEND;
- /*Store the result in the parameters*/
- *underlying = p;
- *underlying_type = MACH_MSG_TYPE_COPY_SEND;
-
- /*Here everything is OK*/
- return 0;
+ LOG_MSG("node_set_translators.open_port: %ld", (long)*underlying);
+
+ /*drop our reference to the port*/
+ ports_port_deref(newpi);
+ }
+ /*We are not setting the first translator, this one is not required
+ to sit on the node itself*/
+ else
+ /*in the previous iteration of the loop fsys_getroot gave us the port
+ to the toplevel translator on the current node, namely `p`; this is
+ what is required of us now*/
+ {
+ *underlying = p;
+ *underlying_type = MACH_MSG_TYPE_COPY_SEND;
+ }
+
+ /*Return the result of operations (everything should be okay here)*/
+ return err;
}/*open_port*/
/*Adds a "/hurd/" at the beginning of the translator name, if required*/
@@ -715,47 +883,83 @@ node_set_translator
return full;
}/*put_in_hurd*/
- /*Obtain a copy (possibly extended) of the name*/
- ext = put_in_hurd(trans);
- if(!ext)
- return ENOMEM;
-
- /*TODO: Better argument-parsing?*/
-
- /*Obtain the argz version of str*/
- err = argz_create_sep(ext, ' ', &argz, &argz_len);
+ /*Obtain the unauthenticated port to the directory*/
+ err = io_restrict_auth(diruser->po->np->nn->port, &unauth_dir, 0, 0, 0, 0);
if(err)
return err;
+
+ /*While all translators have not been looked through*/
+ for(str = trans, idx = 0; idx < ntrans; ++idx)
+ {
+ /*obtain a copy (possibly extended) of the name*/
+ ext = put_in_hurd(str);
+ if(!ext)
+ return ENOMEM;
- /*Start the translator*/
- err = fshelp_start_translator
- (
- open_port, NULL, argz, argz, argz_len,
- 60000,/*this is the default in settrans*/
- &active_control
- );
- if(err)
- return err;
+ /*TODO: Better argument-parsing?*/
- /*Attempt to set a translator on the port opened by the previous call*/
- err = file_set_translator
- (
- p, 0, FS_TRANS_SET, 0, argz, argz_len,
- active_control, MACH_MSG_TYPE_COPY_SEND
- );
- if(err)
- return err;
+ /*obtain the argz version of str*/
+ err = argz_create_sep(ext, ' ', &argz, &argz_len);
+ if(err)
+ return err;
- /*Deallocate the port we have just opened*/
- PORT_DEALLOC(p);
+ /*start the translator*/
+ err = fshelp_start_translator
+ (
+ open_port, (void *)((idx == 0) ? 0 : 1), argz, argz, argz_len,
+ 60000,/*this is the default in settrans*/
+ &active_control
+ );
+ if(err)
+ return err;
+
+ /*attempt to set a translator on the port opened by the previous call*/
+ err = file_set_translator
+ (
+ p, 0, FS_TRANS_SET, 0, argz, argz_len,
+ active_control, MACH_MSG_TYPE_COPY_SEND
+ );
+ /*close the port we have just opened*/
+ PORT_DEALLOC(p);
+
+ /*stop, if the attempt to set the translator failed*/
+ if(err)
+ return err;
+
+ /*allocate a new element for the current control port*/
+ p_el = malloc(sizeof(struct port_el));
+ if(!p_el)
+ return ENOMEM;
+
+ /*store the current control port in the new cell*/
+ p_el->p = active_control;
+
+ /*add the new control port to the list*/
+ p_el->next = np->nn->cntl_ports;
+ np->nn->cntl_ports = p_el;
+
+ /*obtain the port to the top of the newly-set translator*/
+ err = fsys_getroot
+ (
+ active_control, unauth_dir, MACH_MSG_TYPE_COPY_SEND,
+ uids, nuids, gids, ngids,
+ flags, &retry_port, retry_name, &p
+ );
+ if(err)
+ return err;
+ }
+
+ /*Return the port*/
+ *port = p;
/*Everything is OK here*/
return 0;
- }/*node_set_translator*/
+ }/*node_set_translators*/
/*----------------------------------------------------------------------------*/
/*Kill the topmost translator for this node*/
/*This function will normally be called from netfs_attempt_lookup, therefore
it's better that the caller should provide the parent node for `node`.*/
+/*This is the code for the wrong version of nsmux.*/
error_t
node_kill_translator
(
@@ -763,88 +967,159 @@ node_kill_translator
node_t * node
)
{
+ error_t err = 0;
+
/*Lookup the file*/
mach_port_t p =
- file_name_lookup_under(dir->nn->port, node->nn->lnode->name, O_NOTRANS, 0);
+ file_name_lookup_under
+ (dir->nn->port, node->nn->lnode->name, /*O_NOTRANS*/0, 0);
+ if(!p)
+ return errno;
/*Remove a translator from the node*/
- error_t err = file_set_translator
+/*This code was taken from the code of settrans and works only when there is
+ only one translator in the stack (not including the ext2fs, for example).
+ For this code to work the O_NOTRANS is required in the lookup.*/
+ /*error_t err = file_set_translator
(
p, FS_TRANS_SET, FS_TRANS_SET, 0, NULL, 0,
MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND
- );
+ );*/
+
+ /*Obtain the control port of the filesystem to which file `name` belongs*/
+ fsys_t fsys;
+ err = file_getcontrol(p, &fsys);
+
+ char * argz = NULL;
+ size_t argz_len = 0;
+ err = file_get_fs_options(p, &argz, &argz_len);
/*Close the port*/
PORT_DEALLOC(p);
+ /*If the control port of the filesystem could not be fetched, stop*/
+ if(err)
+ return err;
+
+ /*Ask the translator to go away*/
+ err = fsys_goaway(fsys, 0);
+
+ /*If the translator is busy*/
+ if(err)
+ /*force the translator to go away*/
+ err = fsys_goaway(fsys, FSYS_GOAWAY_FORCE);
+
+ /*Deallocate the control port*/
+ PORT_DEALLOC(fsys);
+
/*Return the result of removing the translator*/
return err;
}/*node_kill_translator*/
/*----------------------------------------------------------------------------*/
/*Kills all translators on the nodes belonging to the given directory*/
void
-node_kill_all_translators
+node_kill_translators
(
node_t * node
)
{
- /*Goes through all children of the given node recursively*/
- void
- traverse_children_r
- (
- node_t * dir,
- node_t * np,
- size_t ntrans /*the number of translators to remove from all nodes*/
- )
- {
- int i;
+ /*If the node has no translators*/
+ if(node->nn->trans == NULL)
+ /*nothing to do*/
+ return;
- /*A child of the current node*/
- lnode_t * ln = np->nn->lnode;
-
- /*If the current node is not a directory*/
- if(!(ln->flags & FLAG_LNODE_DIR))
- {
- /*remove the required number of translators from the current node*/
- for(i = 0; i < ntrans + ln->ntrans; ++i)
- node_kill_translator(dir, np);
- }
- else
- /*Go through the list of entries belonging to this directory*/
- for(ln = ln->entries; ln; ln = ln->next)
- {
- /*die, if there is no node corresponding to the current child*/
- /*This is abnormal, because lnodes should normally go away shortly
- after the destruction of correpsonding nodes*/
- assert(ln->node);
-
- /*kill translators for this node*/
- traverse_children_r(np, ln->node, ntrans + ln->ntrans);
- }
-
- /*Obtain a pointer to the lnode corresponding to np*/
- ln = np->nn->lnode;
+ error_t err = 0;
+
+ /*The current element in the port list*/
+ port_el_t * p_el;
+
+ /*While the list of control ports is not empty*/
+ for(p_el = node->nn->cntl_ports; p_el; p_el = node->nn->cntl_ports)
+ {
+ /*kill the current translator*/
+ err = fsys_goaway(p_el->p, 0);
- /*Destroy the list of translators*/
- if(ln->trans)
- free(ln->trans);
+ /*If the translator says it is busy, force it to go away*/
+ if(err == EBUSY)
+ err = fsys_goaway(p_el->p, FSYS_GOAWAY_FORCE);
- /*No more translators on this node*/
- ln->trans = NULL;
- ln->ntrans = ln->translen = 0;
+ /*move the beginning of the list of control ports forward*/
+ node->nn->cntl_ports = p_el->next;
- /*There are no translators on this node*/
- ln->flags &= ~FLAG_LNODE_TRANSLATED;
- }/*traverse_children_r*/
-
- /*Obtain the pointer to the parent node of the current node*/
- node_t * dnp;
- ncache_node_lookup(node->nn->lnode->dir, &dnp);
+ /*destroy the current cell in the list of ports*/
+ free(p_el);
+ }
+ }/*node_kill_translators*/
+/*----------------------------------------------------------------------------*/
+/*Constructs a list of translators that were set on the ancestors of `node`*/
+/*TODO: Remove node_list_translators.*/
+error_t
+node_list_translators
+ (
+ node_t * node,
+ char ** trans, /*the malloced list of 0-separated strings*/
+ size_t * ntrans /*the number of elements in `trans`*/
+ )
+ {
+ /*The size of block of memory for the list of translators*/
+ size_t sz = 0;
+
+ /*Used for tracing the lineage of `node`*/
+ lnode_t * ln = node->nn->lnode;
+
+ /*Used in computing the lengths of lists of translators in every node
+ we will go through and for constructing the final list of translators*/
+ char * p;
- /*Kill all translators on the current node*/
- traverse_children_r(dnp, node, node->nn->lnode->ntrans);
+ /*The current position in *data (used in filling out the list of
+ translators)*/
+ char * transp;
+
+ /*The length of the current translator name*/
+ size_t complen;
+
+ size_t i;
+
+ /*Trace the lineage of the `node` (including itself) and compute the
+ total length of the list of translators*/
+ for(; ln; sz += node->nn->translen, ln = ln->dir);
+
+ /*Try to allocate a block of memory sufficient for storing the list of
+ translators*/
+ *trans = malloc(sz);
+ if(!*trans)
+ return ENOMEM;
- /*Unlock the parent node*/
- mutex_unlock(&dnp->lock);
- }/*node_kill_all_translators*/
+ /*No translators at first*/
+ *ntrans = 0;
+
+ /*Again trace the lineage of the `node` (including itself)*/
+ for(transp = *trans + sz, ln = node->nn->lnode; ln; ln = ln->dir)
+ {
+ /*Go through each translator name in the list of names*/
+ for
+ (
+ i = 0, p = node->nn->trans + node->nn->translen - 2;
+ i < node->nn->ntrans; ++i
+ )
+ {
+ /*position p at the beginning of the current component and
+ compute its length at the same time*/
+ for(complen = 0; *p; --p, ++complen);
+ --p;
+
+ /*move the current position backwards*/
+ transp -= complen + 1;
+
+ /*copy the current translator name into the list*/
+ strcpy(transp, p + 2);
+
+ /*we've got another translator*/
+ ++*ntrans;
+ }
+ }
+
+ /*Everything OK*/
+ return 0;
+ }/*lnode_list_translators*/
/*----------------------------------------------------------------------------*/
diff --git a/node.h b/node.h
index 72c244e8c..6cec6ddfe 100644
--- a/node.h
+++ b/node.h
@@ -5,7 +5,7 @@
/*----------------------------------------------------------------------------*/
/*Based on the code of unionfs translator.*/
/*----------------------------------------------------------------------------*/
-/*Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc.
+/*Copyright (C) 2001, 2002, 2005, 2008 Free Software Foundation, Inc.
Written by Sergiu Ivanov <unlimitedscolobb@gmail.com>.
This program is free software; you can redistribute it and/or
@@ -51,24 +51,47 @@
# define OFFSET_T __off_t
#endif /*__USE_FILE_OFFSET64*/
/*----------------------------------------------------------------------------*/
-/*The size of a chunk of a string (for a small optimization in checking
- the property)*/
-#define STRING_CHUNK 256
-/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
+/*--------Types---------------------------------------------------------------*/
+/*A list element containing a port*/
+struct port_el
+ {
+ /*the port*/
+ mach_port_t p;
+
+ /*the next element in the list*/
+ struct port_el * next;
+ };/*struct port_el*/
+/*----------------------------------------------------------------------------*/
+typedef struct port_el port_el_t;
+/*----------------------------------------------------------------------------*/
/*The user-defined node for libnetfs*/
struct netnode
{
/*the reference to the corresponding light node*/
lnode_t * lnode;
- /*the flags associated with this node (might be not required)*/
+ /*the flags associated with this node*/
int flags;
/*a port to the underlying filesystem*/
file_t port;
+ /*the malloced set of translators which have to be stacked upon this node
+ and upon its children; the corresponding translators will have to decide
+ on their own whether to accept directories or not*/
+ char * trans;
+
+ /*the number of translators listed in `translators`*/
+ size_t ntrans;
+
+ /*the length of the list of translators (in bytes)*/
+ size_t translen;
+
+ /*the list of control ports to the translators being set on this node*/
+ port_el_t * cntl_ports;
+
/*the neighbouring entries in the cache*/
node_t * ncache_prev, * ncache_next;
};/*struct netnode*/
@@ -104,6 +127,14 @@ node_create
node_t ** node /*store the result here*/
);
/*----------------------------------------------------------------------------*/
+/*Derives a new proxy from `lnode`*/
+error_t
+node_create_proxy
+ (
+ lnode_t * lnode,
+ node_t ** node /*store the result here*/
+ );
+/*----------------------------------------------------------------------------*/
/*Destroys the specified node and removes a light reference from the
associated light node*/
void
@@ -165,15 +196,17 @@ node_unlink_file
char * name
);
/*----------------------------------------------------------------------------*/
-/*Sets the given translator on the supplied node*/
-/*This function will normally be called from netfs_attempt_lookup, therefore
- it's better that the caller should provide the parent node for `node`.*/
+/*Sets the given translators on the specified node and returns the port to
+ the topmost one opened as `flags` require*/
error_t
-node_set_translator
+node_set_translators
(
- node_t * dir,
- node_t * node,
- const char * trans /*set this on `name`*/
+ struct protid * diruser,
+ node_t * np,
+ char * trans, /*set these on `node`*/
+ size_t ntrans,
+ int flags,
+ mach_port_t * port
);
/*----------------------------------------------------------------------------*/
/*Kill the topmost translator for this node*/
@@ -189,9 +222,19 @@ node_kill_translator
/*Kills all translators on the current node or on all underlying nodes it the
current node is a directory*/
void
-node_kill_all_translators
+node_kill_translators
(
node_t * node
);
/*----------------------------------------------------------------------------*/
+/*Constructs a list of translators that were set on the ancestors of `node`*/
+/*TODO: Remove node_list_translators.*/
+error_t
+node_list_translators
+ (
+ node_t * node,
+ char ** trans, /*the malloced list of 0-separated strings*/
+ size_t * ntrans /*the number of elements in `trans`*/
+ );
+/*----------------------------------------------------------------------------*/
#endif /*__NODE_H__*/
diff --git a/nsmux.c b/nsmux.c
index d512d7722..2ee209740 100644
--- a/nsmux.c
+++ b/nsmux.c
@@ -5,7 +5,7 @@
/*----------------------------------------------------------------------------*/
/*Based on the code of unionfs translator.*/
/*----------------------------------------------------------------------------*/
-/*Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc.
+/*Copyright (C) 2001, 2002, 2005, 2008 Free Software Foundation, Inc.
Written by Sergiu Ivanov <unlimitedscolobb@gmail.com>.
This program is free software; you can redistribute it and/or
@@ -33,6 +33,7 @@
#include <argp.h>
#include <hurd/netfs.h>
#include <fcntl.h>
+#include <hurd/paths.h>
/*----------------------------------------------------------------------------*/
#include "debug.h"
#include "options.h"
@@ -99,18 +100,8 @@ netfs_check_open_permissions
{
LOG_MSG("netfs_check_open_permissions: '%s'", np->nn->lnode->name);
- error_t err = 0;
-
- /*Cheks user's permissions*/
- if(flags & O_READ)
- err = fshelp_access(&np->nn_stat, S_IREAD, user);
- if(!err && (flags & O_WRITE))
- err = fshelp_access(&np->nn_stat, S_IWRITE, user);
- if(!err && (flags & O_EXEC))
- err = fshelp_access(&np->nn_stat, S_IEXEC, user);
-
- /*Return the result of the check*/
- return err;
+ /*Cheks user's permissions and return the result*/
+ return check_open_permissions(user, &np->nn_stat, flags);
}/*netfs_check_open_permissions*/
/*----------------------------------------------------------------------------*/
/*Attempts an utimes call for the user `cred` on node `node`*/
@@ -194,7 +185,7 @@ netfs_validate_stat
struct iouser * cred
)
{
- LOG_MSG("netfs_validate_stat: '%s'", np->nn->lnode->name);
+ LOG_MSG("netfs_validate_stat: '%s'", (np ? np->nn->lnode->name : ""));
error_t err = 0;
@@ -220,6 +211,9 @@ netfs_validate_stat
/*attempt to stat this file*/
err = io_stat(np->nn->port, &np->nn_stat);
+ if(S_ISDIR(np->nn_stat.st_mode))
+ LOG_MSG("\tIs a directory");
+
/*If stat information has been successfully obtained for the file*/
if(!err)
/*duplicate the st_mode field of stat structure*/
@@ -509,14 +503,53 @@ netfs_attempt_lookup
struct node ** node
)
{
- LOG_MSG("netfs_attempt_lookup: '%s'", name);
+ LOG_MSG("netfs_attempt_lookup");
- error_t err = 0;
- int i = 0;
+ /*We should never get here. In any case, we do not want to do this type
+ of lookup, netfs_attempt_lookup_improved is what we want*/
+ return EOPNOTSUPP;
+ }/*netfs_attempt_lookup*/
+/*----------------------------------------------------------------------------*/
+/*Performs an advanced lookup of file `name` under `dir`. If the lookup of the
+ last component of the path is requested (`lastcomp` is 1), it is not a
+ directory and no translators are required (`name` does not contain ',,'), the
+ function will simply open the required file and return the port in `file`. In
+ other cases it will create a proxy node and return it in `node`.*/
+error_t
+netfs_attempt_lookup_improved
+ (
+ struct iouser * user,
+ struct node * dir,
+ char * name,
+ int flags,
+ int lastcomp,
+ node_t ** node,
+ file_t * file
+ )
+ {
+ LOG_MSG("netfs_attempt_lookup_improved: '%s'", name);
+ error_t err = 0;
+
/*If we are asked to fetch the current directory*/
if(strcmp(name, ".") == 0)
{
+ /*validate the stat information for `dir`*/
+ err = netfs_validate_stat(dir, user);
+ if(err)
+ {
+ mutex_unlock(&dir->lock);
+ return err;
+ }
+
+ /*If `dir` is not a directory, actually*/
+ if(!S_ISDIR(dir->nn_stat.st_mode))
+ {
+ /*unlock the directory and stop right here*/
+ mutex_unlock(&dir->lock);
+ return ENOTDIR;
+ }
+
/*add a reference to `dir` and put it into `node`*/
netfs_nref(dir);
*node = dir;
@@ -527,6 +560,22 @@ netfs_attempt_lookup
/*If we are asked to fetch the parent directory*/
else if(strcmp(name, "..") == 0)
{
+ /*validate the stat information for `dir`*/
+ err = netfs_validate_stat(dir, user);
+ if(err)
+ {
+ mutex_unlock(&dir->lock);
+ return err;
+ }
+
+ /*If `dir` is not a directory, actually*/
+ if(!S_ISDIR(dir->nn_stat.st_mode))
+ {
+ /*unlock the directory and stop right here*/
+ mutex_unlock(&dir->lock);
+ return ENOTDIR;
+ }
+
/*If the supplied node is not root*/
if(dir->nn->lnode->dir)
{
@@ -612,7 +661,9 @@ netfs_attempt_lookup
error_t
lookup
(
- char * name /*lookup this*/
+ char * name, /*lookup this*/
+ int flags, /*lookup `name` in the this way*/
+ int proxy /*should a proxy node be created*/
)
{
/*Try to lookup the given file in the underlying directory*/
@@ -620,13 +671,8 @@ netfs_attempt_lookup
/*If the lookup failed*/
if(p == MACH_PORT_NULL)
- {
- /*unlock the directory*/
- mutex_unlock(&dir->lock);
-
/*no such entry*/
return ENOENT;
- }
/*Obtain the stat information about the file*/
io_statbuf_t stat;
@@ -638,20 +684,25 @@ netfs_attempt_lookup
/*If this file is not a directory*/
if(err || !S_ISDIR(stat.st_mode))
{
- /*do not set the port*/
- p = MACH_PORT_NULL;
+ /*lookup the required file with the supplied flags*/
+ p = file_name_lookup_under(dir->nn->port, name, flags, 0);
+ if(p == MACH_PORT_NULL)
+ return EBADF;
/*remember we do not have a directory*/
isdir = 0;
+
+ /*If a proxy node is not required*/
+ if(!proxy)
+ /*stop here, we want only the port to the file*/
+ return 0;
}
else
{
/*lookup the port with the right to read the contents of the directory*/
p = file_name_lookup_under(dir->nn->port, name, O_READ | O_DIRECTORY, 0);
if(p == MACH_PORT_NULL)
- {
return EBADF; /*not enough rights?*/
- }
/*we have a directory here*/
isdir = 1;
@@ -675,16 +726,25 @@ netfs_attempt_lookup
lnode_install(dir->nn->lnode, lnode);
}
- /*Obtain the node corresponding to this lnode*/
- err = ncache_node_lookup(lnode, node);
+ /*If we are to create a proxy node*/
+ if(proxy)
+ /*create a proxy node from the given lnode*/
+ err = node_create_proxy(lnode, node);
+ /*If we don't need proxy nodes in this lookup*/
+ else
+ {
+ /*obtain the node corresponding to this lnode*/
+ err = ncache_node_lookup(lnode, node);
+
+ /*remove an extra reference from the lnode*/
+ lnode_ref_remove(lnode);
+ }
- /*Remove an extra reference from the lnode*/
- lnode_ref_remove(lnode);
-
- /*If the lookup in the cache failed*/
+ /*If either the lookup in the cache or the creation of a proxy failed*/
if(err)
{
/*stop*/
+ mutex_unlock(&lnode->lock);
finalize();
return err;
}
@@ -702,10 +762,14 @@ netfs_attempt_lookup
err = lnode_path_construct(lnode, NULL);
if(err)
{
+ mutex_unlock(&lnode->lock);
finalize();
return err;
}
+ /*Unlock the lnode*/
+ mutex_unlock(&lnode->lock);
+
/*Now the node is up-to-date*/
(*node)->nn->flags = FLAG_NODE_ULFS_UPTODATE;
@@ -736,12 +800,15 @@ netfs_attempt_lookup
++sep;
}
- /*If the control sequence has been found present*/
+ /*If the control sequence has been found*/
if(sep)
{
+ /*the name of the file to lookup*/
+ char * name_cpy;
+
/*copy the name*/
/*just copy the pointer*/
- char * name_cpy = /*strdup*/(name);
+ name_cpy = /*strdup*/(name);
if(!name_cpy)
{
err = ENOMEM;
@@ -756,12 +823,16 @@ netfs_attempt_lookup
*(sep++) = 0;
*(sep++) = 0;
- /*try to lookup a node with the specified name*/
- err = lookup(name_cpy);
+ /*try to lookup the file with the specified name and create a proxy
+ node for it (since we need to start translators)*/
+ err = lookup(name_cpy, flags, 1);
+
+ /*If the lookup failed*/
if(err)
{
+ /*say that the file has not been found*/
finalize();
- return err;
+ return ENOENT;
}
/*duplicate the part of the name containing the list of translators
@@ -816,263 +887,500 @@ netfs_attempt_lookup
which does not end in a comma and the corresponding terminal 0*/
++ntrans;
++translen;
-
- /*If there are no translators set upon the current node*/
- if(!lnode->trans)
- {
- /*copy the list of translators we have just built in the lnode*/
- lnode->trans = trans;
- lnode->ntrans = ntrans;
- lnode->translen = translen;
-
- /*If the node has already been fully translated before and it's
- not a directory*/
- /*We don't need to set the whole collection of translators,
- both inherited and the ones in lnode->trans. The latter
- are only necessary. Directories, on the other hand, cannot
- bear translators on them.*/
- if
- (
- (lnode->flags & FLAG_LNODE_TRANSLATED)
- && !(lnode->flags & FLAG_LNODE_DIR)
- )
- {
- /*Go through the list of translators*/
- for(str = trans, i = 0; i < ntrans; ++i)
- {
- /*set the translator specified in the current component*/
- err = node_set_translator(dir, *node, str);
- if(err)
- {
- finalize();
- return 0; /*TODO: A better way to fight errors here*/
- }
-
- /*skip the current component*/
- str += strlen(str) + 1;
- }
- /*we don't own the list of translators any more*/
- trans = NULL;
- ntrans = 0;
- translen = 0;
-
- /*here the lookup is successful*/
- err = 0;
- finalize();
- return err;
- }
-
- /*we don't own the list of translators any more*/
- trans = NULL;
- ntrans = 0;
- translen = 0;
- }
- else
- {
- /*If the current node is not a directory*/
- if(!isdir)
- {
- /*obtain the minimal of the lengths of the lists of translators*/
- size_t minlen =
- (translen < lnode->translen) ? (translen) : (lnode->translen);
-
- /*the number of similar translators*/
- size_t similar = 0;
-
- /*the current position in the list*/
- size_t i;
-
- /*Go through the lists of translators*/
- for(i = 0; i < minlen; ++i)
- {
- /*If the current characters are different, stop here*/
- if(trans[i] != lnode->trans[i])
- break;
-
- /*If the current character marks the end of a translator name*/
- if(trans[i] == 0)
- /*one more matching translator*/
- ++similar;
- }
-
- /*While all not matching translators have not been removed*/
- size_t j;
- for(j = 0; j < lnode->ntrans - similar; ++j)
- {
- /*remove one more translator*/
- err = node_kill_translator(dir, *node);
- if(err)
- {
- finalize();
- return err;
- }
- }
-
- /*obtain the pointer to the first not matching position*/
- str = trans + i;
-
- /*seek to the beginning of the current translator name*/
- for(; (str > trans) && *str; --str);
-
- /*While the required new translators have not been set*/
- for(i = 0; i < ntrans - similar; ++i)
- {
- /*set the current translator on the file*/
- err = node_set_translator(dir, *node, str);
- if(err)
- {
- finalize();
- return err;
- }
-
- /*skip the current translator*/
- str += strlen(str) + 1;
- }
- }
- /*We have looked up a directory*/
- else
- {
- /*If the length of the lists of translators are the same*/
- if((lnode->translen = translen) && (lnode->ntrans == ntrans))
- {
- /*check each character of the list of translators*/
- int i;
- for(i = 0; (i < translen) && (lnode->trans[i] == trans[i]); ++i);
-
- /*If the lists coincide*/
- if(i == translen)
- {
- /*the lookup has finished successfully here*/
- err = 0;
- finalize();
- return err;
- }
- }
-
- /*unlock the directory in which we are at the moment*/
- mutex_unlock(&dir->lock);
-
- /*kill all translators on all children of this node*/
- node_kill_all_translators(*node);
-
- /*lock the directory back*/
- mutex_lock(&dir->lock);
- }
-
- /*destroy the list of translators in the current node*/
- free(lnode->trans);
-
- /*put the new list in the node*/
- lnode->trans = trans;
- lnode->ntrans = ntrans;
- lnode->translen = translen;
-
- /*all required translators have been already applied on this node*/
- /*lnode->flags |= FLAG_LNODE_TRANSLATED;*/
-
- /*we don't own the list of translators any more*/
- trans = NULL;
-
- /*the lookup is already finished here*/
- err = 0;
- finalize();
- return err;
- }
+ /*copy the list of translators we have just built in the new proxy node*/
+ (*node)->nn->trans = trans;
+ (*node)->nn->ntrans = ntrans;
+ (*node)->nn->translen = translen;
+
+ /*we don't own the list of translators any more*/
+ trans = NULL;
+ ntrans = 0;
+ translen = 0;
}
/*The control sequence ',,' has not been found*/
else
{
- /*simply lookup the provided name*/
- err = lookup(name);
+ /*simply lookup the provided name, without creating the proxy, if not
+ necessary (i.e. when the file is not a directory)*/
+ err = lookup(name, flags, 0);
if(err)
{
finalize();
return err;
}
-
- /*If there are some translators set on this file*/
- if(lnode->trans)
- {
- /*unlock the directory*/
- mutex_unlock(&dir->lock);
-
- /*kill all translators on this node*/
- node_kill_all_translators(*node);
- /*lock the directory again*/
- mutex_lock(&dir->lock);
-
- /*all translators have been succesfully set here*/
- /*lnode->flags |= FLAG_LNODE_TRANSLATED;*/
-
- /*the lookup has finished successfully here*/
- /*The translators inherited from parents survive throughout
- the previous loop*/
- err = 0;
- finalize();
- return err;
- }
+ /*if we have looked up a regular file, store the port to it in *`file`*/
+ if(!isdir)
+ *file = p;
}
- /*If we have a directory*/
- if(isdir)
+ /*Everything OK here*/
+ finalize();
+ return err;
+ }/*netfs_attempt_lookup_improved*/
+/*----------------------------------------------------------------------------*/
+/*Responds to the RPC dir_lookup*/
+error_t
+netfs_S_dir_lookup
+ (
+ struct protid * diruser,
+ char * filename,
+ int flags,
+ mode_t mode,
+ retry_type * do_retry,
+ char * retry_name,
+ mach_port_t * retry_port,
+ mach_msg_type_number_t * retry_port_type
+ )
+ {
+ LOG_MSG("netfs_S_dir_lookup: '%s'", filename);
+
+ int create; /* true if O_CREAT flag set */
+ int excl; /* true if O_EXCL flag set */
+ int mustbedir = 0; /* true if the result must be S_IFDIR */
+ int lastcomp = 0; /* true if we are at the last component */
+ int newnode = 0; /* true if this node is newly created */
+ int nsymlinks = 0;
+ struct node *dnp, *np;
+ char *nextname;
+ error_t error;
+ struct protid *newpi;
+ struct iouser *user;
+
+ /*The port to the file for the case when we don't need proxy nodes*/
+ file_t file = MACH_PORT_NULL;
+
+ /*The port to the same file with restricted rights*/
+ file_t file_restricted = MACH_PORT_NULL;
+
+ /*The stat information about the node pointed at by `file` (for the case
+ when not proxy nodes are to be created)*/
+ io_statbuf_t stat;
+
+ if (!diruser)
+ return EOPNOTSUPP;
+
+ create = (flags & O_CREAT);
+ excl = (flags & O_EXCL);
+
+ /* Skip leading slashes */
+ while (*filename == '/')
+ filename++;
+
+ *retry_port_type = MACH_MSG_TYPE_MAKE_SEND;
+ *do_retry = FS_RETRY_NORMAL;
+ *retry_name = '\0';
+
+ if (*filename == '\0')
+ {
+ /* Set things up in the state expected by the code from gotit: on. */
+ dnp = 0;
+ np = diruser->po->np;
+ mutex_lock (&np->lock);
+ netfs_nref (np);
+ goto gotit;
+ }
+
+ dnp = diruser->po->np;
+ mutex_lock (&dnp->lock);
+
+ netfs_nref (dnp); /* acquire a reference for later netfs_nput */
+
+ do
+ {
+ assert (!lastcomp);
+
+ /* Find the name of the next pathname component */
+ nextname = index (filename, '/');
+
+ if (nextname)
+ {
+ *nextname++ = '\0';
+ while (*nextname == '/')
+ nextname++;
+ if (*nextname == '\0')
+ {
+ /* These are the rules for filenames ending in /. */
+ nextname = 0;
+ lastcomp = 1;
+ mustbedir = 1;
+ create = 0;
+ }
+ else
+ lastcomp = 0;
+ }
+ else
+ lastcomp = 1;
+
+ np = 0;
+
+ retry_lookup:
+
+ if ((dnp == netfs_root_node || dnp == diruser->po->shadow_root)
+ && filename[0] == '.' && filename[1] == '.' && filename[2] == '\0')
+ if (dnp == diruser->po->shadow_root)
+ /* We're at the root of a shadow tree. */
+ {
+ *do_retry = FS_RETRY_REAUTH;
+ *retry_port = diruser->po->shadow_root_parent;
+ *retry_port_type = MACH_MSG_TYPE_COPY_SEND;
+ if (! lastcomp)
+ strcpy (retry_name, nextname);
+ error = 0;
+ mutex_unlock (&dnp->lock);
+ goto out;
+ }
+ else if (diruser->po->root_parent != MACH_PORT_NULL)
+ /* We're at a real translator root; even if DIRUSER->po has a
+ shadow root, we can get here if its in a directory that was
+ renamed out from under it... */
+ {
+ *do_retry = FS_RETRY_REAUTH;
+ *retry_port = diruser->po->root_parent;
+ *retry_port_type = MACH_MSG_TYPE_COPY_SEND;
+ if (!lastcomp)
+ strcpy (retry_name, nextname);
+ error = 0;
+ mutex_unlock (&dnp->lock);
+ goto out;
+ }
+ else
+ /* We are global root */
+ {
+ error = 0;
+ np = dnp;
+ netfs_nref (np);
+ }
+ else
{
- /*FIXME: It means we've got a directory, and no translators are set on
- directories. The point is that nsmux should mainly handle libtrivs-based
- translators, which should not operate on directories.*/
- err = 0;
- finalize();
- return err;
- }
+ /* Attempt a lookup on the next pathname component. */
+ /*error = netfs_attempt_lookup (diruser->user, dnp, filename, &np);*/
+
+ /*attempt an improved lookup on the next pathname component*/
+ error = netfs_attempt_lookup_improved
+ (diruser->user, dnp, filename, flags, lastcomp, &np, &file);
- /*If the current node has already been successfully translated*/
- if(lnode->flags & FLAG_LNODE_TRANSLATED)
+ /*If no problems have occurred during the lookup and we do not have O_EXCL*/
+ if(!error && !excl)
{
- /*no additional translators must set on this file*/
- err = 0;
- finalize();
- return err;
+ /*If a simple file has been looked up*/
+ if(file)
+ /*just return the port*/
+ goto justport;
+
+ /*If a proxy for setting up translators has just been created*/
+ if(np->nn->trans)
+ {
+ /*set the list of translators on this node*/
+ node_set_translators
+ (diruser, np, np->nn->trans, np->nn->ntrans, flags, &file);
+
+ /*lock the the node and add a new reference*/
+ mutex_lock(&np->lock);
+ netfs_nref(np);
+
+ /*return `file` as the resulting port*/
+ goto justport;
+ }
+ }
}
- /*Obtain the list of inherited translators*/
- err = lnode_list_translators(lnode, &trans, &ntrans);
- if(err)
- {
- finalize();
+ /* At this point, DNP is unlocked */
+
+ /* Implement O_EXCL flag here */
+ if (lastcomp && create && excl && !error)
+ error = EEXIST;
+
+ /* Create the new node if necessary */
+ if (lastcomp && create && error == ENOENT)
+ {
+ mode &= ~(S_IFMT | S_ISPARE | S_ISVTX);
+ mode |= S_IFREG;
+ mutex_lock (&dnp->lock);
+ error = netfs_attempt_create_file (diruser->user, dnp,
+ filename, mode, &np);
+
+ /* If someone has already created the file (between our lookup
+ and this create) then we just got EEXIST. If we are
+ EXCL, that's fine; otherwise, we have to retry the lookup. */
+ if (error == EEXIST && !excl)
+ {
+ mutex_lock (&dnp->lock);
+ goto retry_lookup;
+ }
+
+ newnode = 1;
+ }
+
+ /* All remaining errors get returned to the user */
+ if (error)
+ goto out;
+
+ error = netfs_validate_stat (np, diruser->user);
+ if (error)
+ goto out;
+
+ if ((((flags & O_NOTRANS) == 0) || !lastcomp)
+ && ((np->nn_translated & S_IPTRANS)
+ || S_ISFIFO (np->nn_translated)
+ || S_ISCHR (np->nn_translated)
+ || S_ISBLK (np->nn_translated)
+ || fshelp_translated (&np->transbox)))
+ {
+ mach_port_t dirport;
+
+ /* A callback function for short-circuited translators.
+ S_ISLNK and S_IFSOCK are handled elsewhere. */
+ error_t short_circuited_callback1 (void *cookie1, void *cookie2,
+ uid_t *uid, gid_t *gid,
+ char **argz, size_t *argz_len)
+ {
+ struct node *np = cookie1;
+ error_t err;
+
+ err = netfs_validate_stat (np, diruser->user);
+ if (err)
return err;
- }
- /*If no translators have to be set*/
- if(ntrans == 0)
+ switch (np->nn_translated & S_IFMT)
{
- /*we have looked up what we need*/
- finalize();
- return 0;
+ case S_IFCHR:
+ case S_IFBLK:
+ if (asprintf (argz, "%s%c%d%c%d",
+ (S_ISCHR (np->nn_translated)
+ ? _HURD_CHRDEV : _HURD_BLKDEV),
+ 0, major (np->nn_stat.st_rdev),
+ 0, minor (np->nn_stat.st_rdev)) < 0)
+ return ENOMEM;
+ *argz_len = strlen (*argz) + 1;
+ *argz_len += strlen (*argz + *argz_len) + 1;
+ *argz_len += strlen (*argz + *argz_len) + 1;
+ break;
+ case S_IFIFO:
+ if (asprintf (argz, "%s", _HURD_FIFO) < 0)
+ return ENOMEM;
+ *argz_len = strlen (*argz) + 1;
+ break;
+ default:
+ return ENOENT;
}
- /*Go through the list of translators*/
- for(str = trans, i = 0; i < ntrans; ++i)
+ *uid = np->nn_stat.st_uid;
+ *gid = np->nn_stat.st_gid;
+
+ return 0;
+ }
+
+ /* Create an unauthenticated port for DNP, and then
+ unlock it. */
+ error = iohelp_create_empty_iouser (&user);
+ if (! error)
+ {
+ newpi = netfs_make_protid (netfs_make_peropen (dnp, 0,
+ diruser->po),
+ user);
+ if (! newpi)
+ {
+ error = errno;
+ iohelp_free_iouser (user);
+ }
+ }
+
+ if (! error)
+ {
+ dirport = ports_get_send_right (newpi);
+ ports_port_deref (newpi);
+
+ error = fshelp_fetch_root (&np->transbox, diruser->po,
+ dirport,
+ diruser->user,
+ lastcomp ? flags : 0,
+ ((np->nn_translated & S_IPTRANS)
+ ? _netfs_translator_callback1
+ : short_circuited_callback1),
+ _netfs_translator_callback2,
+ do_retry, retry_name, retry_port);
+ /* fetch_root copies DIRPORT for success, so we always should
+ deallocate our send right. */
+ mach_port_deallocate (mach_task_self (), dirport);
+ }
+
+ if (error != ENOENT)
+ {
+ netfs_nrele (dnp);
+ netfs_nput (np);
+ *retry_port_type = MACH_MSG_TYPE_MOVE_SEND;
+ if (!lastcomp && !error)
{
- /*set the translator specified in the current component*/
- err = node_set_translator(dir, *node, str);
- if(err)
+ strcat (retry_name, "/");
+ strcat (retry_name, nextname);
+ }
+ return error;
+ }
+
+ /* ENOENT means there was a hiccup, and the translator vanished
+ while NP was unlocked inside fshelp_fetch_root; continue as normal. */
+ error = 0;
+ }
+
+ if (S_ISLNK (np->nn_translated)
+ && (!lastcomp
+ || mustbedir /* "foo/" must see that foo points to a dir */
+ || !(flags & (O_NOLINK|O_NOTRANS))))
+ {
+ size_t nextnamelen, newnamelen, linklen;
+ char *linkbuf;
+
+ /* Handle symlink interpretation */
+ if (nsymlinks++ > netfs_maxsymlinks)
+ {
+ error = ELOOP;
+ goto out;
+ }
+
+ linklen = np->nn_stat.st_size;
+
+ nextnamelen = nextname ? strlen (nextname) + 1 : 0;
+ newnamelen = nextnamelen + linklen + 1;
+ linkbuf = alloca (newnamelen);
+
+ error = netfs_attempt_readlink (diruser->user, np, linkbuf);
+ if (error)
+ goto out;
+
+ if (nextname)
+ {
+ linkbuf[linklen] = '/';
+ memcpy (linkbuf + linklen + 1, nextname,
+ nextnamelen - 1);
+ }
+ linkbuf[nextnamelen + linklen] = '\0';
+
+ if (linkbuf[0] == '/')
+ {
+ /* Punt to the caller */
+ *do_retry = FS_RETRY_MAGICAL;
+ *retry_port = MACH_PORT_NULL;
+ strcpy (retry_name, linkbuf);
+ goto out;
+ }
+
+ filename = linkbuf;
+ if (lastcomp)
+ {
+ lastcomp = 0;
+
+ /* Symlinks to nonexistent files aren't allowed to cause
+ creation, so clear the flag here. */
+ create = 0;
+ }
+ netfs_nput (np);
+ mutex_lock (&dnp->lock);
+ np = 0;
+ }
+ else
+ {
+ /* Normal nodes here for next filename component */
+ filename = nextname;
+ netfs_nrele (dnp);
+
+ if (lastcomp)
+ dnp = 0;
+ else
+ {
+ dnp = np;
+ np = 0;
+ }
+ }
+ }
+ while (filename && *filename);
+
+ /* At this point, NP is the node to return. */
+ gotit:
+
+ if (mustbedir)
+ {
+ netfs_validate_stat (np, diruser->user);
+ if (!S_ISDIR (np->nn_stat.st_mode))
+ {
+ error = ENOTDIR;
+ goto out;
+ }
+ }
+ error = netfs_check_open_permissions (diruser->user, np,
+ flags, newnode);
+ if (error)
+ goto out;
+
+ flags &= ~OPENONLY_STATE_MODES;
+
+ error = iohelp_dup_iouser (&user, diruser->user);
+ if (error)
+ goto out;
+
+ newpi = netfs_make_protid (netfs_make_peropen (np, flags, diruser->po),
+ user);
+ if (! newpi)
+ {
+ iohelp_free_iouser (user);
+ error = errno;
+ goto out;
+ }
+
+ *retry_port = ports_get_right (newpi);
+ ports_port_deref (newpi);
+
+ goto out;
+
+ /*At this point, we have to return `file` as the resulting port*/
+ justport:
+ /*If a directory is definitely wanted*/
+ if(mustbedir)
+ {
+ /*stat the looked up file*/
+ error = io_stat(file, &stat);
+ if(error)
+ goto out;
+
+ /*If the file is not a directory*/
+ if(!S_ISDIR(stat.st_mode))
{
- finalize();
- return 0; /*TODO: A better way to fight errors here*/
+ /*this is an error; stop here*/
+ error = ENOTDIR;
+ goto out;
}
-
- /*skip the current component*/
- str += strlen(str) + 1;
- }
-
- /*All translators have been succesfully set on this node*/
- lnode->flags |= FLAG_LNODE_TRANSLATED;
-
- /*Everything OK here*/
- finalize();
- return err;
- }/*netfs_attempt_lookup*/
+
+ }
+
+ /*Check the user's open permissions for the specified port*/
+ error = check_open_permissions(diruser->user, &stat, file);
+ if(error)
+ goto out;
+
+ /*Restrict the port to the rights of the user*/
+ error = io_restrict_auth
+ (
+ file, &file_restricted,
+ diruser->user->uids->ids, diruser->user->uids->num,
+ diruser->user->gids->ids, diruser->user->gids->num
+ );
+ if(error)
+ goto out;
+
+ /*Put the resulting port in the corresponding receiver parameter*/
+ *retry_port = file_restricted;
+ *retry_port_type = MACH_MSG_TYPE_MOVE_SEND;
+
+ out:
+ if(error && (file != MACH_PORT_NULL))
+ PORT_DEALLOC(file);
+ if (np)
+ netfs_nput (np);
+ if (dnp)
+ netfs_nrele (dnp);
+ return error;
+ }/*netfs_S_dir_lookup*/
/*----------------------------------------------------------------------------*/
/*Deletes `name` in `dir` for `user`*/
error_t
@@ -1353,32 +1661,6 @@ netfs_attempt_read
error_t err = 0;
- /*If there is no port open for the current node*/
- if(np->nn->port == MACH_PORT_NULL)
- {
- /*the parent node of the current node*/
- node_t * dnp;
-
- /*obtain the parent node of the the current node*/
- err = ncache_node_lookup(np->nn->lnode->dir, &dnp);
-
- /*the lookup should never fail here*/
- assert(!err);
-
- /*open a port to the file we are interested in*/
- mach_port_t p = file_name_lookup_under
- (dnp->nn->port, np->nn->lnode->name, O_READ, 0);
-
- /*put `dnp` back, since we don't need it any more*/
- netfs_nput(dnp);
-
- if(!p)
- return EBADF;
-
- /*store the port in the node*/
- np->nn->port = p;
- }
-
/*Obtain a pointer to the first byte of the supplied buffer*/
char * buf = data;
@@ -1411,8 +1693,6 @@ netfs_attempt_write
void * data
)
{
- LOG_MSG("netfs_attempt_write");
-
return 0;
}/*netfs_attempt_write*/
/*----------------------------------------------------------------------------*/
@@ -1427,6 +1707,8 @@ netfs_node_norefs
node_destroy(np);
}/*netfs_node_norefs*/
/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
/*Entry point*/
int
main
diff --git a/nsmux.h b/nsmux.h
index ee469f2d5..a38874d68 100644
--- a/nsmux.h
+++ b/nsmux.h
@@ -5,7 +5,7 @@
/*----------------------------------------------------------------------------*/
/*Based on the code of unionfs translator.*/
/*----------------------------------------------------------------------------*/
-/*Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc.
+/*Copyright (C) 2001, 2002, 2005, 2008 Free Software Foundation, Inc.
Written by Sergiu Ivanov <unlimitedscolobb@gmail.com>.
This program is free software; you can redistribute it and/or
@@ -47,6 +47,12 @@
/*The inode number for the root node*/
#define NSMUX_ROOT_INODE 1
/*----------------------------------------------------------------------------*/
+/*The special flag character for creating proxy nodes*/
+#define LOOKUP_MAGIC_CHAR '\33'
+/*----------------------------------------------------------------------------*/
+/*Bits that are turned off after open*/
+#define OPENONLY_STATE_MODES (O_CREAT | O_EXCL | O_NOLINK | O_NOTRANS)
+/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*--------Global Variables----------------------------------------------------*/
@@ -60,6 +66,10 @@ extern mach_port_t underlying_node;
/*The stat information about the underlying node*/
extern io_statbuf_t underlying_node_stat;
/*----------------------------------------------------------------------------*/
+/*The translator callbacks required by netfs_S_dir_lookup*/
+fshelp_fetch_root_callback1_t _netfs_translator_callback1;
+fshelp_fetch_root_callback2_t _netfs_translator_callback2;
+/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*--------Functions-----------------------------------------------------------*/
@@ -145,6 +155,37 @@ netfs_attempt_lookup
struct node ** node
);
/*----------------------------------------------------------------------------*/
+/*Performs an advanced lookup of file `name` under `dir`. If the lookup of the
+ last component of the path is requested (`lastcomp` is 1), it is not a
+ directory and no translators are required (`name` does not contain ',,'), the
+ function will simply open the required file and return the port in `file`. In
+ other cases it will create a proxy node and return it in `node`.*/
+error_t
+netfs_attempt_lookup_improved
+ (
+ struct iouser * user,
+ struct node * dir,
+ char * name,
+ int flags,
+ int lastcomp,
+ node_t ** node,
+ file_t * file
+ );
+/*----------------------------------------------------------------------------*/
+/*Responds to the RPC dir_lookup*/
+error_t
+netfs_S_dir_lookup
+ (
+ struct protid * diruser,
+ char * filename,
+ int flags,
+ mode_t mode,
+ retry_type * do_retry,
+ char * retry_name,
+ mach_port_t * retry_port,
+ mach_msg_type_number_t * retry_port_type
+ );
+/*----------------------------------------------------------------------------*/
/*Deletes `name` in `dir` for `user`*/
error_t
netfs_attempt_unlink
diff --git a/options.c b/options.c
index c69cd2806..55a0ea5ad 100644
--- a/options.c
+++ b/options.c
@@ -5,7 +5,7 @@
/*----------------------------------------------------------------------------*/
/*Based on the code of unionfs translator.*/
/*----------------------------------------------------------------------------*/
-/*Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc.
+/*Copyright (C) 2001, 2002, 2005, 2008 Free Software Foundation, Inc.
Written by Sergiu Ivanov <unlimitedscolobb@gmail.com>.
This program is free software; you can redistribute it and/or
diff --git a/options.h b/options.h
index 60f757204..cbedb3db6 100644
--- a/options.h
+++ b/options.h
@@ -5,7 +5,7 @@
/*----------------------------------------------------------------------------*/
/*Based on the code of unionfs translator.*/
/*----------------------------------------------------------------------------*/
-/*Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc.
+/*Copyright (C) 2001, 2002, 2005, 2008 Free Software Foundation, Inc.
Written by Sergiu Ivanov <unlimitedscolobb@gmail.com>.
This program is free software; you can redistribute it and/or