diff options
author | Sergiu Ivanov <unlimitedscolobb@gmail.com> | 2008-07-22 18:10:44 +0300 |
---|---|---|
committer | Sergiu Ivanov <unlimitedscolobb@gmail.com> | 2008-07-22 18:10:44 +0300 |
commit | 13fa6563250dcd4b2d1a54f15aba1bb7d8aace28 (patch) | |
tree | f70c733622bd20dada164bf6b072c4bfb7bc22e4 /node.c | |
parent | ef6b6263abd1d58ebefe3c8b751c9148459c9638 (diff) |
Added the possibility to propagate translators onto directories. Fixed bugs.
Now the user can enter directories using the following command:
cd dir,,x
All files in this directory will then be implicitly translated
by translator 'x'; in other words, if there is a file 'file' in
directory 'dir', after executing the command mentioned above,
and after running
cat file
the user will obtain the content of 'file' translated by 'x'.
Also fixed several rather serious bugs in lookup of file names
of the type 'file,,x'.
Diffstat (limited to 'node.c')
-rw-r--r-- | node.c | 229 |
1 files changed, 228 insertions, 1 deletions
@@ -32,12 +32,14 @@ #include <sys/stat.h> #include <sys/mman.h> #include <stdio.h> +#include <argz.h> /*----------------------------------------------------------------------------*/ #include "debug.h" #include "node.h" #include "options.h" #include "lib.h" #include "nsmux.h" +#include "ncache.h" /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ @@ -111,7 +113,16 @@ node_destroy assert(!np->nn->ncache_next || !np->nn->ncache_prev); /*Destroy the port to the underlying filesystem allocated to the node*/ - PORT_DEALLOC(np->nn->port); + 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) + { + /*kill all translators on the underlying nodes*/ + node_kill_all_translators(np); + } /*Lock the lnode corresponding to the current node*/ mutex_lock(&np->nn->lnode->lock); @@ -621,3 +632,219 @@ 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`.*/ +error_t +node_set_translator + ( + node_t * dir, + node_t * node, + const char * trans /*set this on `name`*/ + ) + { + error_t err; + + /*A port for opened to the file*/ + mach_port_t p; + + /*A copy (possibly extended) of the name of the translator*/ + char * ext; + + /*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; + + /*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 + ( + const 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/"); + /*LOG_MSG("node_set_translator: %s", full);*/ + strcpy(full + 6, name); + /*LOG_MSG("node_set_translator: %s", full);*/ + full[6 + len] = 0; + /*LOG_MSG("node_set_translator: %s", full);*/ + + /*Return the full path*/ + 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); + if(err) + return err; + + /*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; + + /*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; + + /*Deallocate the port we have just opened*/ + PORT_DEALLOC(p); + + /*Everything is OK here*/ + return 0; + }/*node_set_translator*/ +/*----------------------------------------------------------------------------*/ +/*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`.*/ +error_t +node_kill_translator + ( + node_t * dir, + node_t * node + ) + { + /*Lookup the file*/ + mach_port_t p = + file_name_lookup_under(dir->nn->port, node->nn->lnode->name, O_NOTRANS, 0); + + /*Remove a translator from the node*/ + error_t err = file_set_translator + ( + p, FS_TRANS_SET, FS_TRANS_SET, 0, NULL, 0, + MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND + ); + + /*Close the port*/ + PORT_DEALLOC(p); + + /*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_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; + + /*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; + + /*Destroy the list of translators*/ + if(ln->trans) + free(ln->trans); + + /*No more translators on this node*/ + ln->trans = NULL; + ln->ntrans = ln->translen = 0; + + /*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); + + /*Kill all translators on the current node*/ + traverse_children_r(dnp, node, node->nn->lnode->ntrans); + + /*Unlock the parent node*/ + mutex_unlock(&dnp->lock); + }/*node_kill_all_translators*/ +/*----------------------------------------------------------------------------*/ |