diff options
author | Sergiu Ivanov <unlimitedscolobb@gmail.com> | 2008-07-13 20:26:34 +0300 |
---|---|---|
committer | Sergiu Ivanov <unlimitedscolobb@gmail.com> | 2008-07-13 20:26:34 +0300 |
commit | c9c70745fbdb4be82796f94e5601109d9071bb46 (patch) | |
tree | b0ec5e62a5f9ee77bc7f52f90a4bba47e74448a7 /nsmux.c |
Copied the skeleton for mirroring a directory from filterfs.
At the moment nsmux is only capable of creating a read-only
mirror of the given directory.
Diffstat (limited to 'nsmux.c')
-rw-r--r-- | nsmux.c | 1122 |
1 files changed, 1122 insertions, 0 deletions
diff --git a/nsmux.c b/nsmux.c new file mode 100644 index 000000000..8f068f2e1 --- /dev/null +++ b/nsmux.c @@ -0,0 +1,1122 @@ +/*----------------------------------------------------------------------------*/ +/*nsmux.c*/ +/*----------------------------------------------------------------------------*/ +/*The filesystem proxy for namespace-based translator selection.*/ +/*----------------------------------------------------------------------------*/ +/*Based on the code of unionfs translator.*/ +/*----------------------------------------------------------------------------*/ +/*Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc. + Written by Sergiu Ivanov <unlimitedscolobb@gmail.com>. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or * (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA.*/ +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +#define _GNU_SOURCE 1 +/*----------------------------------------------------------------------------*/ +#include "nsmux.h" +/*----------------------------------------------------------------------------*/ +#include <error.h> +#include <argp.h> +#include <argz.h> +#include <hurd/netfs.h> +#include <fcntl.h> +/*----------------------------------------------------------------------------*/ +#include "debug.h" +#include "options.h" +#include "ncache.h" +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/*--------Macros--------------------------------------------------------------*/ +/*The state modes use in open*/ +#define OPENONLY_STATE_MODES (O_CREAT | O_EXCL | O_NOLINK | O_NOTRANS \ + | O_NONBLOCK) +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/*--------Global Variables----------------------------------------------------*/ +/*The name of the server*/ +char * netfs_server_name = "nsmux"; +/*----------------------------------------------------------------------------*/ +/*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 file to print debug messages to*/ +FILE * nsmux_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: '%s'", np->nn->lnode->name); + + 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: '%s'", np->nn->lnode->name); + + error_t err = 0; + + /*If we are not at the root*/ + if(np != netfs_root_node) + { + /*If the node is not surely up-to-date*/ + if(!(np->nn->flags & FLAG_NODE_ULFS_UPTODATE)) + { + /*update it*/ + err = node_update(np); + } + + /*If no errors have yet occurred*/ + if(!err) + { + /*If the port to the file corresponding to `np` is valid*/ + if(np->nn->port != MACH_PORT_NULL) + { + /*We have a directory here (normally, only they maintain an open port). + Generally, our only concern is to maintain an open port in this case*/ + + /*attempt to stat this file*/ + err = io_stat(np->nn->port, &np->nn_stat); + + /*If stat information has been successfully obtained for the file*/ + if(!err) + /*duplicate the st_mode field of stat structure*/ + np->nn_translated = np->nn_stat.st_mode; + } + else + { + /*We, most probably, have something which is not a directory. Therefore + we will open the port and close it after the stat, so that additional + resources are not consumed.*/ + + /*the parent node of the current node*/ + node_t * dnp; + + /*obtain the parent node of the the current node*/ + err = ncache_node_lookup(np->nn->lnode->dir, &dnp); + + /*the lookup should never fail here*/ + assert(!err); + + /*open a port to the file we are interested in*/ + mach_port_t p = file_name_lookup_under + (dnp->nn->port, np->nn->lnode->name, 0, 0); + + /*put `dnp` back, since we don't need it any more*/ + netfs_nput(dnp); + + if(!p) + return EBADF; + + /*try to stat the node*/ + err = io_stat(p, &np->nn_stat); + + /*deallocate the port*/ + PORT_DEALLOC(p); + } + } + } + /*If we are at the root*/ + else + /*put the size of the node into the stat structure belonging to `np`*/ + node_get_size(np, (OFFSET_T *)&np->nn_stat.st_size); + + /*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: '%s'", dir->nn->lnode->name); + + error_t err; + + /*Two pointers required for processing the list of dirents*/ + node_dirent_t * dirent_start, * dirent_current; + + /*The pointer to the beginning of the list of dirents*/ + node_dirent_t * dirent_list = NULL; + + /*The size of the current dirent*/ + size_t size = 0; + + /*The number of dirents added*/ + int count = 0; + + /*The dereferenced value of parameter `data`*/ + char * data_p; + + /*Takes into account the size of the given dirent*/ + int + bump_size + ( + const char * name + ) + { + /*If the required number of entries has not been listed yet*/ + if((num_entries == -1) || (count < num_entries)) + { + /*take the current size and take into account the length of the name*/ + size_t new_size = size + DIRENT_LEN(strlen(name)); + + /*If there is a limit for the received size and it has been exceeded*/ + if((max_data_len > 0) && (new_size > max_data_len)) + /*a new dirent cannot be added*/ + return 0; + + /*memorize the new size*/ + size = new_size; + + /*increase the number of dirents added*/ + ++count; + + /*everything is OK*/ + return 1; + } + else + { + /*dirents cannot be added*/ + return 0; + } + }/*bump_size*/ + + /*Adds a dirent to the list of dirents*/ + int + add_dirent + ( + const char * name, + ino_t ino, + int type + ) + { + /*If the required number of dirents has not been listed yet*/ + if((num_entries == -1) || (count < num_entries)) + { + /*create a new dirent*/ + struct dirent hdr; + + /*obtain the length of the name*/ + size_t name_len = strlen(name); + + /*compute the full size of the dirent*/ + size_t sz = DIRENT_LEN(name_len); + + /*If there is no room for this dirent*/ + if(sz > size) + /*stop*/ + return 0; + else + /*take into account the fact that a new dirent has just been added*/ + size -= sz; + + /*setup the dirent*/ + hdr.d_ino = ino; + hdr.d_reclen = sz; + hdr.d_type = type; + hdr.d_namlen = name_len; + + /*The following two lines of code reflect the old layout of + dirents in the memory. Now libnetfs expects the layout + identical to the layout provided by dir_readdir (see dir_entries_get)*/ + + /*copy the header of the dirent into the final block of dirents*/ + memcpy(data_p, &hdr, DIRENT_NAME_OFFS); + + /*copy the name of the dirent into the block of dirents*/ + strcpy(data_p + DIRENT_NAME_OFFS, name); + + /*This line is commented for the same reason as the two specifically + commented lines above.*/ + /*move the current pointer in the block of dirents*/ + data_p += sz; + + /*count the new dirent*/ + ++count; + + /*everything was OK, so say it*/ + return 1; + } + else + /*no [new] dirents allowed*/ + return 0; + }/*add_dirent*/ + + /*List the dirents for node `dir`*/ + err = node_entries_get(dir, &dirent_list); + + /*If listing was successful*/ + if(!err) + { + /*find the entry whose number is `first_entry`*/ + for + ( + dirent_start = dirent_list, count = 2; + dirent_start && (count < first_entry); + dirent_start = dirent_start->next, ++count + ); + + /*reset number of dirents added so far*/ + count = 0; + + /*make space for entries '.' and '..', if required*/ + if(first_entry == 0) + bump_size("."); + if(first_entry <= 1) + bump_size(".."); + + /*Go through all dirents*/ + for + ( + dirent_current = dirent_start; + dirent_current; + dirent_current = dirent_current->next + ) + /*If another dirent cannot be added succesfully*/ + if(bump_size(dirent_current->dirent->d_name) == 0) + /*stop here*/ + break; + + /*allocate the required space for dirents*/ + *data = mmap(0, size, PROT_READ | PROT_WRITE, MAP_ANON, 0, 0); + + /*check if any error occurred*/ + err = ((void *)*data == MAP_FAILED) ? (errno) : (0); + } + + /*If no errors have occurred so far*/ + if(!err) + { + /*obtain the pointer to the beginning of the block of dirents*/ + data_p = *data; + + /*fill the parameters with useful values*/ + *data_len = size; + *data_entries = count; + + /*reset the number of dirents added*/ + count = 0; + + /*add entries '.' and '..', if required*/ + if(first_entry == 0) + add_dirent(".", 2, DT_DIR); + if(first_entry <= 1) + add_dirent("..", 2, DT_DIR); + + /*Follow the list of dirents beginning with dirents_start*/ + for + ( + dirent_current = dirent_start; dirent_current; + dirent_current = dirent_current->next + ) + /*If the addition of the current dirent fails*/ + if + ( + add_dirent + (dirent_current->dirent->d_name, dirent_current->dirent->d_fileno, + dirent_current->dirent->d_type) == 0 + ) + /*stop adding dirents*/ + break; + } + + /*If the list of dirents has been allocated, free it*/ + if(dirent_list) + node_entries_free(dirent_list); + + /*The directory has been read right now, modify the access time*/ + fshelp_touch(&dir->nn_stat, TOUCH_ATIME, maptime); + + /*Return the result of listing the dirents*/ + return err; + }/*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); + + error_t err = 0; + + /*If we are asked to fetch the current directory*/ + if(strcmp(name, ".") == 0) + { + /*add a reference to `dir` and put it into `node`*/ + netfs_nref(dir); + *node = dir; + + /*everything is OK*/ + return 0; + } + /*If we are asked to fetch the parent directory*/ + else if(strcmp(name, "..") == 0) + { + /*If the supplied node is not root*/ + if(dir->nn->lnode->dir) + { + /*The node corresponding to the parent directory must exist here*/ + assert(dir->nn->lnode->dir->node); + + /*put the parent node of `dir` into the result*/ + err = ncache_node_lookup(dir->nn->lnode->dir, node); + } + /*The supplied node is root*/ + else + { + /*this node is not included into our filesystem*/ + err = ENOENT; + *node = NULL; + } + + /*unlock the directory*/ + mutex_unlock(&dir->lock); + + /*stop here*/ + return err; + } + + /*Try to lookup the given file in the underlying directory*/ + mach_port_t p = file_name_lookup_under(dir->nn->port, name, 0, 0); + + /*If the lookup failed*/ + if(p == MACH_PORT_NULL) + { + /*unlock the directory*/ + mutex_unlock(&dir->lock); + + /*no such entry*/ + return ENOENT; + } + + /*Obtain the stat information about the file*/ + io_statbuf_t stat; + err = io_stat(p, &stat); + + /*Deallocate the obtained port*/ + PORT_DEALLOC(p); + + /*If this file is not a directory*/ + if(err || !S_ISDIR(stat.st_mode)) + { + /*do not set the port*/ + p = MACH_PORT_NULL; + } + else + { + /*lookup the port with the right to read the contents of the directory*/ + p = file_name_lookup_under(dir->nn->port, name, O_READ | O_DIRECTORY, 0); + if(p == MACH_PORT_NULL) + { + return EBADF; /*not enough rights?*/ + } + } + + /*The lnode corresponding to the entry we are supposed to fetch*/ + lnode_t * lnode; + + /*Finalizes the execution of this function*/ + void + finalize(void) + { + /*If some errors have occurred*/ + if(err) + { + /*the user should receive nothing*/ + *node = NULL; + + /*If there is some port, free it*/ + if(p != MACH_PORT_NULL) + PORT_DEALLOC(p); + } + /*If there is a node to return*/ + if(*node) + { + /*unlock the node*/ + mutex_unlock(&(*node)->lock); + + /*add the node to the cache*/ + ncache_node_add(*node); + } + + /*Unlock the mutexes in `dir`*/ + mutex_unlock(&dir->nn->lnode->lock); + mutex_unlock(&dir->lock); + }/*finalize*/ + + /*Try to find an lnode called `name` under the lnode corresponding to `dir`*/ + err = lnode_get(dir->nn->lnode, name, &lnode); + + /*If such an entry does not exist*/ + if(err == ENOENT) + { + /*create a new lnode with the supplied name*/ + err = lnode_create(name, &lnode); + if(err) + { + finalize(); + return err; + } + + /*install the new lnode into the directory*/ + lnode_install(dir->nn->lnode, lnode); + } + + /*Obtain the node corresponding to this lnode*/ + err = ncache_node_lookup(lnode, node); + + /*Remove an extra reference from the lnode*/ + lnode_ref_remove(lnode); + + /*If the lookup in the cache failed*/ + if(err) + { + /*stop*/ + finalize(); + return err; + } + + /*Store the port in the node*/ + (*node)->nn->port = p; + + /*Construct the full path to the node*/ + err = lnode_path_construct(lnode, NULL); + if(err) + { + finalize(); + return err; + } + + /*Now the node is up-to-date*/ + (*node)->nn->flags = FLAG_NODE_ULFS_UPTODATE; + + /*Return the result of performing the operations*/ + finalize(); + return err; + }/*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; + + /*If there is no port open for the current node*/ + if(np->nn->port == MACH_PORT_NULL) + { + /*the parent node of the current node*/ + node_t * dnp; + + /*obtain the parent node of the the current node*/ + err = ncache_node_lookup(np->nn->lnode->dir, &dnp); + + /*the lookup should never fail here*/ + assert(!err); + + /*open a port to the file we are interested in*/ + mach_port_t p = file_name_lookup_under + (dnp->nn->port, np->nn->lnode->name, O_READ, 0); + + /*put `dnp` back, since we don't need it any more*/ + netfs_nput(dnp); + + if(!p) + return EBADF; + + /*store the port in the node*/ + np->nn->port = p; + } + + /*Read the required data from the file*/ + err = io_read(np->nn->port, (char **)&data, len, offset, *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*/ +/*----------------------------------------------------------------------------*/ +/*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*/ + underlying_node = netfs_startup(bootstrap_port, O_READ); + LOG_MSG("netfs initialization complete."); + + /*Initialize the root node*/ + err = node_init_root(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."); + + /*Initialize the cache with the required number of nodes*/ + ncache_init(ncache_size); + LOG_MSG("Cache initialized."); + + /*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 = NSMUX_ROOT_INODE; + netfs_root_node->nn_stat.st_fsid = fsid; + netfs_root_node->nn_stat.st_mode = S_IFDIR | (underlying_node_stat.st_mode + & ~S_IFMT & ~S_ITRANS); /*we are providing a translated directory*/ + + netfs_root_node->nn_translated = netfs_root_node->nn_stat.st_mode; + + /*If the underlying node is not a directory, enhance the permissions + of the root node of the proxy filesystem*/ + if(!S_ISDIR(underlying_node_stat.st_mode)) + { + /*can be read by owner*/ + if(underlying_node_stat.st_mode & S_IRUSR) + /*allow execution by the owner*/ + netfs_root_node->nn_stat.st_mode |= S_IXUSR; + /*can be read by group*/ + if(underlying_node_stat.st_mode & S_IRGRP) + /*allow execution by the group*/ + netfs_root_node->nn_stat.st_mode |= S_IXGRP; + /*can be read by others*/ + if(underlying_node_stat.st_mode & S_IROTH) + /*allow execution by the others*/ + netfs_root_node->nn_stat.st_mode |= S_IXOTH; + } + + /*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*/ +/*----------------------------------------------------------------------------*/ |