summaryrefslogtreecommitdiff
path: root/nsmux.c
diff options
context:
space:
mode:
Diffstat (limited to 'nsmux.c')
-rw-r--r--nsmux.c465
1 files changed, 277 insertions, 188 deletions
diff --git a/nsmux.c b/nsmux.c
index d7f89002c..d512d7722 100644
--- a/nsmux.c
+++ b/nsmux.c
@@ -31,7 +31,6 @@
/*----------------------------------------------------------------------------*/
#include <error.h>
#include <argp.h>
-#include <argz.h>
#include <hurd/netfs.h>
#include <fcntl.h>
/*----------------------------------------------------------------------------*/
@@ -41,13 +40,6 @@
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
-/*--------Macros--------------------------------------------------------------*/
-/*The state modes use in open*/
-#define OPENONLY_STATE_MODES (O_CREAT | O_EXCL | O_NOLINK | O_NOTRANS \
- | O_NONBLOCK)
-/*----------------------------------------------------------------------------*/
-
-/*----------------------------------------------------------------------------*/
/*--------Global Variables----------------------------------------------------*/
/*The name of the server*/
char * netfs_server_name = "nsmux";
@@ -520,6 +512,7 @@ netfs_attempt_lookup
LOG_MSG("netfs_attempt_lookup: '%s'", name);
error_t err = 0;
+ int i = 0;
/*If we are asked to fetch the current directory*/
if(strcmp(name, ".") == 0)
@@ -564,10 +557,32 @@ netfs_attempt_lookup
/*The lnode corresponding to the entry we are supposed to fetch*/
lnode_t * lnode;
+ /*The position of ',,' in the name*/
+ char * sep;
+
+ /*A pointer for various operations on strings*/
+ char * str;
+
+ /*A list of translators*/
+ char * trans = NULL;
+
+ /*The number of translators in the list*/
+ size_t ntrans;
+
+ /*The length of the list of translators*/
+ size_t translen;
+
+ /*Is the looked up file a directory*/
+ int isdir;
+
/*Finalizes the execution of this function*/
void
finalize(void)
{
+ /*Free the list of translators, if it has been allocated*/
+ if(trans)
+ free(trans);
+
/*If some errors have occurred*/
if(err)
{
@@ -625,6 +640,9 @@ netfs_attempt_lookup
{
/*do not set the port*/
p = MACH_PORT_NULL;
+
+ /*remember we do not have a directory*/
+ isdir = 0;
}
else
{
@@ -634,6 +652,9 @@ netfs_attempt_lookup
{
return EBADF; /*not enough rights?*/
}
+
+ /*we have a directory here*/
+ isdir = 1;
}
/*Try to find an lnode called `name` under the lnode corresponding to `dir`*/
@@ -653,28 +674,13 @@ netfs_attempt_lookup
/*install the new lnode into the directory*/
lnode_install(dir->nn->lnode, lnode);
}
- else
- {
- /*TODO: Remove the code from here and put it into the caller block,
- so that we can decide there whether to remove translators and
- *which* ones to remove*/
-
- /*free the list of translators associated with this node, if
- such a list exists*/
- if(lnode->trans)
- {
- free(lnode->trans);
- lnode->trans = NULL;
- lnode->ntrans = lnode->translen = 0;
- }
- }
-
+
/*Obtain the node corresponding to this lnode*/
err = ncache_node_lookup(lnode, node);
/*Remove an extra reference from the lnode*/
lnode_ref_remove(lnode);
-
+
/*If the lookup in the cache failed*/
if(err)
{
@@ -686,6 +692,12 @@ netfs_attempt_lookup
/*Store the port in the node*/
(*node)->nn->port = p;
+ /*Fill in the flag about the node being a directory*/
+ if(isdir)
+ lnode->flags |= FLAG_LNODE_DIR;
+ else
+ lnode->flags &= ~FLAG_LNODE_DIR;
+
/*Construct the full path to the node*/
err = lnode_path_construct(lnode, NULL);
if(err)
@@ -701,12 +713,6 @@ netfs_attempt_lookup
return 0;
}/*lookup*/
- /*The position of ',,' in the name*/
- char * sep;
-
- /*A pointer for various operations on strings*/
- char * str;
-
/*While pairs of commas can still be found in the name*/
for(sep = strstr(name, ",,"); sep; sep = strstr(sep, ",,"))
{
@@ -760,58 +766,219 @@ netfs_attempt_lookup
/*duplicate the part of the name containing the list of translators
and store the copy in the lnode*/
- lnode->trans = strdup(sep);
- if(!lnode->trans)
+ trans = strdup(sep);
+ if(!trans)
{
finalize();
return err;
}
- /*free the copy of the name*/
- /*we've just copied the pointer, so don't free it*/
- /*free(name_cpy);*/
-
/*obtain a pointer to the beginning of the list of translators*/
- str = lnode->trans;
+ str = trans;
- /*used to process escaped commas*/
- /*char * p;*/
+ /*a pointer for removal of extra commas*/
+ char * p;
/*Go through the list of translators*/
- for(lnode->ntrans = 0; *str; ++str)
+ for(translen = ntrans = 0; *str; ++str)
{
- /*Commas are not allowed in translator names*/
-#if 0
- /*If we are now situated at an escaped comma*/
- if((*str == '\\') && (str[1] == ','))
- {
- /*shift everything left in the string to remove the escaping backslash*/
- for(p = str; *p; *p = p[1], ++p);
-
- /*count a single character and step forward*/
- ++lnode->translen;
- continue;
- }
-#endif
-
/*If the current character is a comma*/
if(*str == ',')
{
+ /*While the next characters are commas, too*/
+ for(; str[1] == ',';)
+ {
+ /*shift the string leftwards*/
+ for(p = str + 1; *p; p[-1] = *p, ++p);
+ p[-1] = 0;
+ }
+
+ /*If the next character is the terminal 0*/
+ if(!str[1])
+ {
+ /*this comma is extra*/
+ *str = 0;
+ break;
+ }
+
/*make it a separator zero*/
*str = 0;
/*we have just finished going through a new component*/
- ++lnode->ntrans;
+ ++ntrans;
}
/*take the current character into account*/
- ++lnode->translen;
+ ++translen;
}
/*take into consideration the last element in the list,
which does not end in a comma and the corresponding terminal 0*/
- ++lnode->ntrans;
- ++lnode->translen;
+ ++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;
+ }
}
/*The control sequence ',,' has not been found*/
else
@@ -823,14 +990,51 @@ netfs_attempt_lookup
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;
+ }
}
- /*The list of translators inherited from its ancestors*/
- char * trans;
-
- /*the number of translators*/
- size_t ntrans;
-
+ /*If we have a directory*/
+ if(isdir)
+ {
+ /*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;
+ }
+
+ /*If the current node has already been successfully translated*/
+ if(lnode->flags & FLAG_LNODE_TRANSLATED)
+ {
+ /*no additional translators must set on this file*/
+ err = 0;
+ finalize();
+ return err;
+ }
+
/*Obtain the list of inherited translators*/
err = lnode_list_translators(lnode, &trans, &ntrans);
if(err)
@@ -847,139 +1051,24 @@ netfs_attempt_lookup
return 0;
}
- int i;
-
- /*If there is a port open for the current node*/
- if((*node)->nn->port != MACH_PORT_NULL)
- {
- /*close the port, since we will open it when starting translators*/
- PORT_DEALLOC((*node)->nn->port);
- }
-
- /*Opens a port to the file at the request of fshelp_start_translator*/
- error_t
- open_port
- (
- int flags,
- mach_port_t * underlying,
- mach_msg_type_name_t * underlying_type,
- task_t task,
- void * cookie /*some additional information, not used here*/
- )
- {
- /*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;
-
- /*Store the result in the parameters*/
- *underlying = p;
- *underlying_type = MACH_MSG_TYPE_COPY_SEND;
-
- /*Here everything is OK*/
- return 0;
- }/*open_port*/
-
- /*Adds a "/hurd/" at the beginning of the translator name, if required*/
- char *
- put_in_hurd
- (
- char * name
- )
- {
- /*If the path to the translator is absolute, return a copy of the name*/
- /*TODO: A better decision technique on whether we have to add the prefix*/
- if(name[0] == '/')
- return strdup(name);
-
- /*Compute the length of the name*/
- size_t len = strlen(name);
-
- /*Try to allocate new memory*/
- char * full = malloc(6/*strlen("/hurd/")*/ + len + 1);
- if(!full)
- return NULL;
-
- /*Construct the name*/
- strcpy(full, "/hurd/");
- strcpy(full + 6, name);
- full[6 + len] = 0;
-
- /*Return the full path*/
- return full;
- }/*put_in_hurd*/
-
- /*A copy (possibly extended) of the name of the translator*/
- char * ext;
-
- /*The length of the current component in the list of translators*/
- size_t complen;
-
- /*The holders of argz-transformed translator name and arguments*/
- char * argz = NULL;
- size_t argz_len = 0;
-
- /*The control port for the active translator*/
- mach_port_t active_control;
-
/*Go through the list of translators*/
for(str = trans, i = 0; i < ntrans; ++i)
{
- /*obtain the length of the current component*/
- complen = strlen(str);
-
- /*obtain a copy (possibly extended) of the name*/
- ext = put_in_hurd(str);
- if(!ext)
- {
- err = ENOMEM;
- finalize();
- return err;
- }
-
- /*TODO: Better argument-parsing?*/
-
- /*obtain the argz version of str*/
- err = argz_create_sep(ext, ' ', &argz, &argz_len);
+ /*set the translator specified in the current component*/
+ err = node_set_translator(dir, *node, str);
if(err)
{
finalize();
- return err;
+ return 0; /*TODO: A better way to fight errors here*/
}
-
- /*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)
- {
- finalize();
- 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
- );
- if(err)
- {
- finalize();
- return err;
- }
-
- /*deallocate the port we have just opened*/
- PORT_DEALLOC(p);
-
+
/*skip the current component*/
- str += complen + 1;
+ str += strlen(str) + 1;
}
+ /*All translators have been succesfully set on this node*/
+ lnode->flags |= FLAG_LNODE_TRANSLATED;
+
/*Everything OK here*/
finalize();
return err;