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*/
/*---------------------------------------------------------------------------*/

Reply via email to