/*----------------------------------------------------------------------------*/ /*mangle.c*/ /*----------------------------------------------------------------------------*/ /*A simple translator which mangles the underlying file*/ /*----------------------------------------------------------------------------*/ /*Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc. Written by Sergiu Ivanov . 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 #include #include #include #include #include #include #include /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /*--------Macros--------------------------------------------------------------*/ #ifdef DEBUG # define LOG_MSG(msg, args...) {fprintf(fDbg, msg"\n", ##args); fflush(fDbg);} #else # define LOG_MSG(msg, args...) #endif /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /*--------Types---------------------------------------------------------------*/ /*Our hook for trivfs_peropen*/ struct trivfs_peropen_hook { /*The current offset*/ loff_t offs; };/*struct trivfs_peropen_hook*/ /*----------------------------------------------------------------------------*/ typedef struct trivfs_peropen_hook trivfs_peropen_hook_t; /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /*--------Forward Declarations------------------------------------------------*/ error_t mangle_peropen_create ( struct trivfs_peropen * po ); /*----------------------------------------------------------------------------*/ void mangle_peropen_destroy ( struct trivfs_peropen * po ); /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /*--------Global Variables----------------------------------------------------*/ /*The type of this server*/ int trivfs_fstype = FSTYPE_MISC; /*generic trivfs server*/ /*----------------------------------------------------------------------------*/ /*The ID of the current filesystem*/ int trivfs_fsid = 0; /*----------------------------------------------------------------------------*/ /*Type of access published by the translator*/ int trivfs_allow_open = O_READ; /*----------------------------------------------------------------------------*/ /*Actually supported access modes*/ int trivfs_support_read = 1; int trivfs_support_write = 0; int trivfs_support_exec = 0; /*----------------------------------------------------------------------------*/ /*The hooks for completing the creation and destruction of trivfs_peropen objects*/ error_t (* trivfs_peropen_create_hook)(struct trivfs_peropen *) = mangle_peropen_create; void (* trivfs_peropen_destroy_hook)(struct trivfs_peropen *) = mangle_peropen_destroy; /*----------------------------------------------------------------------------*/ /*The lock protecting the access to the file*/ static struct rwlock contents_lock; /*----------------------------------------------------------------------------*/ /*The port to the underlying node of the translator*/ mach_port_t underlying; /*----------------------------------------------------------------------------*/ #ifdef DEBUG /*The file for debug ouput*/ FILE * fDbg; #endif /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /*--------Functions-----------------------------------------------------------*/ /*Completes the inialization of a trivfs_peropen object*/ error_t mangle_peropen_create ( struct trivfs_peropen * po ) { /*Try to create a new hook*/ trivfs_peropen_hook_t * hook = malloc(sizeof(trivfs_peropen_hook_t)); if(!hook) return ENOMEM; /*Set the maintained pointer for this file to the beginning*/ hook->offs = 0; /*Store the hook in peropen*/ po->hook = hook; /*Everything OK here*/ return 0; }/*mangle_peropen_create*/ /*----------------------------------------------------------------------------*/ /*Completes the destruction of a trivfs_peropen object*/ void mangle_peropen_destroy ( struct trivfs_peropen * po ) { /*Destroy the hook, if there is any*/ if(po->hook) { free(po->hook); po->hook = NULL; } }/*mangle_peropen_destroy*/ /*----------------------------------------------------------------------------*/ /*Modifies the stat information of the underlying node*/ void trivfs_modify_stat ( struct trivfs_protid * cred, io_statbuf_t * st ) { LOG_MSG("trivfs_modify_stat"); error_t err; /*Stat the underlying node and return the result*/ err = io_stat(underlying, st); }/*trivfs_modify_stat*/ /*----------------------------------------------------------------------------*/ /*Frees the resources*/ error_t trivfs_goaway ( struct trivfs_control * cntl, int flags ) { LOG_MSG("trivfs_goaway"); /*Close the debug file*/ #ifdef DEBUG fclose(fDbg); #endif /*Die peacefully*/ exit(EXIT_SUCCESS); }/*trivfs_goaway*/ /*----------------------------------------------------------------------------*/ /*Reads the specified number of bytes from the specified offset*/ kern_return_t trivfs_S_io_read ( struct trivfs_protid * cred, mach_port_t reply, mach_msg_type_name_t reply_type, data_t * data, mach_msg_type_number_t * data_len, loff_t offs, vm_size_t amount ) { LOG_MSG("trivfs_S_io_read"); /*Stop if no credentials are specified*/ if(!cred) return EOPNOTSUPP; /*Stop if this file was not opened for reading*/ if(!(cred->po->openmodes & O_READ)) return EBADF; /*If we are not actually asked to read anything*/ if(amount <= 0) { /*read nothing and stop successfully*/ *data_len = 0; return 0; } error_t err = 0; /*Map new memory for the supplied data*/ *data = mmap(0, *data_len, PROT_READ | PROT_WRITE, MAP_ANON, 0, 0); if(*data == MAP_FAILED) return errno; /*Obtain a pointer to the hook*/ trivfs_peropen_hook_t * hook = (trivfs_peropen_hook_t *)cred->po->hook; /*The real offset of reading*/ loff_t real_offs = (offs == -1) ? (hook->offs) : (offs); /*Try to read the data from the underlying file into the supplied buffer*/ err = io_read(underlying, data, data_len, real_offs, *data_len); if(err) return err; /*If the caller did not specify an offset*/ if(offs == -1) /*compute the new cursor position in the file for this user*/ hook->offs += *data_len; /*Used in mangling the data*/ size_t i; /*If we have to mangle*/ #ifdef MANGLE /*Go through the read buffer and shift the values in the bytes forward*/ for(i = 0; i < *data_len; ++(*data)[i++]); /*If we have to demangle*/ #elif defined(DEMANGLE) /*Go through the read buffer and shift the values in the bytes backward*/ for(i = 0; i < *data_len; --(*data)[i++]); #endif /*Return success*/ return 0; }/*trivfs_S_io_read*/ /*----------------------------------------------------------------------------*/ /*Writes the specified number of bytes at the specified offset*/ kern_return_t trivfs_S_io_write ( struct trivfs_protid * cred, mach_port_t reply, mach_msg_type_name_t replytype, data_t data, mach_msg_type_number_t datalen, loff_t offs, mach_msg_type_number_t * amount ) { LOG_MSG("trivfs_S_io_write"); /*Stop, if credentials are bad*/ if(!cred) return EOPNOTSUPP; /*Sorry, we are readonly*/ return EROFS; }/*trivfs_S_io_write*/ /*----------------------------------------------------------------------------*/ /*How much data we can offer at the moment*/ kern_return_t trivfs_S_io_readable ( struct trivfs_protid * cred, mach_port_t reply, mach_msg_type_name_t replytype, mach_msg_type_number_t * amount ) { LOG_MSG("trivfs_S_io_readable"); /*Stop, if credentials are bad*/ if(!cred) return EOPNOTSUPP; error_t err; /*Ask how much can be read from the underlying file*/ err = io_readable(underlying, amount); /*Return the result of operations*/ return err; }/*trivfs_S_io_readable*/ /*---------------------------------------------------------------------------*/ /*We are wanted truncated to the given size*/ kern_return_t trivfs_S_file_set_size ( struct trivfs_protid * cred, mach_port_t reply, mach_msg_type_name_t replytype, loff_t size ) { LOG_MSG("trivfs_S_file_set_size"); /*Stop if credentials are bad*/ if(!cred) return EOPNOTSUPP; /*Sorry, we are readonly*/ return EROFS; }/*trivfs_S_file_set_size*/ /*---------------------------------------------------------------------------*/ /*Change current read/write offset*/ kern_return_t trivfs_S_io_seek ( struct trivfs_protid * cred, mach_port_t reply, mach_msg_type_name_t reply_type, loff_t offs, int whence, loff_t * new_offs ) { LOG_MSG("trivfs_S_io_seek"); /*Stop if credentials are bad*/ if(!cred) return EOPNOTSUPP; /*TODO: Implement seeking*/ return EOPNOTSUPP; }/*trivfs_S_io_seek*/ /*---------------------------------------------------------------------------*/ /*Wait until the specified type of IO can done quickly*/ kern_return_t trivfs_S_io_select ( struct trivfs_protid * cred, mach_port_t reply, mach_msg_type_name_t replytype, int * type ) { LOG_MSG("trivfs_S_io_select"); /*Stop if credentials are bad*/ if(!cred) return EOPNOTSUPP; /*If not allowed operations are requested*/ if ( ((*type & SELECT_READ ) && !(cred->po->openmodes & O_READ)) ) return EBADF; /*Reset the flag for URG*/ *type &= ~SELECT_URG; /*Everything OK*/ return 0; }/*trivfs_S_io_select*/ /*---------------------------------------------------------------------------*/ /*Four functions for controlling the access modes*/ kern_return_t trivfs_S_io_get_openmodes ( struct trivfs_protid * cred, mach_port_t reply, mach_msg_type_name_t replytype, int * bits ) { LOG_MSG("trivfs_S_io_get_openmodes"); /*Stop if credentials are bad*/ if(!cred) return EOPNOTSUPP; /*We do no restriction on open modes now*/ *bits = cred->po->openmodes; return 0; }/*trivfs_S_io_get_openmodes*/ /*---------------------------------------------------------------------------*/ error_t trivfs_S_io_set_all_openmodes ( struct trivfs_protid * cred, mach_port_t reply, mach_msg_type_name_t replytype, int mode ) { LOG_MSG("trivfs_S_io_set_all_openmodes"); /*Stop, if credentials are bad*/ if(!cred) return EOPNOTSUPP; /*Nothing to do here*/ return 0; }/*trivfs_S_io_set_all_openmodes*/ /*---------------------------------------------------------------------------*/ kern_return_t trivfs_S_io_set_some_openmodes ( struct trivfs_protid * cred, mach_port_t reply, mach_msg_type_name_t replytype, int bits ) { LOG_MSG("trivfs_S_io_set_some_openmodes"); /*Stop, if credentials are bad*/ if(!cred) return EOPNOTSUPP; /*Nothing to do here*/ return 0; }/*trivfs_S_io_set_some_openmodes*/ /*---------------------------------------------------------------------------*/ kern_return_t trivfs_S_io_clear_some_openmodes ( struct trivfs_protid * cred, mach_port_t reply, mach_msg_type_name_t replytype, int bits ) { LOG_MSG("trivfs_S_io_clear_some_openmodes"); /*Stop, if credentials are bad*/ if(!cred) return EOPNOTSUPP; /*Nothing to do here*/ return 0; }/*trivfs_S_io_clear_some_openmodes*/ /*---------------------------------------------------------------------------*/ /*Helps libtrivs construct an answer to a call to fsys_get_options*/ error_t trivfs_append_args ( struct trivfs_control * fsys, char ** argz, size_t * argz_len ) { /*This translator has no arguments*/ return 0; }/*trivfs_append_args*/ /*---------------------------------------------------------------------------*/ /*Process setting a translator on this node*/ kern_return_t trivfs_S_file_set_translator ( struct trivfs_protid * cred, mach_port_t reply, mach_msg_type_name_t reply_type, int actflags, int passflags, int oldtransflags, char * trans, size_t translen, mach_port_t existing ) { LOG_MSG("trivfs_S_file_set_translator"); /*Just agree (?)*/ return 0; }/*trivfs_S_file_set_translator*/ /*---------------------------------------------------------------------------*/ /*Entry point*/ int main ( int argc, char ** argv ) { #ifdef DEBUG mach_port_t tmp = file_name_lookup("/var/log/mangle/mangle.dbg", 0, 0); if(tmp == MACH_PORT_NULL) fDbg = fopen("/var/log/mangle/mangle.dbg", "wt"); else fDbg = fopen("/var/log/mangle/mangle1.dbg", "wt"); mach_port_deallocate(mach_task_self(), tmp); #endif LOG_MSG("Log session started"); error_t err; /*The information about this translator*/ struct trivfs_control * fsys; /*The bootstrap port of the translator*/ mach_port_t bootstrap; /*Obtain the bootstrap port of the translator*/ task_get_bootstrap_port(mach_task_self(), &bootstrap); /*If we don't have a bootstrap port*/ if(bootstrap == MACH_PORT_NULL) { error(EXIT_FAILURE, 0, "Must be started as a translator"); LOG_MSG("Must be started as a translator"); } /*Try to startup the translator*/ err = trivfs_startup(bootstrap, O_READ, 0, 0, 0, 0, &fsys); /*Deallocate the bootstrap port*/ mach_port_deallocate(mach_task_self(), bootstrap); /*Stop, if the translator could not be launched*/ if(err) error(EXIT_FAILURE, err, "Could not startup the translator"); /*Store a copy of the port to the underlying node*/ underlying = fsys->underlying; /*Attempt to stat the underlying node*/ io_statbuf_t stat; err = io_stat(underlying, &stat); if(err) { error(EXIT_FAILURE, err, "Could not stat the underlying node"); LOG_MSG("Could not stat the underlying node"); } /*If the underlying node is a directory*/ if(S_ISDIR(stat.st_mode)) { error(EXIT_FAILURE, err, "Cannot set the translator upon a directory"); LOG_MSG("Cannot set the translator upon a directory"); } LOG_MSG("Translating inode %lu", (unsigned long)stat.st_ino); /*Start the single-threaded server loop*/ ports_manage_port_operations_one_thread(fsys->pi.bucket, trivfs_demuxer, 0); /*Everything OK*/ return 0; }/*main*/ /*---------------------------------------------------------------------------*/