diff options
-rw-r--r-- | REAMDE | 10 | ||||
-rw-r--r-- | debug.h | 59 | ||||
-rw-r--r-- | filter.c | 726 | ||||
-rw-r--r-- | filter.c~ | 736 | ||||
-rw-r--r-- | filter.h | 348 | ||||
-rw-r--r-- | node.c | 166 | ||||
-rw-r--r-- | node.h | 114 | ||||
-rw-r--r-- | options.c | 190 | ||||
-rw-r--r-- | options.h | 44 |
9 files changed, 2393 insertions, 0 deletions
@@ -0,0 +1,10 @@ +FILTER TRANSLATOR FOR NSMUX + +filter is GNU/Hurd translator designed specifically to be used in +namespace-based translator selection, that is with nsmux. When set on +a file this translator will traverse the stack of static translators +(which sit on the real filesystem node) and stop at the translator +whose name matches the name provided to the filter on the command +line. It will then read and write data using this translator, i.e. all +translators sitting upon this translator and below the filter will be +shunted. diff --git a/debug.h b/debug.h new file mode 100644 index 000000000..254226737 --- /dev/null +++ b/debug.h @@ -0,0 +1,59 @@ +/*----------------------------------------------------------------------------*/ +/*debug.h*/ +/*----------------------------------------------------------------------------*/ +/*Simple facilities for debugging messages*/ +/*----------------------------------------------------------------------------*/ +/*Based on the code of unionfs translator.*/ +/*----------------------------------------------------------------------------*/ +/*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 + 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.*/ +/*----------------------------------------------------------------------------*/ +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + +/*----------------------------------------------------------------------------*/ +#include <stdio.h> +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/*--------Macros--------------------------------------------------------------*/ +/*Print debug messages here*/ +#define DEBUG_OUTPUT "/var/log/filter.dbg" +/*----------------------------------------------------------------------------*/ +#ifdef DEBUG + /*Initializes the log*/ +# define INIT_LOG() filter_dbg = fopen(DEBUG_OUTPUT, "wt") + /*Closes the log*/ +# define CLOSE_LOG() fclose(filter_dbg) + /*Prints a debug message and flushes the debug output*/ +# define LOG_MSG(fmt, args...) {fprintf(filter_dbg, fmt"\n", ##args);\ + fflush(filter_dbg);} +#else + /*Remove requests for debugging output*/ +# define INIT_LOG() +# define CLOSE_LOG() +# define LOG_MSG(fmt, args...) +#endif /*DEBUG*/ +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/*--------Global Variables----------------------------------------------------*/ +/*The file to write debugging info to*/ +extern FILE * filter_dbg; +/*----------------------------------------------------------------------------*/ +#endif /*__DEBUG_H__*/ diff --git a/filter.c b/filter.c new file mode 100644 index 000000000..09a409cb2 --- /dev/null +++ b/filter.c @@ -0,0 +1,726 @@ +/*----------------------------------------------------------------------------*/ +/*filter.c*/ +/*----------------------------------------------------------------------------*/ +/*The filtering translator*/ +/*----------------------------------------------------------------------------*/ +/*Based on the code of unionfs translator.*/ +/*----------------------------------------------------------------------------*/ +/*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 + 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 "filter.h" +/*----------------------------------------------------------------------------*/ +#include <error.h> +#include <argp.h> +#include <argz.h> +#include <hurd/netfs.h> +#include <fcntl.h> +/*----------------------------------------------------------------------------*/ +#include "debug.h" +#include "options.h" +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/*--------Global Variables----------------------------------------------------*/ +/*The name of the server*/ +char * netfs_server_name = "filter"; +/*----------------------------------------------------------------------------*/ +/*The version of the server*/ +char * netfs_server_version = "0.0"; +/*----------------------------------------------------------------------------*/ +/*The maximal length of a chain of symbolic links*/ +int netfs_maxsymlinks = 12; +/*----------------------------------------------------------------------------*/ +/*A port to the underlying node*/ +mach_port_t underlying_node; +/*----------------------------------------------------------------------------*/ +/*Status information for the underlying node*/ +io_statbuf_t underlying_node_stat; +/*----------------------------------------------------------------------------*/ +/*Mapped time used for updating node information*/ +volatile struct mapped_time_value * maptime; +/*----------------------------------------------------------------------------*/ +/*The filesystem ID*/ +pid_t fsid; +/*----------------------------------------------------------------------------*/ +/*The port from which we will read (TODO: and write) the data*/ +mach_port_t target; +/*----------------------------------------------------------------------------*/ +/*The file to print debug messages to*/ +FILE * filter_dbg; +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/*--------Functions-----------------------------------------------------------*/ +/*Attempts to create a file named `name` in `dir` for `user` with mode `mode`*/ +error_t +netfs_attempt_create_file + ( + struct iouser * user, + struct node * dir, + char * name, + mode_t mode, + struct node ** node + ) + { + LOG_MSG("netfs_attempt_create_file"); + + /*Unlock `dir` and say that we can do nothing else here*/ + mutex_unlock(&dir->lock); + return EOPNOTSUPP; + }/*netfs_attempt_create_file*/ +/*----------------------------------------------------------------------------*/ +/*Return an error if the process of opening a file should not be allowed + to complete because of insufficient permissions*/ +error_t +netfs_check_open_permissions + ( + struct iouser * user, + struct node * np, + int flags, + int newnode + ) + { + LOG_MSG("netfs_check_open_permissions"); + + 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; + }/*netfs_check_open_permissions*/ +/*----------------------------------------------------------------------------*/ +/*Attempts an utimes call for the user `cred` on node `node`*/ +error_t +netfs_attempt_utimes + ( + struct iouser * cred, + struct node * node, + struct timespec * atime, + struct timespec * mtime + ) + { + LOG_MSG("netfs_attempt_utimes"); + + error_t err = 0; + + /*See what information is to be updated*/ + int flags = TOUCH_CTIME; + + /*Check if the user is indeed the owner of the node*/ + err = fshelp_isowner(&node->nn_stat, cred); + + /*If the user is allowed to do utimes*/ + if(!err) + { + /*If atime is to be updated*/ + if(atime) + /*update the atime*/ + node->nn_stat.st_atim = *atime; + else + /*the current time will be set as the atime*/ + flags |= TOUCH_ATIME; + + /*If mtime is to be updated*/ + if(mtime) + /*update the mtime*/ + node->nn_stat.st_mtim = *mtime; + else + /*the current time will be set as mtime*/ + flags |= TOUCH_MTIME; + + /*touch the file*/ + fshelp_touch(&node->nn_stat, flags, maptime); + } + + /*Return the result of operations*/ + return err; + }/*netfs_attempt_utimes*/ +/*----------------------------------------------------------------------------*/ +/*Returns the valid access types for file `node` and user `cred`*/ +error_t +netfs_report_access + ( + struct iouser * cred, + struct node * np, + int * types + ) + { + LOG_MSG("netfs_report_access"); + + /*No access at first*/ + *types = 0; + + /*Check the access and set the required bits*/ + if(fshelp_access(&np->nn_stat, S_IREAD, cred) == 0) + *types |= O_READ; + if(fshelp_access(&np->nn_stat, S_IWRITE, cred) == 0) + *types |= O_WRITE; + if(fshelp_access(&np->nn_stat, S_IEXEC, cred) == 0) + *types |= O_EXEC; + + /*Everything OK*/ + return 0; + }/*netfs_report_access*/ +/*----------------------------------------------------------------------------*/ +/*Validates the stat data for the node*/ +error_t +netfs_validate_stat + ( + struct node * np, + struct iouser * cred + ) + { + LOG_MSG("netfs_validate_stat"); + + error_t err = 0; + + /*Validate the stat information about the node*/ + err = io_stat(np->nn->port, &np->nn_stat); + + /*Return the result of operations*/ + return err; + }/*netfs_validate_stat*/ +/*----------------------------------------------------------------------------*/ +/*Syncs `node` completely to disk*/ +error_t +netfs_attempt_sync + ( + struct iouser * cred, + struct node * node, + int wait + ) + { + LOG_MSG("netfs_attempt_sync"); + + /*Operation is not supported*/ + return EOPNOTSUPP; + }/*netfs_attempt_sync*/ +/*----------------------------------------------------------------------------*/ +/*Fetches a directory*/ +error_t +netfs_get_dirents + ( + struct iouser * cred, + struct node * dir, + int first_entry, + int num_entries, + char ** data, + mach_msg_type_number_t * data_len, + vm_size_t max_data_len, + int * data_entries + ) + { + LOG_MSG("netfs_get_dirents"); + + /*This node is not a directory*/ + return ENOTDIR; + }/*netfs_get_dirents*/ +/*----------------------------------------------------------------------------*/ +/*Looks up `name` under `dir` for `user`*/ +error_t +netfs_attempt_lookup + ( + struct iouser * user, + struct node * dir, + char * name, + struct node ** node + ) + { + LOG_MSG("netfs_attempt_lookup: '%s'", name); + + /*Unlock the mutexes in `dir`*/ + mutex_unlock(&dir->lock); + return EOPNOTSUPP; + }/*netfs_attempt_lookup*/ +/*----------------------------------------------------------------------------*/ +/*Deletes `name` in `dir` for `user`*/ +error_t +netfs_attempt_unlink + ( + struct iouser * user, + struct node * dir, + char * name + ) + { + LOG_MSG("netfs_attempt_unlink"); + + return 0; + }/*netfs_attempt_unlink*/ +/*----------------------------------------------------------------------------*/ +/*Attempts to rename `fromdir`/`fromname` to `todir`/`toname`*/ +error_t +netfs_attempt_rename + ( + struct iouser * user, + struct node * fromdir, + char * fromname, + struct node * todir, + char * toname, + int excl + ) + { + LOG_MSG("netfs_attempt_rename"); + + /*Operation not supported*/ + return EOPNOTSUPP; + }/*netfs_attempt_rename*/ +/*----------------------------------------------------------------------------*/ +/*Attempts to create a new directory*/ +error_t +netfs_attempt_mkdir + ( + struct iouser * user, + struct node * dir, + char * name, + mode_t mode + ) + { + LOG_MSG("netfs_attempt_mkdir"); + + return 0; + }/*netfs_attempt_mkdir*/ +/*----------------------------------------------------------------------------*/ +/*Attempts to remove directory `name` in `dir` for `user`*/ +error_t +netfs_attempt_rmdir + ( + struct iouser * user, + struct node * dir, + char * name + ) + { + LOG_MSG("netfs_attempt_rmdir"); + + return 0; + }/*netfs_attempt_rmdir*/ +/*----------------------------------------------------------------------------*/ +/*Attempts to change the mode of `node` for user `cred` to `uid`:`gid`*/ +error_t +netfs_attempt_chown + ( + struct iouser * cred, + struct node * node, + uid_t uid, + uid_t gid + ) + { + LOG_MSG("netfs_attempt_chown"); + + /*Operation is not supported*/ + return EOPNOTSUPP; + }/*netfs_attempt_chown*/ +/*----------------------------------------------------------------------------*/ +/*Attempts to change the author of `node` to `author`*/ +error_t +netfs_attempt_chauthor + ( + struct iouser * cred, + struct node * node, + uid_t author + ) + { + LOG_MSG("netfs_attempt_chauthor"); + + /*Operation is not supported*/ + return EOPNOTSUPP; + }/*netfs_attempt_chauthor*/ +/*----------------------------------------------------------------------------*/ +/*Attempts to change the mode of `node` to `mode` for `cred`*/ +error_t +netfs_attempt_chmod + ( + struct iouser * user, + struct node * node, + mode_t mode + ) + { + LOG_MSG("netfs_attempt_chmod"); + + /*Operation is not supported*/ + return EOPNOTSUPP; + }/*netfs_attempt_chmod*/ +/*----------------------------------------------------------------------------*/ +/*Attempts to turn `node` into a symlink targetting `name`*/ +error_t +netfs_attempt_mksymlink + ( + struct iouser * cred, + struct node * node, + char * name + ) + { + LOG_MSG("netfs_attempt_mksymlink"); + + /*Operation is not supported*/ + return EOPNOTSUPP; + }/*netfs_attempt_mksymlink*/ +/*----------------------------------------------------------------------------*/ +/*Attempts to turn `node` into a device; type can be either S_IFBLK or S_IFCHR*/ +error_t +netfs_attempt_mkdev + ( + struct iouser * cred, + struct node * node, + mode_t type, + dev_t indexes + ) + { + LOG_MSG("netfs_attempt_mkdev"); + + /*Operation is not supported*/ + return EOPNOTSUPP; + }/*netfs_attempt_mkdev*/ +/*----------------------------------------------------------------------------*/ +/*Attempts to set the passive translator record for `file` passing `argz`*/ +error_t +netfs_set_translator + ( + struct iouser * cred, + struct node * node, + char * argz, + size_t arglen + ) + { + LOG_MSG("netfs_set_translator"); + + /*Operation is not supported*/ + return EOPNOTSUPP; + }/*netfs_set_translator */ +/*----------------------------------------------------------------------------*/ +/*Attempts to call chflags for `node`*/ +error_t +netfs_attempt_chflags + ( + struct iouser * cred, + struct node * node, + int flags + ) + { + LOG_MSG("netfs_attempt_chflags"); + + /*Operation is not supported*/ + return EOPNOTSUPP; + }/*netfs_attempt_chflags*/ +/*----------------------------------------------------------------------------*/ +/*Attempts to set the size of file `node`*/ +error_t +netfs_attempt_set_size + ( + struct iouser * cred, + struct node * node, + loff_t size + ) + { + LOG_MSG("netfs_attempt_set_size"); + + /*Operation is not supported*/ + return EOPNOTSUPP; + }/*netfs_attempt_set_size*/ +/*----------------------------------------------------------------------------*/ +/*Fetches the filesystem status information*/ +error_t +netfs_attempt_statfs + ( + struct iouser * cred, + struct node * node, + fsys_statfsbuf_t * st + ) + { + LOG_MSG("netfs_attempt_statfs"); + + /*Operation is not supported*/ + return EOPNOTSUPP; + }/*netfs_attempt_statfs*/ +/*----------------------------------------------------------------------------*/ +/*Syncs the filesystem*/ +error_t +netfs_attempt_syncfs + ( + struct iouser * cred, + int wait + ) + { + LOG_MSG("netfs_attempt_syncfs"); + + /*Everythin OK*/ + return 0; + }/*netfs_attempt_syncfs*/ +/*----------------------------------------------------------------------------*/ +/*Creates a link in `dir` with `name` to `file`*/ +error_t +netfs_attempt_link + ( + struct iouser * user, + struct node * dir, + struct node * file, + char * name, + int excl + ) + { + LOG_MSG("netfs_attempt_link"); + + /*Operation not supported*/ + return EOPNOTSUPP; + }/*netfs_attempt_link*/ +/*----------------------------------------------------------------------------*/ +/*Attempts to create an anonymous file related to `dir` with `mode`*/ +error_t +netfs_attempt_mkfile + ( + struct iouser * user, + struct node * dir, + mode_t mode, + struct node ** node + ) + { + LOG_MSG("netfs_attempt_mkfile"); + + /*Unlock the directory*/ + mutex_unlock(&dir->lock); + + /*Operation not supported*/ + return EOPNOTSUPP; + }/*netfs_attempt_mkfile*/ +/*----------------------------------------------------------------------------*/ +/*Reads the contents of symlink `node` into `buf`*/ +error_t +netfs_attempt_readlink + ( + struct iouser * user, + struct node * node, + char * buf + ) + { + LOG_MSG("netfs_attempt_readlink"); + + /*Operation not supported (why?..)*/ + return EOPNOTSUPP; + }/*netfs_attempt_readlink*/ +/*----------------------------------------------------------------------------*/ +/*Reads from file `node` up to `len` bytes from `offset` into `data`*/ +error_t +netfs_attempt_read + ( + struct iouser * cred, + struct node * np, + loff_t offset, + size_t * len, + void * data + ) + { + LOG_MSG("netfs_attempt_read"); + + error_t err = 0; + + /*Obtain a pointer to the first byte of the supplied buffer*/ + char * buf = data; + + /*Try to read the requested information from the file*/ + err = io_read(np->nn->port, &buf, len, offset, *len); + + /*If some data has been read successfully*/ + if(!err && (buf != data)) + { + /*copy the data from the buffer into which it has just been read into + the supplied receiver*/ + memcpy(data, buf, *len); + + /*unmap the new buffer*/ + munmap(buf, *len); + } + + /*Return the result of reading*/ + return err; + }/*netfs_attempt_read*/ +/*----------------------------------------------------------------------------*/ +/*Writes to file `node` up to `len` bytes from offset from `data`*/ +error_t +netfs_attempt_write + ( + struct iouser * cred, + struct node * node, + loff_t offset, + size_t * len, + void * data + ) + { + LOG_MSG("netfs_attempt_write"); + + return 0; + }/*netfs_attempt_write*/ +/*----------------------------------------------------------------------------*/ +/*Frees all storage associated with the node*/ +void +netfs_node_norefs + ( + struct node * np + ) + { + /*Destroy the node*/ + node_destroy(np); + }/*netfs_node_norefs*/ +/*----------------------------------------------------------------------------*/ +/*Implements file_get_translator_cntl as described in <hurd/fs.defs> + (according to diskfs_S_file_get_translator_cntl)*/ +kern_return_t +netfs_S_file_get_translator_cntl + ( + struct protid * user, + mach_port_t * cntl, + mach_msg_type_name_t * cntltype + ) + { + /*If the information about the user is missing*/ + if(!user) + return EOPNOTSUPP; + + error_t err = 0; + + /*Obtain the node for which we are called*/ + node_t * np = user->po->np; + + /*Lock the node*/ + mutex_lock(&np->lock); + + /*Check if the user is the owner of this node*/ + err = fshelp_isowner(&np->nn_stat, user->user); + + /*If no errors have happened*/ + if(!err) + /*try to fetch the control port*/ + err = fshelp_fetch_control(&np->transbox, cntl); + + /*If no errors have occurred, but no port has been returned*/ + if(!err && (cntl == MACH_PORT_NULL)) + /*set the error accordingly*/ + err = ENXIO; + + /*If no errors have occurred so far*/ + if(!err) + /*set the control port type*/ + *cntltype = MACH_MSG_TYPE_MOVE_SEND; + + /*Unlock the node*/ + mutex_unlock(&np->lock); + + /*Return the result of operations*/ + return err; + }/*netfs_S_file_get_translator_cntl*/ +/*----------------------------------------------------------------------------*/ +int +netfs_demuxer + ( + mach_msg_header_t * ing, + mach_msg_header_t * outp + ); +/*----------------------------------------------------------------------------*/ +/*Entry point*/ +int +main + ( + int argc, + char ** argv + ) + { + /*Start logging*/ + INIT_LOG(); + LOG_MSG(">> Starting initialization..."); + + /*The port on which this translator will be set upon*/ + mach_port_t bootstrap_port; + + error_t err = 0; + + /*Parse the command line arguments*/ + argp_parse(&argp_startup, argc, argv, ARGP_IN_ORDER, 0, 0); + LOG_MSG("Command line arguments parsed."); + + /*Try to create the root node*/ + err = node_create_root(&netfs_root_node); + if(err) + error(EXIT_FAILURE, err, "Failed to create the root node"); + LOG_MSG("Root node created."); + + /*Obtain the bootstrap port*/ + task_get_bootstrap_port(mach_task_self(), &bootstrap_port); + + /*Initialize the translator*/ + netfs_init(); + + /*Obtain a port to the underlying node opened as O_NOTRANS*/ + underlying_node = netfs_startup(bootstrap_port, O_READ | O_NOTRANS); + LOG_MSG("netfs initialization complete."); + + /*Initialize the root node*/ + err = node_init_root(underlying_node, netfs_root_node); + if(err) + error(EXIT_FAILURE, err, "Failed to initialize the root node"); + LOG_MSG("Root node initialized."); + LOG_MSG("\tRoot node address: 0x%lX", (unsigned long)netfs_root_node); + + /*Map the time for updating node information*/ + err = maptime_map(0, 0, &maptime); + if(err) + error(EXIT_FAILURE, err, "Failed to map the time"); + LOG_MSG("Time mapped."); + + /*Obtain stat information about the underlying node*/ + err = io_stat(underlying_node, &underlying_node_stat); + if(err) + error(EXIT_FAILURE, err, + "Cannot obtain stat information about the underlying node"); + LOG_MSG("Stat information for undelying node obtained."); + + /*Obtain the ID of the current process*/ + fsid = getpid(); + + /*Setup the stat information for the root node*/ + netfs_root_node->nn_stat = underlying_node_stat; + + netfs_root_node->nn_stat.st_ino = FILTER_ROOT_INODE; + netfs_root_node->nn_stat.st_fsid = fsid; + netfs_root_node->nn_stat.st_mode = underlying_node_stat.st_mode; + + netfs_root_node->nn_translated = netfs_root_node->nn_stat.st_mode; + + netfs_root_node->nn->port = target; + + /*Update the timestamps of the root node*/ + fshelp_touch + (&netfs_root_node->nn_stat, TOUCH_ATIME | TOUCH_MTIME | TOUCH_CTIME, + maptime); + + LOG_MSG(">> Initialization complete. Entering netfs server loop..."); + + /*Start serving clients*/ + for(;;) + netfs_server_loop(); + }/*main*/ +/*----------------------------------------------------------------------------*/ diff --git a/filter.c~ b/filter.c~ new file mode 100644 index 000000000..bd4ad6d93 --- /dev/null +++ b/filter.c~ @@ -0,0 +1,736 @@ +/*----------------------------------------------------------------------------*/ +/*filter.c*/ +/*----------------------------------------------------------------------------*/ +/*The filtering translator*/ +/*----------------------------------------------------------------------------*/ +/*Based on the code of unionfs translator.*/ +/*----------------------------------------------------------------------------*/ +/*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 + 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 "filter.h" +/*----------------------------------------------------------------------------*/ +#include <error.h> +#include <argp.h> +#include <argz.h> +#include <hurd/netfs.h> +#include <fcntl.h> +/*----------------------------------------------------------------------------*/ +#include "debug.h" +#include "options.h" +#include "trace.h" +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/*--------Global Variables----------------------------------------------------*/ +/*The name of the server*/ +char * netfs_server_name = "filter"; +/*----------------------------------------------------------------------------*/ +/*The version of the server*/ +char * netfs_server_version = "0.0"; +/*----------------------------------------------------------------------------*/ +/*The maximal length of a chain of symbolic links*/ +int netfs_maxsymlinks = 12; +/*----------------------------------------------------------------------------*/ +/*A port to the underlying node*/ +mach_port_t underlying_node; +/*----------------------------------------------------------------------------*/ +/*Status information for the underlying node*/ +io_statbuf_t underlying_node_stat; +/*----------------------------------------------------------------------------*/ +/*Mapped time used for updating node information*/ +volatile struct mapped_time_value * maptime; +/*----------------------------------------------------------------------------*/ +/*The filesystem ID*/ +pid_t fsid; +/*----------------------------------------------------------------------------*/ +/*The port from which we will read (TODO: and write) the data*/ +mach_port_t target; +/*----------------------------------------------------------------------------*/ +/*The file to print debug messages to*/ +FILE * filter_dbg; +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/*--------Functions-----------------------------------------------------------*/ +/*Attempts to create a file named `name` in `dir` for `user` with mode `mode`*/ +error_t +netfs_attempt_create_file + ( + struct iouser * user, + struct node * dir, + char * name, + mode_t mode, + struct node ** node + ) + { + LOG_MSG("netfs_attempt_create_file"); + + /*Unlock `dir` and say that we can do nothing else here*/ + mutex_unlock(&dir->lock); + return EOPNOTSUPP; + }/*netfs_attempt_create_file*/ +/*----------------------------------------------------------------------------*/ +/*Return an error if the process of opening a file should not be allowed + to complete because of insufficient permissions*/ +error_t +netfs_check_open_permissions + ( + struct iouser * user, + struct node * np, + int flags, + int newnode + ) + { + LOG_MSG("netfs_check_open_permissions"); + + 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; + }/*netfs_check_open_permissions*/ +/*----------------------------------------------------------------------------*/ +/*Attempts an utimes call for the user `cred` on node `node`*/ +error_t +netfs_attempt_utimes + ( + struct iouser * cred, + struct node * node, + struct timespec * atime, + struct timespec * mtime + ) + { + LOG_MSG("netfs_attempt_utimes"); + + error_t err = 0; + + /*See what information is to be updated*/ + int flags = TOUCH_CTIME; + + /*Check if the user is indeed the owner of the node*/ + err = fshelp_isowner(&node->nn_stat, cred); + + /*If the user is allowed to do utimes*/ + if(!err) + { + /*If atime is to be updated*/ + if(atime) + /*update the atime*/ + node->nn_stat.st_atim = *atime; + else + /*the current time will be set as the atime*/ + flags |= TOUCH_ATIME; + + /*If mtime is to be updated*/ + if(mtime) + /*update the mtime*/ + node->nn_stat.st_mtim = *mtime; + else + /*the current time will be set as mtime*/ + flags |= TOUCH_MTIME; + + /*touch the file*/ + fshelp_touch(&node->nn_stat, flags, maptime); + } + + /*Return the result of operations*/ + return err; + }/*netfs_attempt_utimes*/ +/*----------------------------------------------------------------------------*/ +/*Returns the valid access types for file `node` and user `cred`*/ +error_t +netfs_report_access + ( + struct iouser * cred, + struct node * np, + int * types + ) + { + LOG_MSG("netfs_report_access"); + + /*No access at first*/ + *types = 0; + + /*Check the access and set the required bits*/ + if(fshelp_access(&np->nn_stat, S_IREAD, cred) == 0) + *types |= O_READ; + if(fshelp_access(&np->nn_stat, S_IWRITE, cred) == 0) + *types |= O_WRITE; + if(fshelp_access(&np->nn_stat, S_IEXEC, cred) == 0) + *types |= O_EXEC; + + /*Everything OK*/ + return 0; + }/*netfs_report_access*/ +/*----------------------------------------------------------------------------*/ +/*Validates the stat data for the node*/ +error_t +netfs_validate_stat + ( + struct node * np, + struct iouser * cred + ) + { + LOG_MSG("netfs_validate_stat"); + + error_t err = 0; + + /*Validate the stat information about the node*/ + err = io_stat(np->nn->port, &np->nn_stat); + + /*Return the result of operations*/ + return err; + }/*netfs_validate_stat*/ +/*----------------------------------------------------------------------------*/ +/*Syncs `node` completely to disk*/ +error_t +netfs_attempt_sync + ( + struct iouser * cred, + struct node * node, + int wait + ) + { + LOG_MSG("netfs_attempt_sync"); + + /*Operation is not supported*/ + return EOPNOTSUPP; + }/*netfs_attempt_sync*/ +/*----------------------------------------------------------------------------*/ +/*Fetches a directory*/ +error_t +netfs_get_dirents + ( + struct iouser * cred, + struct node * dir, + int first_entry, + int num_entries, + char ** data, + mach_msg_type_number_t * data_len, + vm_size_t max_data_len, + int * data_entries + ) + { + LOG_MSG("netfs_get_dirents"); + + /*This node is not a directory*/ + return ENOTDIR; + }/*netfs_get_dirents*/ +/*----------------------------------------------------------------------------*/ +/*Looks up `name` under `dir` for `user`*/ +error_t +netfs_attempt_lookup + ( + struct iouser * user, + struct node * dir, + char * name, + struct node ** node + ) + { + LOG_MSG("netfs_attempt_lookup: '%s'", name); + + /*Unlock the mutexes in `dir`*/ + mutex_unlock(&dir->lock); + return EOPNOTSUPP; + }/*netfs_attempt_lookup*/ +/*----------------------------------------------------------------------------*/ +/*Deletes `name` in `dir` for `user`*/ +error_t +netfs_attempt_unlink + ( + struct iouser * user, + struct node * dir, + char * name + ) + { + LOG_MSG("netfs_attempt_unlink"); + + return 0; + }/*netfs_attempt_unlink*/ +/*----------------------------------------------------------------------------*/ +/*Attempts to rename `fromdir`/`fromname` to `todir`/`toname`*/ +error_t +netfs_attempt_rename + ( + struct iouser * user, + struct node * fromdir, + char * fromname, + struct node * todir, + char * toname, + int excl + ) + { + LOG_MSG("netfs_attempt_rename"); + + /*Operation not supported*/ + return EOPNOTSUPP; + }/*netfs_attempt_rename*/ +/*----------------------------------------------------------------------------*/ +/*Attempts to create a new directory*/ +error_t +netfs_attempt_mkdir + ( + struct iouser * user, + struct node * dir, + char * name, + mode_t mode + ) + { + LOG_MSG("netfs_attempt_mkdir"); + + return 0; + }/*netfs_attempt_mkdir*/ +/*----------------------------------------------------------------------------*/ +/*Attempts to remove directory `name` in `dir` for `user`*/ +error_t +netfs_attempt_rmdir + ( + struct iouser * user, + struct node * dir, + char * name + ) + { + LOG_MSG("netfs_attempt_rmdir"); + + return 0; + }/*netfs_attempt_rmdir*/ +/*----------------------------------------------------------------------------*/ +/*Attempts to change the mode of `node` for user `cred` to `uid`:`gid`*/ +error_t +netfs_attempt_chown + ( + struct iouser * cred, + struct node * node, + uid_t uid, + uid_t gid + ) + { + LOG_MSG("netfs_attempt_chown"); + + /*Operation is not supported*/ + return EOPNOTSUPP; + }/*netfs_attempt_chown*/ +/*----------------------------------------------------------------------------*/ +/*Attempts to change the author of `node` to `author`*/ +error_t +netfs_attempt_chauthor + ( + struct iouser * cred, + struct node * node, + uid_t author + ) + { + LOG_MSG("netfs_attempt_chauthor"); + + /*Operation is not supported*/ + return EOPNOTSUPP; + }/*netfs_attempt_chauthor*/ +/*----------------------------------------------------------------------------*/ +/*Attempts to change the mode of `node` to `mode` for `cred`*/ +error_t +netfs_attempt_chmod + ( + struct iouser * user, + struct node * node, + mode_t mode + ) + { + LOG_MSG("netfs_attempt_chmod"); + + /*Operation is not supported*/ + return EOPNOTSUPP; + }/*netfs_attempt_chmod*/ +/*----------------------------------------------------------------------------*/ +/*Attempts to turn `node` into a symlink targetting `name`*/ +error_t +netfs_attempt_mksymlink + ( + struct iouser * cred, + struct node * node, + char * name + ) + { + LOG_MSG("netfs_attempt_mksymlink"); + + /*Operation is not supported*/ + return EOPNOTSUPP; + }/*netfs_attempt_mksymlink*/ +/*----------------------------------------------------------------------------*/ +/*Attempts to turn `node` into a device; type can be either S_IFBLK or S_IFCHR*/ +error_t +netfs_attempt_mkdev + ( + struct iouser * cred, + struct node * node, + mode_t type, + dev_t indexes + ) + { + LOG_MSG("netfs_attempt_mkdev"); + + /*Operation is not supported*/ + return EOPNOTSUPP; + }/*netfs_attempt_mkdev*/ +/*----------------------------------------------------------------------------*/ +/*Attempts to set the passive translator record for `file` passing `argz`*/ +error_t +netfs_set_translator + ( + struct iouser * cred, + struct node * node, + char * argz, + size_t arglen + ) + { + LOG_MSG("netfs_set_translator"); + + /*Operation is not supported*/ + return EOPNOTSUPP; + }/*netfs_set_translator */ +/*----------------------------------------------------------------------------*/ +/*Attempts to call chflags for `node`*/ +error_t +netfs_attempt_chflags + ( + struct iouser * cred, + struct node * node, + int flags + ) + { + LOG_MSG("netfs_attempt_chflags"); + + /*Operation is not supported*/ + return EOPNOTSUPP; + }/*netfs_attempt_chflags*/ +/*----------------------------------------------------------------------------*/ +/*Attempts to set the size of file `node`*/ +error_t +netfs_attempt_set_size + ( + struct iouser * cred, + struct node * node, + loff_t size + ) + { + LOG_MSG("netfs_attempt_set_size"); + + /*Operation is not supported*/ + return EOPNOTSUPP; + }/*netfs_attempt_set_size*/ +/*----------------------------------------------------------------------------*/ +/*Fetches the filesystem status information*/ +error_t +netfs_attempt_statfs + ( + struct iouser * cred, + struct node * node, + fsys_statfsbuf_t * st + ) + { + LOG_MSG("netfs_attempt_statfs"); + + /*Operation is not supported*/ + return EOPNOTSUPP; + }/*netfs_attempt_statfs*/ +/*----------------------------------------------------------------------------*/ +/*Syncs the filesystem*/ +error_t +netfs_attempt_syncfs + ( + struct iouser * cred, + int wait + ) + { + LOG_MSG("netfs_attempt_syncfs"); + + /*Everythin OK*/ + return 0; + }/*netfs_attempt_syncfs*/ +/*----------------------------------------------------------------------------*/ +/*Creates a link in `dir` with `name` to `file`*/ +error_t +netfs_attempt_link + ( + struct iouser * user, + struct node * dir, + struct node * file, + char * name, + int excl + ) + { + LOG_MSG("netfs_attempt_link"); + + /*Operation not supported*/ + return EOPNOTSUPP; + }/*netfs_attempt_link*/ +/*----------------------------------------------------------------------------*/ +/*Attempts to create an anonymous file related to `dir` with `mode`*/ +error_t +netfs_attempt_mkfile + ( + struct iouser * user, + struct node * dir, + mode_t mode, + struct node ** node + ) + { + LOG_MSG("netfs_attempt_mkfile"); + + /*Unlock the directory*/ + mutex_unlock(&dir->lock); + + /*Operation not supported*/ + return EOPNOTSUPP; + }/*netfs_attempt_mkfile*/ +/*----------------------------------------------------------------------------*/ +/*Reads the contents of symlink `node` into `buf`*/ +error_t +netfs_attempt_readlink + ( + struct iouser * user, + struct node * node, + char * buf + ) + { + LOG_MSG("netfs_attempt_readlink"); + + /*Operation not supported (why?..)*/ + return EOPNOTSUPP; + }/*netfs_attempt_readlink*/ +/*----------------------------------------------------------------------------*/ +/*Reads from file `node` up to `len` bytes from `offset` into `data`*/ +error_t +netfs_attempt_read + ( + struct iouser * cred, + struct node * np, + loff_t offset, + size_t * len, + void * data + ) + { + LOG_MSG("netfs_attempt_read"); + + error_t err = 0; + + /*Obtain a pointer to the first byte of the supplied buffer*/ + char * buf = data; + + /*Try to read the requested information from the file*/ + err = io_read(np->nn->port, &buf, len, offset, *len); + + /*If some data has been read successfully*/ + if(!err && (buf != data)) + { + /*copy the data from the buffer into which it has just been read into + the supplied receiver*/ + memcpy(data, buf, *len); + + /*unmap the new buffer*/ + munmap(buf, *len); + } + + /*Return the result of reading*/ + return err; + }/*netfs_attempt_read*/ +/*----------------------------------------------------------------------------*/ +/*Writes to file `node` up to `len` bytes from offset from `data`*/ +error_t +netfs_attempt_write + ( + struct iouser * cred, + struct node * node, + loff_t offset, + size_t * len, + void * data + ) + { + LOG_MSG("netfs_attempt_write"); + + return 0; + }/*netfs_attempt_write*/ +/*----------------------------------------------------------------------------*/ +/*Frees all storage associated with the node*/ +void +netfs_node_norefs + ( + struct node * np + ) + { + /*Destroy the node*/ + node_destroy(np); + }/*netfs_node_norefs*/ +/*----------------------------------------------------------------------------*/ +/*Implements file_get_translator_cntl as described in <hurd/fs.defs> + (according to diskfs_S_file_get_translator_cntl)*/ +kern_return_t +netfs_S_file_get_translator_cntl + ( + struct protid * user, + mach_port_t * cntl, + mach_msg_type_name_t * cntltype + ) + { + /*If the information about the user is missing*/ + if(!user) + return EOPNOTSUPP; + + error_t err = 0; + + /*Obtain the node for which we are called*/ + node_t * np = user->po->np; + + /*Lock the node*/ + mutex_lock(&np->lock); + + /*Check if the user is the owner of this node*/ + err = fshelp_isowner(&np->nn_stat, user->user); + + /*If no errors have happened*/ + if(!err) + /*try to fetch the control port*/ + err = fshelp_fetch_control(&np->transbox, cntl); + + /*If no errors have occurred, but no port has been returned*/ + if(!err && (cntl == MACH_PORT_NULL)) + /*set the error accordingly*/ + err = ENXIO; + + /*If no errors have occurred so far*/ + if(!err) + /*set the control port type*/ + *cntltype = MACH_MSG_TYPE_MOVE_SEND; + + /*Unlock the node*/ + mutex_unlock(&np->lock); + + /*Return the result of operations*/ + return err; + }/*netfs_S_file_get_translator_cntl*/ +/*----------------------------------------------------------------------------*/ +int +netfs_demuxer + ( + mach_msg_header_t * ing, + mach_msg_header_t * outp + ); +/*----------------------------------------------------------------------------*/ +/*Entry point*/ +int +main + ( + int argc, + char ** argv + ) + { + /*Start logging*/ + INIT_LOG(); + LOG_MSG(">> Starting initialization..."); + + /*The port on which this translator will be set upon*/ + mach_port_t bootstrap_port; + + error_t err = 0; + + /*Parse the command line arguments*/ + argp_parse(&argp_startup, argc, argv, ARGP_IN_ORDER, 0, 0); + LOG_MSG("Command line arguments parsed."); + + /*Try to create the root node*/ + err = node_create_root(&netfs_root_node); + if(err) + error(EXIT_FAILURE, err, "Failed to create the root node"); + LOG_MSG("Root node created."); + + /*Obtain the bootstrap port*/ + task_get_bootstrap_port(mach_task_self(), &bootstrap_port); + + /*Initialize the translator*/ + netfs_init(); + + /*Obtain a port to the underlying node opened as O_NOTRANS*/ + underlying_node = netfs_startup(bootstrap_port, O_READ | O_NOTRANS); + LOG_MSG("netfs initialization complete."); + + /*Initialize the root node*/ + err = node_init_root(underlying_node, netfs_root_node); + if(err) + error(EXIT_FAILURE, err, "Failed to initialize the root node"); + LOG_MSG("Root node initialized."); + LOG_MSG("\tRoot node address: 0x%lX", (unsigned long)netfs_root_node); + + /*Map the time for updating node information*/ + err = maptime_map(0, 0, &maptime); + if(err) + error(EXIT_FAILURE, err, "Failed to map the time"); + LOG_MSG("Time mapped."); + + /*Obtain stat information about the underlying node*/ + err = io_stat(underlying_node, &underlying_node_stat); + if(err) + error(EXIT_FAILURE, err, + "Cannot obtain stat information about the underlying node"); + LOG_MSG("Stat information for undelying node obtained."); + + /*Obtain the ID of the current process*/ + fsid = getpid(); + + /*Setup the stat information for the root node*/ + netfs_root_node->nn_stat = underlying_node_stat; + + netfs_root_node->nn_stat.st_ino = FILTER_ROOT_INODE; + netfs_root_node->nn_stat.st_fsid = fsid; + netfs_root_node->nn_stat.st_mode = underlying_node_stat.st_mode; + + netfs_root_node->nn_translated = netfs_root_node->nn_stat.st_mode; + + /*Filter the translator stack under ourselves*/ + err = trace_find(underlying_node, "/hurd/m", O_READ, &target); + if(err) + error + ( + EXIT_FAILURE, err, + "Could not trace the translator stack on the underlying node" + ); + + netfs_root_node->nn->port = target; + + /*Update the timestamps of the root node*/ + fshelp_touch + (&netfs_root_node->nn_stat, TOUCH_ATIME | TOUCH_MTIME | TOUCH_CTIME, + maptime); + + LOG_MSG(">> Initialization complete. Entering netfs server loop..."); + + /*Start serving clients*/ + for(;;) + netfs_server_loop(); + }/*main*/ +/*----------------------------------------------------------------------------*/ diff --git a/filter.h b/filter.h new file mode 100644 index 000000000..6dc9a69dc --- /dev/null +++ b/filter.h @@ -0,0 +1,348 @@ +/*----------------------------------------------------------------------------*/ +/*filter.h*/ +/*----------------------------------------------------------------------------*/ +/*The definitions for the filtering translator*/ +/*----------------------------------------------------------------------------*/ +/*Based on the code of unionfs translator.*/ +/*----------------------------------------------------------------------------*/ +/*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 + 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.*/ +/*----------------------------------------------------------------------------*/ +#ifndef __FILTER_H__ +#define __FILTER_H__ +/*----------------------------------------------------------------------------*/ +#include <stddef.h> +#include <stdlib.h> +#include <cthreads.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/statfs.h> +#include <sys/time.h> +#include <hurd/ihash.h> +#include <hurd/iohelp.h> +/*----------------------------------------------------------------------------*/ +#include "node.h" +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/*--------Macros--------------------------------------------------------------*/ +/*The inode for the root node*/ +#define FILTER_ROOT_INODE 1 +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/*--------Global Variables----------------------------------------------------*/ +/*A mapped time value*/ +/*Required for a very fast access to time*/ +extern volatile struct mapped_time_value * maptime; +/*----------------------------------------------------------------------------*/ +/*A port to the underlying node*/ +extern mach_port_t underlying_node; +/*----------------------------------------------------------------------------*/ +/*The stat information about the underlying node*/ +extern io_statbuf_t underlying_node_stat; +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/*--------Functions-----------------------------------------------------------*/ +/*Attempts to create a file named `name` in `dir` for `user` with mode `mode`*/ +error_t +netfs_attempt_create_file + ( + struct iouser * user, + struct node * dir, + char * name, + mode_t mode, + struct node ** node + ); +/*----------------------------------------------------------------------------*/ +/*Returns an error if the process of opening a file should not be allowed + to complete because of insufficient permissions*/ +error_t +netfs_check_open_permissions + ( + struct iouser * user, + struct node * np, + int flags, + int newnode + ); +/*----------------------------------------------------------------------------*/ +/*Attempts an utimes call for the user `cred` on node `node`*/ +error_t +netfs_attempt_utimes + ( + struct iouser * cred, + struct node * node, + struct timespec * atime, + struct timespec * mtime + ); +/*----------------------------------------------------------------------------*/ +/*Returns the valid access types for file `node` and user `cred`*/ +error_t +netfs_report_access + ( + struct iouser * cred, + struct node * np, + int * types + ); +/*----------------------------------------------------------------------------*/ +/*Validates the stat data for the node*/ +error_t +netfs_validate_stat + ( + struct node * np, + struct iouser * cred + ); +/*----------------------------------------------------------------------------*/ +/*Syncs `node` completely to disk*/ +error_t +netfs_attempt_sync + ( + struct iouser * cred, + struct node * node, + int wait + ); +/*----------------------------------------------------------------------------*/ +/*Fetches a directory*/ +error_t +netfs_get_dirents + ( + struct iouser * cred, + struct node * dir, + int first_entry, + int num_entries, + char ** data, + mach_msg_type_number_t * data_len, + vm_size_t max_data_len, + int * data_entries + ); +/*----------------------------------------------------------------------------*/ +/*Looks up `name` under `dir` for `user`*/ +error_t +netfs_attempt_lookup + ( + struct iouser * user, + struct node * dir, + char * name, + struct node ** node + ); +/*----------------------------------------------------------------------------*/ +/*Deletes `name` in `dir` for `user`*/ +error_t +netfs_attempt_unlink + ( + struct iouser * user, + struct node * dir, + char * name + ); +/*----------------------------------------------------------------------------*/ +/*Attempts to rename `fromdir`/`fromname` to `todir`/`toname`*/ +error_t +netfs_attempt_rename + ( + struct iouser * user, + struct node * fromdir, + char * fromname, + struct node * todir, + char * toname, + int excl + ); +/*----------------------------------------------------------------------------*/ +/*Attempts to create a new directory*/ +error_t +netfs_attempt_mkdir + ( + struct iouser * user, + struct node * dir, + char * name, + mode_t mode + ); +/*----------------------------------------------------------------------------*/ +/*Attempts to remove directory `name` in `dir` for `user`*/ +error_t +netfs_attempt_rmdir + ( + struct iouser * user, + struct node * dir, + char * name + ); +/*----------------------------------------------------------------------------*/ +/*Attempts to change the owner of `node` for user `cred` to `uid`:`gid`*/ +error_t +netfs_attempt_chown + ( + struct iouser * cred, + struct node * node, + uid_t uid, + uid_t gid + ); +/*----------------------------------------------------------------------------*/ +/*Attempts to change the author of `node` to `author`*/ +error_t +netfs_attempt_chauthor + ( + struct iouser * cred, + struct node * node, + uid_t author + ); +/*----------------------------------------------------------------------------*/ +/*Attempts to change the mode of `node` to `mode` for `cred`*/ +error_t +netfs_attempt_chmod + ( + struct iouser * user, + struct node * node, + mode_t mode + ); +/*----------------------------------------------------------------------------*/ +/*Attempts to turn `node` into a symlink targetting `name`*/ +error_t +netfs_attempt_mksymlink + ( + struct iouser * cred, + struct node * node, + char * name + ); +/*----------------------------------------------------------------------------*/ +/*Attempts to turn `node` into a device; type can be either S_IFBLK or S_IFCHR*/ +error_t +netfs_attempt_mkdev + ( + struct iouser * cred, + struct node * node, + mode_t type, + dev_t indexes + ); +/*----------------------------------------------------------------------------*/ +/*Attempts to set the passive translator record for `file` passing `argz`*/ +error_t +netfs_set_translator + ( + struct iouser * cred, + struct node * node, + char * argz, + size_t arglen + ); +/*----------------------------------------------------------------------------*/ +/*Attempts to call chflags for `node`*/ +error_t +netfs_attempt_chflags + ( + struct iouser * cred, + struct node * node, + int flags + ); +/*----------------------------------------------------------------------------*/ +/*Attempts to set the size of file `node`*/ +error_t +netfs_attempt_set_size + ( + struct iouser * cred, + struct node * node, + loff_t size + ); +/*----------------------------------------------------------------------------*/ +/*Fetches the filesystem status information*/ +error_t +netfs_attempt_statfs + ( + struct iouser * cred, + struct node * node, + fsys_statfsbuf_t * st + ); +/*----------------------------------------------------------------------------*/ +/*Syncs the filesystem*/ +error_t +netfs_attempt_syncfs + ( + struct iouser * cred, + int wait + ); +/*----------------------------------------------------------------------------*/ +/*Creates a link in `dir` with `name` to `file`*/ +error_t +netfs_attempt_link + ( + struct iouser * user, + struct node * dir, + struct node * file, + char * name, + int excl + ); +/*----------------------------------------------------------------------------*/ +/*Attempts to create an anonymous file related to `dir` with `mode`*/ +error_t +netfs_attempt_mkfile + ( + struct iouser * user, + struct node * dir, + mode_t mode, + struct node ** node + ); +/*----------------------------------------------------------------------------*/ +/*Reads the contents of symlink `node` into `buf`*/ +error_t +netfs_attempt_readlink + ( + struct iouser * user, + struct node * node, + char * buf + ); +/*----------------------------------------------------------------------------*/ +/*Reads from file `node` up to `len` bytes from `offset` into `data`*/ +error_t +netfs_attempt_read + ( + struct iouser * cred, + struct node * np, + loff_t offset, + size_t * len, + void * data + ); +/*----------------------------------------------------------------------------*/ +/*Writes to file `node` up to `len` bytes from offset from `data`*/ +error_t +netfs_attempt_write + ( + struct iouser * cred, + struct node * node, + loff_t offset, + size_t * len, + void * data + ); +/*----------------------------------------------------------------------------*/ +/*Frees all storage associated with the node*/ +void +netfs_node_norefs + ( + struct node * np + ); +/*----------------------------------------------------------------------------*/ +/*Implements file_get_translator_cntl as described in <hurd/fs.defs> + (according to diskfs_S_file_get_translator_cntl)*/ +kern_return_t +netfs_S_file_get_translator_cntl + ( + struct protid * user, + mach_port_t * cntl, + mach_msg_type_name_t * cntltype + ); +/*----------------------------------------------------------------------------*/ +#endif /*__FILTER_H__*/ @@ -0,0 +1,166 @@ +/*----------------------------------------------------------------------------*/ +/*node.c*/ +/*----------------------------------------------------------------------------*/ +/*Implementation of node management strategies*/ +/*----------------------------------------------------------------------------*/ +/*Based on the code of unionfs translator.*/ +/*----------------------------------------------------------------------------*/ +/*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 + 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 "filter.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 + ( + 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; + } + + /*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 + ) + { + /*Destroy the port to the underlying filesystem allocated to the node*/ + PORT_DEALLOC(np->nn->port); + + /*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*/ + ) + { + error_t err; + + /*Try to create a node*/ + node_t * node; + err = node_create(&node); + if(err) + return err; + + /*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 + ( + mach_port_t underlying, /*the port to the underlying node*/ + node_t * node /*the root node*/ + ) + { + error_t err = 0; + + /*Acquire a lock for operations on the underlying filesystem*/ + mutex_lock(&ulfs_lock); + + /*Store the specified port in the node*/ + node->nn->port = underlying; + + LOG_MSG("node_init_root: Port: 0x%ld", (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; + } + + /*Release the lock for operations on the undelying filesystem*/ + mutex_unlock(&ulfs_lock); + + /*Return the result of operations*/ + return err; + }/*node_init_root*/ +/*----------------------------------------------------------------------------*/ @@ -0,0 +1,114 @@ +/*----------------------------------------------------------------------------*/ +/*node.h*/ +/*----------------------------------------------------------------------------*/ +/*Node management. Also see lnode.h*/ +/*----------------------------------------------------------------------------*/ +/*Based on the code of unionfs translator.*/ +/*----------------------------------------------------------------------------*/ +/*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 + 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.*/ +/*----------------------------------------------------------------------------*/ +#ifndef __NODE_H__ +#define __NODE_H__ + +/*----------------------------------------------------------------------------*/ +#include <error.h> +#include <sys/stat.h> +#include <hurd/netfs.h> +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/*--------Macros--------------------------------------------------------------*/ +/*Checks whether the give node is the root of the filterfs filesystem*/ +#define NODE_IS_ROOT(n) (((n)->nn->lnode->dir) ? (0) : (1)) +/*----------------------------------------------------------------------------*/ +/*Node flags*/ +#define FLAG_NODE_ULFS_FIXED 0x00000001 /*this node should not be updated*/ +#define FLAG_NODE_INVALIDATE 0x00000002 /*this node must be updated*/ +#define FLAG_NODE_ULFS_UPTODATE 0x00000004 /*this node has just been updated*/ +/*----------------------------------------------------------------------------*/ +/*The type of offset corresponding to the current platform*/ +#ifdef __USE_FILE_OFFSET64 +# define OFFSET_T __off64_t +#else +# 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 +/*----------------------------------------------------------------------------*/ +/*Deallocates the specified port*/ +#define PORT_DEALLOC(p) (mach_port_deallocate(mach_task_self(), (p))) +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/*The user-defined node for libnetfs*/ +struct netnode + { + /*the flags associated with this node (might be not required)*/ + int flags; + + /*a port to the underlying filesystem*/ + file_t port; + };/*struct netnode*/ +/*----------------------------------------------------------------------------*/ +typedef struct netnode netnode_t; +/*----------------------------------------------------------------------------*/ +typedef struct node node_t; +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/*--------Global Variables----------------------------------------------------*/ +/*The lock protecting the underlying filesystem*/ +extern struct mutex ulfs_lock; +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/*--------Functions-----------------------------------------------------------*/ +/*Derives a new node from `lnode` and adds a reference to `lnode`*/ +error_t +node_create + ( + node_t ** node /*store the result here*/ + ); +/*----------------------------------------------------------------------------*/ +/*Destroys the specified node and removes a light reference from the + associated light node*/ +void +node_destroy + ( + node_t * np + ); +/*----------------------------------------------------------------------------*/ +/*Creates the root node and the corresponding lnode*/ +error_t +node_create_root + ( + node_t ** root_node /*store the result here*/ + ); +/*----------------------------------------------------------------------------*/ +/*Initializes the port to the underlying filesystem for the root node*/ +error_t +node_init_root + ( + mach_port_t underlying, /*the port to the underlying node*/ + node_t * node /*the root node*/ + ); +/*----------------------------------------------------------------------------*/ +#endif /*__NODE_H__*/ diff --git a/options.c b/options.c new file mode 100644 index 000000000..736a8589a --- /dev/null +++ b/options.c @@ -0,0 +1,190 @@ +/*----------------------------------------------------------------------------*/ +/*options.h*/ +/*----------------------------------------------------------------------------*/ +/*Definitions for parsing the command line switches*/ +/*----------------------------------------------------------------------------*/ +/*Based on the code of unionfs translator.*/ +/*----------------------------------------------------------------------------*/ +/*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 + 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 <argp.h> +#include <error.h> +/*----------------------------------------------------------------------------*/ +#include "debug.h" +#include "options.h" +#include "node.h" +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/*--------Macros--------------------------------------------------------------*/ +/*Short documentation for argp*/ +#define ARGS_DOC "" +#define DOC "Filters the translator stack of the node it is set upon." +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/*--------Forward Declarations------------------------------------------------*/ +/*Argp parser function for the common options*/ +static +error_t +argp_parse_common_options + ( + int key, + char * arg, + struct argp_state * state + ); +/*----------------------------------------------------------------------------*/ +/*Argp parser function for the startup options*/ +static +error_t +argp_parse_startup_options + ( + int key, + char * arg, + struct argp_state * state + ); +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/*--------Global Variables----------------------------------------------------*/ +/*This variable is set to a non-zero value after the parsing of starup options + is finished*/ +static int parsing_startup_options_finished; +/*----------------------------------------------------------------------------*/ +/*Argp options common to both the runtime and the startup parser*/ +static const struct argp_option argp_common_options[] = + { + {0} + }; +/*----------------------------------------------------------------------------*/ +/*Argp options only meaningful for startupp parsing*/ +static const struct argp_option argp_startup_options[] = + { + {0} + }; +/*----------------------------------------------------------------------------*/ +/*Argp parser for only the common options*/ +static const struct argp argp_parser_common_options = + {argp_common_options, argp_parse_common_options, 0, 0, 0}; +/*----------------------------------------------------------------------------*/ +/*Argp parser for only the startup options*/ +static const struct argp argp_parser_startup_options = + {argp_startup_options, argp_parse_startup_options, 0, 0, 0}; +/*----------------------------------------------------------------------------*/ +/*The list of children parsers for runtime arguments*/ +static const struct argp_child argp_children_runtime[] = + { + {&argp_parser_common_options}, + {&netfs_std_runtime_argp}, + {0} + }; +/*----------------------------------------------------------------------------*/ +/*The list of children parsers for startup arguments*/ +static const struct argp_child argp_children_startup[] = + { + {&argp_parser_startup_options}, + {&argp_parser_common_options}, + {&netfs_std_startup_argp}, + {0} + }; +/*----------------------------------------------------------------------------*/ +/*The version of the server for argp*/ +const char * argp_program_version = "0.0"; +/*----------------------------------------------------------------------------*/ +/*The arpg parser for runtime arguments*/ +struct argp argp_runtime = + {0, 0, 0, 0, argp_children_runtime}; +/*----------------------------------------------------------------------------*/ +/*The argp parser for startup arguments*/ +struct argp argp_startup = + {0, 0, ARGS_DOC, DOC, argp_children_startup}; +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/*--------Functions-----------------------------------------------------------*/ +/*Argp parser function for the common options*/ +static +error_t +argp_parse_common_options + ( + int key, + char * arg, + struct argp_state * state + ) + { + error_t err = 0; + + /*Go through the possible options*/ + switch(key) + { + case ARGP_KEY_END: + { + /*If parsing of startup options has not finished*/ + if(!parsing_startup_options_finished) + { + /*set the flag that the startup options have already been parsed*/ + parsing_startup_options_finished = 1; + } + else + { +/*TODO: Take care of runtime calls modifying the property*/ + } + } + /*If the option could not be recognized*/ + default: + { + /*set the error code*/ + err = ARGP_ERR_UNKNOWN; + } + } + + /*Return the result*/ + return err; + }/*argp_parse_common_options*/ +/*----------------------------------------------------------------------------*/ +/*Argp parser function for the startup options*/ +static +error_t +argp_parse_startup_options + ( + int key, + char * arg, + struct argp_state * state + ) + { + /*Do nothing in a beautiful way*/ + error_t err = 0; + + switch(key) + { + default: + { + err = ARGP_ERR_UNKNOWN; + + break; + } + } + + return err; + }/*argp_parse_startup_options*/ +/*----------------------------------------------------------------------------*/ diff --git a/options.h b/options.h new file mode 100644 index 000000000..1db2f655f --- /dev/null +++ b/options.h @@ -0,0 +1,44 @@ +/*----------------------------------------------------------------------------*/ +/*options.h*/ +/*----------------------------------------------------------------------------*/ +/*Declarations for parsing the command line switches*/ +/*----------------------------------------------------------------------------*/ +/*Based on the code of unionfs translator.*/ +/*----------------------------------------------------------------------------*/ +/*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 + 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.*/ +/*----------------------------------------------------------------------------*/ +#ifndef __OPTIONS_H__ +#define __OPTIONS_H__ + +/*----------------------------------------------------------------------------*/ +/*--------Macros--------------------------------------------------------------*/ +/*Makes a long option out of option name*/ +#define OPT_LONG(o) "--"o +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/*--------Global Variables----------------------------------------------------*/ +/*The argp parser for startup arguments*/ +extern struct argp argp_startup; +/*----------------------------------------------------------------------------*/ +/*The argp parser for rutime arguments*/ +extern struct argp argp_runtime; +/*----------------------------------------------------------------------------*/ +#endif /*__OPTIONS_H__*/ |