On Thu, Jul 17, 2008 at 3:33 PM, Sergiu Ivanov <[EMAIL PROTECTED]>
wrote:
> On Wed, Jul 16, 2008 at 2:32 AM, <[EMAIL PROTECTED]> wrote:
>
>> On Tue, Jul 15, 2008 at 06:10:02PM +0300, Sergiu Ivanov wrote:
>> > I have written a libtrivfs-based translator (the source code is
>> > supplied in the attachment), however I have problems with stacking it
>> > upon itself.
>> [...]
>> > If I now try to stack mangle upon foo again, using the command:
>> >
>> > settrans -L foo mangle
>> >
>> > I receive the following error message:
>> >
>> > settrans: foo: Operation not supported
>>
>> This requires certain RPCs in fs.defs (and probably fsys.defs) to be
>> implemented, most notably file_set_translator. A quick look at
>> file-set-translator.c from libtrivfs shows us that
>> trivfs_S_file_set_translator() is "implemented" as
>>
>> { return EOPNOTSUPP; }
>>
>> i.e. it's not implemented at all.
>>
>> In other words, libtrivfs doesn't seem to support setting further
>> translators on the translated node out of the box. (I think you could
>> implement it manually, though...)
>>
>
I forgot to mention: I've already tried implementing the callback
trivfs_S_file_set_translator in the following way:
{return 0;}
In this case settrans -aL mangle does not complain and I even get two
processes called 'mangle'. However, the process which appears after
settrans -aL mangle seems to be ignored. I mean that the command
cat foo
still prints the contents of 'foo' translated only by *one*
mangle. From the debug log I can see that the mangle translator
process started by settrans -aL mangle does get the right port to the
underlying node (at least, the inode reported by io_stat is
correct). However, cat foo triggers the corresponding callbacks only
in the first instance of mangle.
I supply the new code in the attachment.
scolobb
/*----------------------------------------------------------------------------*/
/*mangle.c*/
/*----------------------------------------------------------------------------*/
/*A simple translator which mangles the underlying file*/
/*----------------------------------------------------------------------------*/
/*Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc.
Written by Sergiu Ivanov <[EMAIL PROTECTED]>.
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 <hurd/trivfs.h>
#include <hurd/hurd_types.h>
#include <stdlib.h>
#include <error.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdio.h>
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*--------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*/
/*---------------------------------------------------------------------------*/