diff options
author | Sergiu Ivanov <unlimitedscolobb@gmail.com> | 2008-10-17 20:42:47 +0300 |
---|---|---|
committer | Sergiu Ivanov <unlimitedscolobb@gmail.com> | 2008-10-17 20:42:47 +0300 |
commit | bed243c33c3354a6fbb360eb32ee940612bb228f (patch) | |
tree | ba655b650a2928b4046eaafd1445b873bbfed589 /filter.c |
Created the most basic one-node libnetfs-based stackable translator.
The filter is going to be an ordinary translator in most
regards, save for its attitude towards the translators
sitting on the real filesystem node associated with the
mirror on which the filter is sitting (see README).
Diffstat (limited to 'filter.c')
-rw-r--r-- | filter.c | 726 |
1 files changed, 726 insertions, 0 deletions
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*/ +/*----------------------------------------------------------------------------*/ |