diff options
Diffstat (limited to 'netfs-sample/node.c~')
-rw-r--r-- | netfs-sample/node.c~ | 803 |
1 files changed, 0 insertions, 803 deletions
diff --git a/netfs-sample/node.c~ b/netfs-sample/node.c~ deleted file mode 100644 index ec83b41b..00000000 --- a/netfs-sample/node.c~ +++ /dev/null @@ -1,803 +0,0 @@ -/*----------------------------------------------------------------------------*/ -/*node.c*/ -/*----------------------------------------------------------------------------*/ -/*Implementation of node management strategies*/ -/*----------------------------------------------------------------------------*/ -/*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 1 -/*----------------------------------------------------------------------------*/ -#include <stdlib.h> -#include <fcntl.h> -#include <sys/stat.h> -#include <sys/mman.h> -#include <stdio.h> -/*----------------------------------------------------------------------------*/ -#include "debug.h" -#include "node.h" -#include "options.h" -#include "lib.h" -#include "filterfs.h" -/*----------------------------------------------------------------------------*/ - -/*----------------------------------------------------------------------------*/ -/*--------Global Variables----------------------------------------------------*/ -/*The lock protecting the underlying filesystem*/ -struct mutex ulfs_lock = MUTEX_INITIALIZER; -/*----------------------------------------------------------------------------*/ - -/*----------------------------------------------------------------------------*/ -/*--------Functions-----------------------------------------------------------*/ -/*Derives a new node from `lnode` and adds a reference to `lnode`*/ -error_t -node_create - ( - 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)); - - /*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; - } - - /*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; - node_new->nn->flags = 0; - node_new->nn->ncache_next = node_new->nn->ncache_prev = NULL; - - /*store the result of creation in the second parameter*/ - *node = node_new; - } - - /*Return the result of operations*/ - return err; - }/*node_create*/ -/*----------------------------------------------------------------------------*/ -/*Destroys the specified node and removes a light reference from the - associated light node*/ -void -node_destroy - ( - node_t * np - ) - { - /*Die if the node does not belong to node cache*/ - 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); - - /*Lock the lnode corresponding to the current node*/ - mutex_lock(&np->nn->lnode->lock); - - /*Orphan the light node*/ - np->nn->lnode->node = NULL; - - /*Remove a reference from the lnode*/ - lnode_ref_remove(np->nn->lnode); - - /*Free the netnode and the node itself*/ - free(np->nn); - free(np); - }/*node_destroy*/ -/*----------------------------------------------------------------------------*/ -/*Creates the root node and the corresponding lnode*/ -error_t -node_create_root - ( - node_t ** root_node /*store the result here*/ - ) - { - /*Try to create a new lnode*/ - lnode_t * lnode; - error_t err = lnode_create(NULL, &lnode); - - /*Stop, if the creation failed*/ - if(err) - return err; - - /*Try to derive the node corresponding to `lnode`*/ - node_t * node; - err = node_create(lnode, &node); - - /*If the operation failed*/ - if(err) - { - /*destroy the created lnode*/ - lnode_destroy(lnode); - - /*stop*/ - return err; - } - - /*Release the lock on the lnode*/ - mutex_unlock(&lnode->lock); - - /*Store the result in the parameter*/ - *root_node = node; - - /*Return the result*/ - return err; - }/*node_create_root*/ -/*----------------------------------------------------------------------------*/ -/*Initializes the port to the underlying filesystem for the root node*/ -error_t -node_init_root - ( - node_t * node /*the root node*/ - ) - { - error_t err = 0; - - /*Acquire a lock for operations on the underlying filesystem*/ - mutex_lock(&ulfs_lock); - - /*Open the port to the directory specified in `dir`*/ - node->nn->port = file_name_lookup(dir, O_READ | O_DIRECTORY, 0); - - /*If the directory could not be opened*/ - if(node->nn->port == MACH_PORT_NULL) - { - /*set the error code accordingly*/ - err = errno; - LOG_MSG("node_init_root: Could not open the port for %s.", dir); - - /*release the lock and stop*/ - mutex_unlock(&ulfs_lock); - return err; - } - - LOG_MSG("node_init_root: Port for %s opened successfully.", dir); - LOG_MSG("\tPort: 0x%lX", (unsigned long)node->nn->port); - - /*Stat the root node*/ - err = io_stat(node->nn->port, &node->nn_stat); - if(err) - { - /*deallocate the port*/ - PORT_DEALLOC(node->nn->port); - - LOG_MSG("node_init_root: Could not stat the root node."); - - /*unlock the mutex and exit*/ - mutex_unlock(&ulfs_lock); - return err; - } - - /*Set the path to the corresponding lnode to `dir`*/ - node->nn->lnode->path = strdup(dir); - if(!node->nn->lnode->path) - { - /*deallocate the port*/ - PORT_DEALLOC(node->nn->port); - - /*unlock the mutex*/ - mutex_unlock(&ulfs_lock); - - LOG_MSG("node_init_root: Could not strdup the directory."); - return ENOMEM; - } - - /*The current position in dir*/ - char * p = dir + strlen(dir); - - /*Go through the path from end to beginning*/ - for(; p >= dir; --p) - { - /*If the current character is a '/'*/ - if(*p == '/') - { - /*If p is not the first character*/ - if(p > dir) - { - /*if this slash is escaped, skip it*/ - if(*(p - 1) == '\\') - continue; - } - - /*advance the pointer to the first character after the slash*/ - ++p; - - /*stop*/ - break; - } - } - - LOG_MSG("node_init_root: The name of root node is %s.", p); - - /*Set the name of the lnode to the last element in the path to dir*/ - node->nn->lnode->name = strdup(p); - /*If the name of the node could not be duplicated*/ - if(!node->nn->lnode->name) - { - /*free the name of the path to the node and deallocate teh port*/ - free(node->nn->lnode->path); - PORT_DEALLOC(node->nn->port); - - /*unlock the mutex*/ - mutex_unlock(&ulfs_lock); - - LOG_MSG("node_init_root: Could not strdup the name of the root node."); - return ENOMEM; - } - - /*Compute the length of the name of the root node*/ - node->nn->lnode->name_len = strlen(p); - - /*Release the lock for operations on the undelying filesystem*/ - mutex_unlock(&ulfs_lock); - - /*Return the result of operations*/ - return err; - }/*node_init_root*/ -/*----------------------------------------------------------------------------*/ -/*Frees a list of dirents*/ -void -node_entries_free - ( - node_dirent_t * dirents /*free this*/ - ) - { - /*The current and the next elements*/ - node_dirent_t * dirent, * dirent_next; - - /*Go through all elements of the list*/ - for(dirent = dirents; dirent; dirent = dirent_next) - { - /*store the next element*/ - dirent_next = dirent->next; - - /*free the dirent stored in the current element of the list*/ - free(dirent->dirent); - - /*free the current element*/ - free(dirent); - } - }/*node_entries_free*/ -/*----------------------------------------------------------------------------*/ -/*Reads the directory entries from `node`, which must be locked*/ -error_t -node_entries_get - ( - node_t * node, - node_dirent_t ** dirents /*store the result here*/ - ) - { - error_t err = 0; - - /*Obtain the path to the current node*/ - char * path_to_node = node->nn->lnode->path; - - /*The number of PROPERTY_PARAMs in the property*/ - int param_entries_count = 0; - - /*The length of the property*/ - size_t property_len = (property) ? (strlen(property)) : (0); - - /*The length of PROPERTY_PARAM*/ - size_t property_param_len = strlen(PROPERTY_PARAM); - - /*The full name and the filtering command*/ - char * full_name = NULL, * cmd = NULL; - - /*The lengths of the full name and the filtering command in chunks*/ - size_t full_name_size = 1, cmd_size = 1; - - /*If some property was indeed specified*/ - if(property_len != 0) - { - /*the pointer to the current occurrence of PROPERTY_PARAM*/ - char * occurrence = strstr(property, PROPERTY_PARAM); - - /*count the number of occurrences*/ - for(; occurrence; - occurrence = strstr(occurrence + 1, PROPERTY_PARAM), - ++param_entries_count); - - /*try allocate the memory for the fullname and the filtering command*/ - full_name = malloc(full_name_size * STRING_CHUNK); - if(!full_name) - return ENOMEM; - - cmd = malloc(cmd_size * STRING_CHUNK); - if(!cmd) - { - free(full_name); - return ENOMEM; - } - } - - /*Obtain the length of the path*/ - size_t pathlen = strlen(path_to_node); - - /*Checks if the given file satisfies the property. Zero value means that - the entry must be filtered out*/ - int - check_property - ( - const char * name /*the name of the file*/ - ) - { - /*If there is no property*/ - if(!property) - /*no filtering will be applied, any name is OK*/ - return 0; - - /*Everything OK at first*/ - err = 0; - - /*Compute the length of the full name once*/ - size_t full_name_len = pathlen + 1 + strlen(name) + 1; - - /*See how much space (in chunks) is required for the full name*/ - int chunks = full_name_size; - for(; full_name_len > chunks * STRING_CHUNK; ++chunks); - - /*If more memory is requied*/ - if(chunks > full_name_size) - { - /*free the old full name*/ - free(full_name); - - /*try to allocate the new memory*/ - full_name = malloc(chunks * STRING_CHUNK); - if(!full_name) - { - err = ENOMEM; - free(cmd); /*the string for the command is definitely allocated here*/ - return 0; - } - - /*store the new size*/ - full_name_size = chunks; - } - - /*Initialize `full_name` as a valid string*/ - full_name[0] = 0; - - /*Construct the full name*/ - strcpy(full_name, path_to_node); - strcat(full_name, "/"); - strcat(full_name, name); - - /*LOG_MSG("node_entries_get: Applying filter to %s...", full_name);*/ - - /*Compute the space required for the final filtering command*/ - size_t sz = property_len + (strlen(full_name) - property_param_len) - * param_entries_count; - - /*See how much space (in chunks) is required for the command*/ - for(chunks = cmd_size; sz > chunks * STRING_CHUNK; ++chunks); - - /*If more memory is requied*/ - if(chunks > cmd_size) - { - /*free the old command*/ - free(cmd); - - /*try to allocate the new memory*/ - cmd = malloc(chunks * STRING_CHUNK); - if(!cmd) - { - err = ENOMEM; - free(full_name); /*the string for the full name is - definitely allocated here*/ - return 0; - } - - /*store the new size*/ - cmd_size = chunks; - } - - /*Initialize `cmd` as a valid string*/ - cmd[0] = 0; - - /*The current occurence of PROPERTY_PARAM in property*/ - char * p = strstr(property, PROPERTY_PARAM); - - /*The pointer to the current position in the property*/ - char * propp = property; - - /*While the command has not been constructed*/ - for(; p; p = strstr(propp, PROPERTY_PARAM)) - { - /*add the new part of the property to the command*/ - strncat(cmd, propp, p - propp); - - /*add the filename to the command*/ - strcat(cmd, full_name); - - /*LOG_MSG("\tcmd = '%s'", cmd);*/ - - /*advance the pointer in the property*/ - propp = p + property_param_len; - - /*LOG_MSG("\tpropp points at '%s'", propp);*/ - } - - /*Copy the rest of the property to the command*/ - strcat(cmd, propp); - - /*LOG_MSG("node_entries_get: The filtering command: '%s'.", cmd);*/ - - /*Execute the command*/ - int xcode = WEXITSTATUS(system(cmd)); - - /*Return the exit code of the command*/ - return xcode; - }/*check_property*/ - - /*The list of dirents*/ - struct dirent ** dirent_list, **dirent; - - /*The head of the list of dirents*/ - node_dirent_t * node_dirent_list = NULL; - - /*The size of the array of pointers to dirent*/ - size_t dirent_data_size; - - /*The array of dirents*/ - char * dirent_data; - - /*Obtain the directory entries for the given node*/ - err = dir_entries_get - (node->nn->port, &dirent_data, &dirent_data_size, &dirent_list); - if(err) - { - return err; - } - - /*The new entry in the list*/ - node_dirent_t * node_dirent_new; - - /*The new dirent*/ - struct dirent * dirent_new; - - /*LOG_MSG("node_entries_get: Getting entries for %p", node);*/ - - /*The name of the current dirent*/ - char * name; - - /*The length of the current name*/ - size_t name_len; - - /*The size of the current dirent*/ - size_t size; - - /*The exit code of property*/ - int good; - - /*Go through all elements of the list of pointers to dirent*/ - for(dirent = dirent_list; *dirent; ++dirent) - { - /*obtain the name of the current dirent*/ - name = &((*dirent)->d_name[0]); - - /*If the current dirent is either '.' or '..', skip it*/ - if((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0)) - continue; - - /*check if the current dirent has the property*/ - good = check_property(name); - if(err) - break; - - /*If the current entry is not good, skip it*/ - if(good != 0) - continue; - - /*obtain the length of the current name*/ - name_len = strlen(name); - - /*obtain the length of the current dirent*/ - size = DIRENT_LEN(name_len); - - /*create a new list element*/ - node_dirent_new = malloc(sizeof(node_dirent_t)); - if(!node_dirent_new) - { - err = ENOMEM; - break; - } - - /*create a new dirent*/ - dirent_new = malloc(size); - if(!dirent_new) - { - free(node_dirent_new); - err = ENOMEM; - break; - } - - /*fill the dirent with information*/ - dirent_new->d_ino = (*dirent)->d_ino; - dirent_new->d_type = (*dirent)->d_type; - dirent_new->d_reclen = size; - strcpy((char *)dirent_new + DIRENT_NAME_OFFS, name); - - /*add the dirent to the list*/ - node_dirent_new->dirent = dirent_new; - node_dirent_new->next = node_dirent_list; - node_dirent_list = node_dirent_new; - } - - /*If something went wrong in the loop*/ - if(err) - /*free the list of dirents*/ - node_entries_free(node_dirent_list); - else - /*store the list of dirents in the second parameter*/ - *dirents = node_dirent_list; - - /*Free the list of pointers to dirent*/ - free(dirent_list); - - /*Free the results of listing the dirents*/ - munmap(dirent_data, dirent_data_size); - - /*Free the full name and the command (if these are present at all)*/ - if(full_name) - free(full_name); - if(cmd) - free(cmd); - - /*Return the result of operations*/ - return err; - }/*node_entries_get*/ -/*----------------------------------------------------------------------------*/ -/*Makes sure that all ports to the underlying filesystem of `node` are up to - date*/ -error_t -node_update - ( - node_t * node - ) - { - error_t err = 0; - - /*The full path to this node*/ - char * path; - - /*Stat information for `node`*/ - io_statbuf_t stat; - - /*The port to the file corresponding to `node`*/ - file_t port; - - /*If the specified node is the root node or if it must not be updated*/ - if(NODE_IS_ROOT(node) || (node->nn->flags & FLAG_NODE_ULFS_FIXED)) - /*do nothing*/ - return err; /*return 0; actually*/ - - /*Gain exclusive access to the root node of the filesystem*/ - mutex_lock(&netfs_root_node->lock); - - /*Construct the full path to `node`*/ - err = lnode_path_construct(node->nn->lnode, &path); - if(err) - { - mutex_unlock(&netfs_root_node->lock); - return err; - } - - /*Deallocate `node`'s port to the underlying filesystem*/ - if(node->nn->port) - PORT_DEALLOC(node->nn->port); - - /*Try to lookup the file for `node` in its untranslated version*/ - err = file_lookup - ( - netfs_root_node->nn->port, path, O_READ | O_NOTRANS, O_NOTRANS, - 0, &port, &stat - ); - if(err) - { - node->nn->port = MACH_PORT_NULL; - err = 0; /*failure (?)*/ - return err; - } - - /*If the node looked up is actually the root node of filterfs filesystem*/ - if - ( - (stat.st_ino == underlying_node_stat.st_ino) - && (stat.st_fsid == underlying_node_stat.st_fsid) - ) - /*set `err` accordingly*/ - err = ELOOP; - else - { - /*deallocate the obtained port*/ - PORT_DEALLOC(port); - - /*obtain the translated version of the required node*/ - err = file_lookup - (netfs_root_node->nn->port, path, O_READ, 0, 0, &port, &stat); - } - - /*If there have been errors*/ - if(err) - /*reset the port*/ - port = MACH_PORT_NULL; - - /*Store the port in the node*/ - node->nn->port = port; - - /*Remove the flag about the invalidity of the current node and set the - flag that the node is up-to-date*/ - node->nn->flags &= ~FLAG_NODE_INVALIDATE; - node->nn->flags |= FLAG_NODE_ULFS_UPTODATE; - - /*Release the lock on the root node of filterfs filesystem*/ - mutex_unlock(&netfs_root_node->lock); - - /*Return the result of operations*/ - return err; - }/*node_update*/ -/*----------------------------------------------------------------------------*/ -/*Computes the size of the given directory*/ -error_t -node_get_size - ( - node_t * dir, - OFFSET_T * off - ) - { - error_t err = 0; - - /*The final size*/ - size_t size = 0; - - /*The number of directory entries*/ - /*int count = 0;*/ - - /*The the node in the directory entries list from which we start counting*/ - /*node_dirent_t * dirent_start = NULL;*/ - - /*The currently analyzed dirent*/ - node_dirent_t * dirent_current = NULL; - - /*The pointer to the beginning of the list of dirents*/ - node_dirent_t * dirent_list = NULL; - - /*The first entry we have to analyze*/ - /*int first_entry = 2;*/ - - /*Takes into consideration the name of the current dirent*/ - void - bump_size - ( - const char * name - ) - { - /*Increment the current size by the size of the current dirent*/ - size += DIRENT_LEN(strlen(name)); - - /*Count the current dirent*/ - /*++count;*/ - }/*bump_size*/ - - /*Obtain the list of entries in the current directory*/ - err = node_entries_get(dir, &dirent_list); - if(err) - return err; - - /*Obtain the pointer to the dirent which has the number first_entry*/ - /*Actually, the first element of the list*/ - /*This code is included in unionfs, but it's completely useless here*/ - /*for - ( - dirent_start = dirent_list, count = 2; - dirent_start && count < first_entry; - dirent_start = dirent_start->next, ++count - );*/ - - /*Reset the count*/ - /*count = 0;*/ - - /*Make space for '.' and '..' entries*/ - /*This code is included in unionfs, but it's completely useless here*/ - /*if(first_entry == 0) - bump_size("."); - if(first_entry <= 1) - bump_size("..");*/ - - /*See how much space is required for the node*/ - for - ( - dirent_current = dirent_list/*dirent_start*/; dirent_current; - dirent_current = dirent_current->next - ) - bump_size(dirent_current->dirent->d_name); - - /*Free the list of dirents*/ - node_entries_free(dirent_list); - - /*Return the size*/ - *off = size; - return 0; - }/*node_get_size*/ -/*----------------------------------------------------------------------------*/ -/*Remove the file called `name` under `dir`*/ -error_t -node_unlink_file - ( - node_t * dir, - char * name - ) - { - error_t err = 0; - - /*The port to the file which will be unlinked*/ - mach_port_t p; - - /*Stat information about the file which will be unlinked*/ - io_statbuf_t stat; - - /*If port corresponding to `dir` is invalid*/ - if(dir->nn->port == MACH_PORT_NULL) - /*stop with an error*/ - return ENOENT; /*FIXME: Is the return value indeed meaningful here?*/ - - /*Attempt to lookup the specified file*/ - err = file_lookup(dir->nn->port, name, O_NOTRANS, O_NOTRANS, 0, &p, &stat); - if(err) - return err; - - /*Deallocate the obtained port*/ - PORT_DEALLOC(p); - - /*Unlink file `name` under `dir`*/ - err = dir_unlink(dir->nn->port, name); - if(err) - return err; - - return err; - }/*node_unlink_file*/ -/*----------------------------------------------------------------------------*/ |