From manish at oss.oracle.com Thu May 29 10:40:47 2003 From: manish at oss.oracle.com (manish@oss.oracle.com) Date: Sat Jun 28 10:19:52 2003 Subject: [Userfs-commits] rev 2 - in trunk: . kernel kernel/linux kernel/src kernel/src/linux genser utils br lib filesystems filesystems/tarfs filesystems/yfs filesystems/ftpfs filesystems/intfs filesystems/cvsfs filesystems/gvfs filesystems/homer filesystems/mailfs filesystems/example filesystems/arcfs Message-ID: <200305290940.h4T9ekJp021396@oss.oracle.com> Author: manish Date: 2003-05-29 04:40:42 -0500 (Thu, 29 May 2003) New Revision: 2 Added: trunk/ANNOUNCE trunk/COPYING trunk/Changelog trunk/Makefile trunk/README.gnome-vfs trunk/README.mjm trunk/README.mm trunk/README.ps trunk/TODO trunk/br/ trunk/br/br.c trunk/filesystems/ trunk/filesystems/README trunk/filesystems/arcfs/ trunk/filesystems/arcfs/Makefile trunk/filesystems/arcfs/README trunk/filesystems/arcfs/arcfs.c trunk/filesystems/arcfs/arcfs.h trunk/filesystems/arcfs/arcvfs.c trunk/filesystems/arcfs/arcvfs.h trunk/filesystems/arcfs/tgz.c trunk/filesystems/arcfs/zip.c trunk/filesystems/cvsfs/ trunk/filesystems/cvsfs/Makefile trunk/filesystems/cvsfs/README trunk/filesystems/cvsfs/cvs.c trunk/filesystems/cvsfs/cvs.h trunk/filesystems/cvsfs/cvsdir.c trunk/filesystems/cvsfs/cvsdir.h trunk/filesystems/cvsfs/cvsfs.c trunk/filesystems/cvsfs/cvstree.c trunk/filesystems/cvsfs/cvstree.h trunk/filesystems/example/ trunk/filesystems/example/Makefile trunk/filesystems/example/egdir.cc trunk/filesystems/example/egdir.h trunk/filesystems/example/egfile.cc trunk/filesystems/example/egfile.h trunk/filesystems/example/egfs.cc trunk/filesystems/example/egfs.h trunk/filesystems/ftpfs/ trunk/filesystems/ftpfs/ConfFile.cc trunk/filesystems/ftpfs/ConfFile.h trunk/filesystems/ftpfs/Makefile trunk/filesystems/ftpfs/Path.cc trunk/filesystems/ftpfs/Path.h trunk/filesystems/ftpfs/README trunk/filesystems/ftpfs/conninfo.cc trunk/filesystems/ftpfs/conninfo.h trunk/filesystems/ftpfs/dir.cc trunk/filesystems/ftpfs/dir.h trunk/filesystems/ftpfs/dos_host.cc trunk/filesystems/ftpfs/dos_host.h trunk/filesystems/ftpfs/ftpconn.cc trunk/filesystems/ftpfs/ftpconn.h trunk/filesystems/ftpfs/ftpdir.cc trunk/filesystems/ftpfs/ftpdir.h trunk/filesystems/ftpfs/ftpfile.cc trunk/filesystems/ftpfs/ftpfile.h trunk/filesystems/ftpfs/ftpfs.cc trunk/filesystems/ftpfs/ftpfs.h trunk/filesystems/ftpfs/ftplink.cc trunk/filesystems/ftpfs/ftplink.h trunk/filesystems/ftpfs/getdate.h trunk/filesystems/ftpfs/getdate.y trunk/filesystems/ftpfs/host.cc trunk/filesystems/ftpfs/host.h trunk/filesystems/ftpfs/ino.cc trunk/filesystems/ftpfs/ino.h trunk/filesystems/ftpfs/netsys.h trunk/filesystems/ftpfs/nonblk_io.cc trunk/filesystems/ftpfs/pushd.cc trunk/filesystems/ftpfs/pushd.h trunk/filesystems/ftpfs/reap.pl trunk/filesystems/ftpfs/serv_port.cc trunk/filesystems/ftpfs/serv_port.h trunk/filesystems/ftpfs/sitetopdir.cc trunk/filesystems/ftpfs/sitetopdir.h trunk/filesystems/ftpfs/topdir.cc trunk/filesystems/ftpfs/topdir.h trunk/filesystems/ftpfs/unix_host.cc trunk/filesystems/ftpfs/unix_host.h trunk/filesystems/ftpfs/vms_host.h trunk/filesystems/gvfs/ trunk/filesystems/gvfs/Makefile trunk/filesystems/gvfs/gvfs.h trunk/filesystems/gvfs/gvfsops.c trunk/filesystems/gvfs/vfsbase.c trunk/filesystems/gvfs/vfsbase.h trunk/filesystems/homer/ trunk/filesystems/homer/Makefile trunk/filesystems/homer/homer.cc trunk/filesystems/homer/homer.h trunk/filesystems/homer/password.cc trunk/filesystems/intfs/ trunk/filesystems/intfs/Makefile trunk/filesystems/intfs/README trunk/filesystems/intfs/intfs.cc trunk/filesystems/intfs/intfs.h trunk/filesystems/intfs/intfsDirIno.cc trunk/filesystems/intfs/intfsDirIno.h trunk/filesystems/intfs/intfsFifoDir.cc trunk/filesystems/intfs/intfsFifoDir.h trunk/filesystems/intfs/intfsFifoIno.cc trunk/filesystems/intfs/intfsFifoIno.h trunk/filesystems/intfs/intfsIno.cc trunk/filesystems/intfs/intfsIno.h trunk/filesystems/intfs/intfsLinkIno.cc trunk/filesystems/intfs/intfsLinkIno.h trunk/filesystems/intfs/pushd.cc trunk/filesystems/intfs/pushd.h trunk/filesystems/mailfs/ trunk/filesystems/mailfs/Makefile trunk/filesystems/mailfs/README trunk/filesystems/mailfs/TODO trunk/filesystems/mailfs/mail.cc trunk/filesystems/mailfs/mail.h trunk/filesystems/mailfs/maildir.cc trunk/filesystems/mailfs/maildir.h trunk/filesystems/mailfs/mailfile.cc trunk/filesystems/mailfs/mailfile.h trunk/filesystems/mailfs/mailfs.1 trunk/filesystems/mailfs/mailfs.cc trunk/filesystems/mailfs/mailfs.h trunk/filesystems/mailfs/maillink.cc trunk/filesystems/mailfs/maillink.h trunk/filesystems/tarfs/ trunk/filesystems/tarfs/Makefile trunk/filesystems/tarfs/README trunk/filesystems/tarfs/rt.c trunk/filesystems/tarfs/tarfs.c trunk/filesystems/tarfs/tarfs.h trunk/filesystems/tarfs/tarvfs.c trunk/filesystems/tarfs/tarvfs.h trunk/filesystems/yfs/ trunk/filesystems/yfs/Makefile trunk/filesystems/yfs/yfs.c trunk/genser/ trunk/genser/Makefile trunk/genser/README trunk/genser/coder.h trunk/genser/com.h trunk/genser/format.c trunk/genser/format.h trunk/genser/gencode.c trunk/genser/genhdr.c trunk/genser/lexer.l trunk/genser/misc.c trunk/genser/misc.h trunk/genser/parser.y trunk/genser/symtab.c trunk/genser/symtab.h trunk/kernel/ trunk/kernel/Makefile trunk/kernel/linux/ trunk/kernel/linux/Makefile trunk/kernel/linux/assert.h trunk/kernel/linux/coder.h trunk/kernel/linux/userfs_fs.h trunk/kernel/linux/userfs_fs_f.h trunk/kernel/linux/userfs_fs_i.h trunk/kernel/linux/userfs_fs_sb.h trunk/kernel/linux/userfs_mount.h trunk/kernel/linux/userfs_types.c trunk/kernel/linux/userfs_types.h trunk/kernel/src/ trunk/kernel/src/Makefile trunk/kernel/src/file.c trunk/kernel/src/inode.c trunk/kernel/src/linux/ trunk/kernel/src/linux/userfs_fs.h trunk/kernel/src/linux/userfs_fs_f.h trunk/kernel/src/linux/userfs_fs_i.h trunk/kernel/src/linux/userfs_fs_sb.h trunk/kernel/src/linux/userfs_mount.h trunk/kernel/src/linux/userfs_types.c trunk/kernel/src/linux/userfs_types.h trunk/kernel/src/module.c trunk/kernel/src/super.c trunk/kernel/src/uio.c trunk/kernel/src/userfs.h trunk/kernel/src/userfs_types.c trunk/kernel/src/userfs_types.h trunk/kernel/src/userfs_types.ty trunk/kernel/types.h trunk/lib/ trunk/lib/Comm.cc trunk/lib/Comm.h trunk/lib/CommBase.cc trunk/lib/CommBase.h trunk/lib/DeferComm.cc trunk/lib/DeferComm.h trunk/lib/DeferFilesys.cc trunk/lib/DeferFilesys.h trunk/lib/DirInode.cc trunk/lib/DirInode.h trunk/lib/Filesystem.h trunk/lib/Filesystem.p trunk/lib/Inode.cc trunk/lib/Inode.p trunk/lib/Makefile trunk/lib/README trunk/lib/SimpleInode.h trunk/lib/ThreadComm.cc trunk/lib/ThreadComm.h trunk/lib/coder.h trunk/lib/dbg.h trunk/lib/operations.h trunk/rules trunk/rules.sub trunk/utils/ trunk/utils/Makefile trunk/utils/io.c trunk/utils/io.h trunk/utils/muserfs.c trunk/utils/opnames.h trunk/utils/um.c trunk/utils/userfs_types.c Log: initial import Added: trunk/README.mjm ============================================================================== --- trunk/README.mjm 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/README.mjm 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,181 @@ +Mon 3 May 1999 + +cvsfs: Added ability to delete checked out versions properly, so that the +repository version won't show up in it's place. + +cvsfs: need to find a way to checkout files in place. + +userfs: added lib and contrib directories back into the package. +Modified Inode.cc so that is doesn't include fs.h with __KERNEL__ +Modified genser to parse the function prototype that was upsetting +it in posix_types.h. Removed lwp and its C++ wrapper. +Moved all the filesystem programs into the same directory. + +Mike + +Sat 1 May 1999 + +Fixed bug in cvsfs.c - the truncate code was incorrect. +Implemented do_notify_change() function. + +Fixed a bug in the original code that was causing the module +to crash when the userfs_sleep function was used. This was generally +when more than one process was using the user file system at +a time. eg. + +$ cd test +$ cp /zImage-990430 . & cp /zImage-990421 . + +To solve this, in uio.c#kissone(), the line lp->bed=NULL was commented out. + +Other bugs (fixed other days): +* included cache update when writing to files +* fixed append mode when writing to files +* notify_change should must truncate to the requied size if the file + size is changed. + +TODO List: +* make cvsfs more efficient. This could envolve tighter integration with the + filesystem... perhaps enter the real inodes from the checkout directory + into the directory entries for the cvsfs file system, so that accesses to + real files go directly to the underlying filesystem instead of through + cvsfs. + +Mike + +------------------------------------------------------------- + +Wed 28 April 1999 + +Well, Jeremy was right, the port to 2.6.6 has turned out to +take alot of effort. Today i've almost got cvsfs working, but +am still having trouble reading/writing files after renaming. +This is the same problems as i was having below, but it is fixed +for the case of creation of new files now. + +CVSfs will be cool if i can get it to work :-) + +Mike + +------------------------------------------------------------ + +Monday 26 April 1999 + +Hello! Silly me, i forgot to set the userfs file handle in create also. +Why do we need to keep two copies of the handle anyhow? Still trying to +figure out why create doesn't work. + +Found out why create doesn't work. In lookup, you must create a dentry +and add it to the parent directory even if the lookup is unsuccessful. +This is necessary for the kernel to be able to create the file. + +Similarly for mkdir. i have changed around the userfs_create +userfs_mknod and userfs_mkdir functions to all user the do_create fn. + +Now the write function doesn't seem to be working, but i'm tired so i'm +going to bed. + +Mike + +-------------------------------------------------------------- + +Sunday 25 April 1999 + +Fixed a couple of major bugs, and changed the way things work a little. +I had forgotted to malloc memory for userfs_inode_info, and the code +was using who-knows-what memory to store the inode information. Every so +often, this would make the kernel cause an exception... notably after running +"du" on a userfs filesystem a couple of times. + +So... because mallocs make me uneasy (especially in the kernel) i have updated +the userfs code to store its extra inode info in the end of the inode struct, +in the space reserved for filesystem code to store its information. This is +good, but we've got be sure that there's enough room there for our data. To +make sure, i've added a check in the install_module code. (It should really +be done at compile time though.) + +For some reason i haven't figured yet, i can't create files in my userfs +filesystems. (or directories either.) + +------------------------------------------------------------- + +Hello, + +i forgot to mention that to compile userfs you may need to comment +out the following line in /usr/include/linux/posis_types.h: + +/* typedef void (*__kernel_sighandler_t)(int); */ + +This is because the genser program cannot deal with function pointers. +(i think). Anyway, it hasn't cause any trouble since i've commented it +out, so i'm going to leave it that way until i could be bothered to +modify the code to genser to handle it. (or somebody beats me to it.) + +I've added a few userfs file systems to the tar: + +tarfs: reads a tar file (not through a process) and creates a filesystem + from the contents +yfs: a simple mirror file system (read only) +cvsfs: display the contents of a CVS repositry in a filesystem. Hopefully + after a bit of work i can make it so that you can compile in place + without checking out the source tree... sound familiar to anybody ;-) + +Fixed the following bugs with the 2.2.6 version: +* when writing to a file, use the "off" pointer +* in do_userfs_write, use copy_from_user, not copy_to_user +* when deleting an inode, d_delete entry must be called. + +24 April 1999 + +Mike + +-------------------------------------------------------------------- +Hello Again, + +enough work for tonight! + +i've found (and hopefully corrected) the following problems: + +1) need to check both tokern and fromkern (struct file *) are not NULL + in uio.c in userfs_close_channel. The new kernel must be doing something + different with the pipe handles. +2) tgz.c was not compatable with the tar on my system and wouldn't + read the tar file index properly. Adjusted the fields in index reader. + (i've got GNU tar 1.12) + +Now userfs/Linux 2.2.6 seems to work with arcfs for read access to zip and +tar files. + +Things still to do: +* check that the other functions work (eg. writing, links, etc) +* go through with a fine tooth comb and check if there's any SMP or + other danger spots, memory leaks or other nasties. + +Mike + +23 Apr 1999 + +btw. i forgot to mention that you should define __SMP__ in the makefile if +you have a SMP system, and only if you have a SMP system. (that one took +me a while to figure out ;-) + +-------------------------------------------------------------------------- +Hi, + +currently this code doesn't work! i am half way through modifying the userfs +module to work with the linux 2.2.6 kernel. It compiles, but don't be +deceived by this... it will crash your system if you use it as it stands! + +Things to do: +* use the handles in the correct manner, including correct use of dput +* lock kernel/file handles in appropriate spots + +Please send any updates to +Michael.McCormack@alcatel.com.au or mccormack@ozemail.com.au + +regards + +Mike McCormack + +Shanghai, China 22 Apr 1999 (yes i read my mail in Australia from here) + Added: trunk/kernel/linux/userfs_mount.h ============================================================================== --- trunk/kernel/linux/userfs_mount.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/linux/userfs_mount.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,30 @@ +/* + * Information passed from user process to the kernel as the + * 3rd argument to mount(2). + */ + +#ifndef _LINUX_USERFS_MOUNT +#define _LINUX_USERFS_MOUNT + +/* + * WARNING! Do not delete or change the order of these fields. If + * a new field is required then add it to the end. The version field + * tracks which fields are present. This will ensure some measure of + * mount-to-kernel version compatibilty. Some of these aren't used yet + * but here they are anyway. + */ + +/* Change this if things are added to the structure below */ +#define USERFS_VERSION 3 + + +struct userfs_mount +{ + int version; /* v1 - version of structure */ + int tokern; /* v1 - fd of stream into the kernel */ + int fromkern; /* v1 - from kernel */ + int magic; /* v2 - magic */ + int seq; /* v3 - initial sequence number */ +}; + +#endif /* _LINUX_USERFS_MOUNT */ Added: trunk/kernel/linux/userfs_types.h ============================================================================== --- trunk/kernel/linux/userfs_types.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/linux/userfs_types.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,894 @@ +/* -*- C -*- + * DO NOT EDIT BY HAND! + * + * This was automatically generated from "userfs_types.ty" by genhdr. + */ +#ifndef __USERFS_TYPES_H_SEEN__ +#define __USERFS_TYPES_H_SEEN__ + +#ifndef __KERNEL__ +#include +#include +typedef __kernel_suseconds_t suseconds_t; +typedef __u8 uint8_t; +typedef __u16 uint16_t; +typedef __u32 uint32_t; +#undef __FD_ZERO +#undef __FD_SET +#undef __FD_CLR +#undef __FD_ISSET +#endif +#if !defined(ALLOC) +# if defined(__KERNEL__) +# include +# include +# include +# define ALLOC(x) kmalloc(x, GFP_KERNEL) +# define FREE(x) kfree(x) +# else +# define ALLOC ALLOC +# include +# include +#ifdef __GLIBC__ +#include +#include +typedef unsigned char unchar; +#endif +static __inline__ void *ALLOC(int alloc) +{ + void *mem = malloc(alloc); + + assert(mem != 0); + return mem; +} +#define FREE(x) free(x) +# endif /* __KERNEL__ */ +#endif /* ALLOC */ +#include +#include +#include +#define UP_REPL 0 /* Is a reply */ +#define UP_REQ 1 /* Is a request */ +#define UP_ENQ 2 /* Is capability enquiry */ +#ifndef _NO_CODER_H_ +/* Type encode/decode routines */ +#include "coder.h" /* Standard routines */ +#endif /* _NO_CODER_H_ */ +/* Encoded types */ + +typedef Ulong _userfs_types_001[32]; +typedef long _userfs_types_002[2]; +typedef Ulong _userfs_types_003[32]; +typedef ushort uf_uid_t; +typedef ushort uf_gid_t; +typedef ushort uf_nlink_t; +typedef ushort uf_dev_t; +typedef struct +{ + Ulong nelem; + long* elems; +} _userfs_types_004; +typedef struct +{ + uf_uid_t uid; + uf_uid_t euid; + uf_uid_t suid; + uf_uid_t gid; + uf_uid_t egid; + uf_uid_t sgid; + uf_uid_t umask; + _userfs_types_004 groups; +} up_cred; +typedef struct +{ + Ulong ia_valid; + umode_t ia_mode; + uf_uid_t ia_uid; + uf_gid_t ia_gid; + off_t ia_size; + time_t ia_atime; + time_t ia_mtime; + time_t ia_ctime; +} up_iattr; +typedef struct +{ + __s16 version; + long seq; + Uchar op; + Uchar isreq; + Ulong size; +} up_preamble; +typedef struct +{ + __s16 version; + long seq; + Uchar op; + Uchar isreq; + Ulong size; + long err_no; +} upp_repl; +typedef struct +{ + umode_t mode; + uf_nlink_t nlink; + uf_uid_t uid; + uf_gid_t gid; + off_t size; + time_t atime; + time_t mtime; + time_t ctime; + uf_dev_t rdev; + Ulong blksize; + Ulong blocks; +} up_inode; +typedef struct +{ + Ulong nelem; + __s8* elems; +} up_name; +typedef struct +{ + up_inode ino; + up_handle handle; +} upp_iwrite_s; +typedef struct +{ + up_handle handle; +} upp_iread_s; +typedef struct +{ + up_handle handle; + up_inode ino; +} upp_iread_r; +typedef struct +{ + up_handle dir; + up_name name; +} upp_unlink_s; +typedef struct +{ + up_handle link; +} upp_readlink_s; +typedef struct +{ + up_name name; +} upp_readlink_r; +typedef struct +{ + up_handle dir; + up_handle link; + long flag; + long mode; +} upp_followlink_s; +typedef struct +{ + up_name path; +} upp_followlink_r; +typedef struct +{ + Ulong nelem; + long* elems; +} _userfs_types_005; +typedef struct +{ + long mode; + up_handle dir; + up_cred cred; + long rdev; + up_name name; +} upp_create_s; +typedef struct +{ + up_handle file; +} upp_create_r; +typedef struct +{ + up_handle dir; + up_name name; +} upp_lookup_s; +typedef struct +{ + up_handle handle; +} upp_lookup_r; +typedef struct +{ + up_handle file; + off_t off; + off_t size; + up_credtok ctok; +} upp_read_s; +typedef struct +{ + Ulong nelem; + Uchar* elems; +} _userfs_types_006; +typedef struct +{ + _userfs_types_006 data; +} upp_read_r; +typedef struct +{ + Ulong nelem; + Uchar* elems; +} _userfs_types_007; +typedef struct +{ + up_handle file; + off_t off; + up_credtok ctok; + _userfs_types_007 data; +} upp_write_s; +typedef struct +{ + off_t wrote; +} upp_write_r; +typedef struct +{ + up_handle dir; + off_t off; + up_credtok ctok; +} upp_readdir_s; +typedef struct +{ + up_handle file; + off_t off; + up_name name; +} upp_readdir_r; +typedef upp_readdir_s upp_multireaddir_s; +typedef struct +{ + Ulong nelem; + upp_readdir_r* elems; +} upp_multireaddir_r; +typedef struct +{ + up_handle root; +} upp_mount_r; +typedef struct +{ + up_handle handle; +} upp_iput_s; +typedef struct +{ + Ulong nelem; + long* elems; +} _userfs_types_008; +typedef struct +{ + up_cred cred; + up_handle file; +} upp_open_s; +typedef struct +{ + up_credtok ctok; +} upp_open_r; +typedef struct +{ + up_handle file; + up_credtok ctok; +} upp_close_s; +typedef struct +{ + Ulong nelem; + long* elems; +} _userfs_types_009; +typedef struct +{ + up_cred cred; + up_handle file; + long mask; +} upp_permission_s; +typedef struct +{ + up_handle odir; + up_name oname; + up_handle ndir; + up_name nname; +} upp_rename_s; +typedef struct +{ + up_handle ofile; + up_handle dir; + up_name name; +} upp_link_s; +typedef struct +{ + Ulong nelem; + long* elems; +} _userfs_types_010; +typedef struct +{ + up_handle dir; + up_name name; + up_name symname; + up_cred cred; +} upp_symlink_s; +typedef long _userfs_types_011[2]; +typedef struct +{ + __kernel_off_t bsize; + __kernel_off_t blocks; + __kernel_off_t bfree; + __kernel_off_t bavail; + __kernel_off_t files; + __kernel_off_t ffree; + _userfs_types_011 fsid; + __kernel_off_t namelen; +} upp_statfs_r; +typedef struct +{ + up_handle file; + off_t size; +} upp_truncate_s; +typedef struct +{ + up_handle handle; + up_iattr iattr; +} upp_notify_change_s; +typedef struct +{ + up_handle handle; + up_version version; +} upp_inode_valid_s; +typedef struct +{ + up_version version; + __s8 valid; +} upp_inode_valid_r; +static unsigned char *encode_char(const char *, unsigned char *); +static unsigned char *decode_char(char *, unsigned char *); +static unsigned int sizeof_char(const char *); + +static unsigned char *encode_short(const short *, unsigned char *); +static unsigned char *decode_short(short *, unsigned char *); +static unsigned int sizeof_short(const short *); + +static unsigned char *encode_long(const long *, unsigned char *); +static unsigned char *decode_long(long *, unsigned char *); +static unsigned int sizeof_long(const long *); + +static unsigned char *encode_longlong(const longlong *, unsigned char *); +static unsigned char *decode_longlong(longlong *, unsigned char *); +static unsigned int sizeof_longlong(const longlong *); + +static unsigned char *encode_float(const float *, unsigned char *); +static unsigned char *decode_float(float *, unsigned char *); +static unsigned int sizeof_float(const float *); + +static unsigned char *encode_double(const double *, unsigned char *); +static unsigned char *decode_double(double *, unsigned char *); +static unsigned int sizeof_double(const double *); + +static unsigned char *encode_void(const void *, unsigned char *); +static unsigned char *decode_void(void *, unsigned char *); +static unsigned int sizeof_void(const void *); + +static unsigned char *encode_Uchar(const Uchar *, unsigned char *); +static unsigned char *decode_Uchar(Uchar *, unsigned char *); +static unsigned int sizeof_Uchar(const Uchar *); + +static unsigned char *encode_Ushort(const Ushort *, unsigned char *); +static unsigned char *decode_Ushort(Ushort *, unsigned char *); +static unsigned int sizeof_Ushort(const Ushort *); + +static unsigned char *encode_Ulong(const Ulong *, unsigned char *); +static unsigned char *decode_Ulong(Ulong *, unsigned char *); +static unsigned int sizeof_Ulong(const Ulong *); + +static unsigned char *encode_Ulonglong(const Ulonglong *, unsigned char *); +static unsigned char *decode_Ulonglong(Ulonglong *, unsigned char *); +static unsigned int sizeof_Ulonglong(const Ulonglong *); + +unsigned char *encode_Uint(const Uint *, unsigned char *); +unsigned char *decode_Uint(Uint *, unsigned char *); +unsigned int sizeof_Uint(const Uint *); + +unsigned char *encode_int(const int *, unsigned char *); +unsigned char *decode_int(int *, unsigned char *); +unsigned int sizeof_int(const int *); + +unsigned char *encode__userfs_types_001(const _userfs_types_001 *, unsigned char *); +unsigned char *decode__userfs_types_001(_userfs_types_001 *, unsigned char *); +unsigned int sizeof__userfs_types_001(const _userfs_types_001 *); + +unsigned char *encode___kernel_fd_set(const __kernel_fd_set *, unsigned char *); +unsigned char *decode___kernel_fd_set(__kernel_fd_set *, unsigned char *); +unsigned int sizeof___kernel_fd_set(const __kernel_fd_set *); + +unsigned char *encode___kernel_key_t(const __kernel_key_t *, unsigned char *); +unsigned char *decode___kernel_key_t(__kernel_key_t *, unsigned char *); +unsigned int sizeof___kernel_key_t(const __kernel_key_t *); + +unsigned char *encode___kernel_dev_t(const __kernel_dev_t *, unsigned char *); +unsigned char *decode___kernel_dev_t(__kernel_dev_t *, unsigned char *); +unsigned int sizeof___kernel_dev_t(const __kernel_dev_t *); + +unsigned char *encode___kernel_ino_t(const __kernel_ino_t *, unsigned char *); +unsigned char *decode___kernel_ino_t(__kernel_ino_t *, unsigned char *); +unsigned int sizeof___kernel_ino_t(const __kernel_ino_t *); + +unsigned char *encode___kernel_mode_t(const __kernel_mode_t *, unsigned char *); +unsigned char *decode___kernel_mode_t(__kernel_mode_t *, unsigned char *); +unsigned int sizeof___kernel_mode_t(const __kernel_mode_t *); + +unsigned char *encode___kernel_nlink_t(const __kernel_nlink_t *, unsigned char *); +unsigned char *decode___kernel_nlink_t(__kernel_nlink_t *, unsigned char *); +unsigned int sizeof___kernel_nlink_t(const __kernel_nlink_t *); + +unsigned char *encode___kernel_off_t(const __kernel_off_t *, unsigned char *); +unsigned char *decode___kernel_off_t(__kernel_off_t *, unsigned char *); +unsigned int sizeof___kernel_off_t(const __kernel_off_t *); + +unsigned char *encode___kernel_pid_t(const __kernel_pid_t *, unsigned char *); +unsigned char *decode___kernel_pid_t(__kernel_pid_t *, unsigned char *); +unsigned int sizeof___kernel_pid_t(const __kernel_pid_t *); + +unsigned char *encode___kernel_ipc_pid_t(const __kernel_ipc_pid_t *, unsigned char *); +unsigned char *decode___kernel_ipc_pid_t(__kernel_ipc_pid_t *, unsigned char *); +unsigned int sizeof___kernel_ipc_pid_t(const __kernel_ipc_pid_t *); + +unsigned char *encode___kernel_uid_t(const __kernel_uid_t *, unsigned char *); +unsigned char *decode___kernel_uid_t(__kernel_uid_t *, unsigned char *); +unsigned int sizeof___kernel_uid_t(const __kernel_uid_t *); + +unsigned char *encode___kernel_gid_t(const __kernel_gid_t *, unsigned char *); +unsigned char *decode___kernel_gid_t(__kernel_gid_t *, unsigned char *); +unsigned int sizeof___kernel_gid_t(const __kernel_gid_t *); + +unsigned char *encode___kernel_size_t(const __kernel_size_t *, unsigned char *); +unsigned char *decode___kernel_size_t(__kernel_size_t *, unsigned char *); +unsigned int sizeof___kernel_size_t(const __kernel_size_t *); + +unsigned char *encode___kernel_ssize_t(const __kernel_ssize_t *, unsigned char *); +unsigned char *decode___kernel_ssize_t(__kernel_ssize_t *, unsigned char *); +unsigned int sizeof___kernel_ssize_t(const __kernel_ssize_t *); + +unsigned char *encode___kernel_ptrdiff_t(const __kernel_ptrdiff_t *, unsigned char *); +unsigned char *decode___kernel_ptrdiff_t(__kernel_ptrdiff_t *, unsigned char *); +unsigned int sizeof___kernel_ptrdiff_t(const __kernel_ptrdiff_t *); + +unsigned char *encode___kernel_time_t(const __kernel_time_t *, unsigned char *); +unsigned char *decode___kernel_time_t(__kernel_time_t *, unsigned char *); +unsigned int sizeof___kernel_time_t(const __kernel_time_t *); + +unsigned char *encode___kernel_suseconds_t(const __kernel_suseconds_t *, unsigned char *); +unsigned char *decode___kernel_suseconds_t(__kernel_suseconds_t *, unsigned char *); +unsigned int sizeof___kernel_suseconds_t(const __kernel_suseconds_t *); + +unsigned char *encode___kernel_clock_t(const __kernel_clock_t *, unsigned char *); +unsigned char *decode___kernel_clock_t(__kernel_clock_t *, unsigned char *); +unsigned int sizeof___kernel_clock_t(const __kernel_clock_t *); + +unsigned char *encode___kernel_daddr_t(const __kernel_daddr_t *, unsigned char *); +unsigned char *decode___kernel_daddr_t(__kernel_daddr_t *, unsigned char *); +unsigned int sizeof___kernel_daddr_t(const __kernel_daddr_t *); + +unsigned char *encode___kernel_caddr_t(const __kernel_caddr_t *, unsigned char *); +unsigned char *decode___kernel_caddr_t(__kernel_caddr_t *, unsigned char *); +unsigned int sizeof___kernel_caddr_t(const __kernel_caddr_t *); + +unsigned char *encode___kernel_uid16_t(const __kernel_uid16_t *, unsigned char *); +unsigned char *decode___kernel_uid16_t(__kernel_uid16_t *, unsigned char *); +unsigned int sizeof___kernel_uid16_t(const __kernel_uid16_t *); + +unsigned char *encode___kernel_gid16_t(const __kernel_gid16_t *, unsigned char *); +unsigned char *decode___kernel_gid16_t(__kernel_gid16_t *, unsigned char *); +unsigned int sizeof___kernel_gid16_t(const __kernel_gid16_t *); + +unsigned char *encode___kernel_uid32_t(const __kernel_uid32_t *, unsigned char *); +unsigned char *decode___kernel_uid32_t(__kernel_uid32_t *, unsigned char *); +unsigned int sizeof___kernel_uid32_t(const __kernel_uid32_t *); + +unsigned char *encode___kernel_gid32_t(const __kernel_gid32_t *, unsigned char *); +unsigned char *decode___kernel_gid32_t(__kernel_gid32_t *, unsigned char *); +unsigned int sizeof___kernel_gid32_t(const __kernel_gid32_t *); + +unsigned char *encode___kernel_old_uid_t(const __kernel_old_uid_t *, unsigned char *); +unsigned char *decode___kernel_old_uid_t(__kernel_old_uid_t *, unsigned char *); +unsigned int sizeof___kernel_old_uid_t(const __kernel_old_uid_t *); + +unsigned char *encode___kernel_old_gid_t(const __kernel_old_gid_t *, unsigned char *); +unsigned char *decode___kernel_old_gid_t(__kernel_old_gid_t *, unsigned char *); +unsigned int sizeof___kernel_old_gid_t(const __kernel_old_gid_t *); + +unsigned char *encode__userfs_types_002(const _userfs_types_002 *, unsigned char *); +unsigned char *decode__userfs_types_002(_userfs_types_002 *, unsigned char *); +unsigned int sizeof__userfs_types_002(const _userfs_types_002 *); + +unsigned char *encode___kernel_fsid_t(const __kernel_fsid_t *, unsigned char *); +unsigned char *decode___kernel_fsid_t(__kernel_fsid_t *, unsigned char *); +unsigned int sizeof___kernel_fsid_t(const __kernel_fsid_t *); + +unsigned char *encode_umode_t(const umode_t *, unsigned char *); +unsigned char *decode_umode_t(umode_t *, unsigned char *); +unsigned int sizeof_umode_t(const umode_t *); + +unsigned char *encode___s8(const __s8 *, unsigned char *); +unsigned char *decode___s8(__s8 *, unsigned char *); +unsigned int sizeof___s8(const __s8 *); + +unsigned char *encode___u8(const __u8 *, unsigned char *); +unsigned char *decode___u8(__u8 *, unsigned char *); +unsigned int sizeof___u8(const __u8 *); + +unsigned char *encode___s16(const __s16 *, unsigned char *); +unsigned char *decode___s16(__s16 *, unsigned char *); +unsigned int sizeof___s16(const __s16 *); + +unsigned char *encode___u16(const __u16 *, unsigned char *); +unsigned char *decode___u16(__u16 *, unsigned char *); +unsigned int sizeof___u16(const __u16 *); + +unsigned char *encode___s32(const __s32 *, unsigned char *); +unsigned char *decode___s32(__s32 *, unsigned char *); +unsigned int sizeof___s32(const __s32 *); + +unsigned char *encode___u32(const __u32 *, unsigned char *); +unsigned char *decode___u32(__u32 *, unsigned char *); +unsigned int sizeof___u32(const __u32 *); + +unsigned char *encode__userfs_types_003(const _userfs_types_003 *, unsigned char *); +unsigned char *decode__userfs_types_003(_userfs_types_003 *, unsigned char *); +unsigned int sizeof__userfs_types_003(const _userfs_types_003 *); + +unsigned char *encode_fd_set(const fd_set *, unsigned char *); +unsigned char *decode_fd_set(fd_set *, unsigned char *); +unsigned int sizeof_fd_set(const fd_set *); + +unsigned char *encode_dev_t(const dev_t *, unsigned char *); +unsigned char *decode_dev_t(dev_t *, unsigned char *); +unsigned int sizeof_dev_t(const dev_t *); + +unsigned char *encode_ino_t(const ino_t *, unsigned char *); +unsigned char *decode_ino_t(ino_t *, unsigned char *); +unsigned int sizeof_ino_t(const ino_t *); + +unsigned char *encode_mode_t(const mode_t *, unsigned char *); +unsigned char *decode_mode_t(mode_t *, unsigned char *); +unsigned int sizeof_mode_t(const mode_t *); + +unsigned char *encode_nlink_t(const nlink_t *, unsigned char *); +unsigned char *decode_nlink_t(nlink_t *, unsigned char *); +unsigned int sizeof_nlink_t(const nlink_t *); + +unsigned char *encode_off_t(const off_t *, unsigned char *); +unsigned char *decode_off_t(off_t *, unsigned char *); +unsigned int sizeof_off_t(const off_t *); + +unsigned char *encode_pid_t(const pid_t *, unsigned char *); +unsigned char *decode_pid_t(pid_t *, unsigned char *); +unsigned int sizeof_pid_t(const pid_t *); + +unsigned char *encode_daddr_t(const daddr_t *, unsigned char *); +unsigned char *decode_daddr_t(daddr_t *, unsigned char *); +unsigned int sizeof_daddr_t(const daddr_t *); + +unsigned char *encode_key_t(const key_t *, unsigned char *); +unsigned char *decode_key_t(key_t *, unsigned char *); +unsigned int sizeof_key_t(const key_t *); + +unsigned char *encode_suseconds_t(const suseconds_t *, unsigned char *); +unsigned char *decode_suseconds_t(suseconds_t *, unsigned char *); +unsigned int sizeof_suseconds_t(const suseconds_t *); + +unsigned char *encode_uid_t(const uid_t *, unsigned char *); +unsigned char *decode_uid_t(uid_t *, unsigned char *); +unsigned int sizeof_uid_t(const uid_t *); + +unsigned char *encode_gid_t(const gid_t *, unsigned char *); +unsigned char *decode_gid_t(gid_t *, unsigned char *); +unsigned int sizeof_gid_t(const gid_t *); + +unsigned char *encode_size_t(const size_t *, unsigned char *); +unsigned char *decode_size_t(size_t *, unsigned char *); +unsigned int sizeof_size_t(const size_t *); + +unsigned char *encode_ssize_t(const ssize_t *, unsigned char *); +unsigned char *decode_ssize_t(ssize_t *, unsigned char *); +unsigned int sizeof_ssize_t(const ssize_t *); + +unsigned char *encode_ptrdiff_t(const ptrdiff_t *, unsigned char *); +unsigned char *decode_ptrdiff_t(ptrdiff_t *, unsigned char *); +unsigned int sizeof_ptrdiff_t(const ptrdiff_t *); + +unsigned char *encode_time_t(const time_t *, unsigned char *); +unsigned char *decode_time_t(time_t *, unsigned char *); +unsigned int sizeof_time_t(const time_t *); + +unsigned char *encode_clock_t(const clock_t *, unsigned char *); +unsigned char *decode_clock_t(clock_t *, unsigned char *); +unsigned int sizeof_clock_t(const clock_t *); + +unsigned char *encode_caddr_t(const caddr_t *, unsigned char *); +unsigned char *decode_caddr_t(caddr_t *, unsigned char *); +unsigned int sizeof_caddr_t(const caddr_t *); + +unsigned char *encode_u_char(const u_char *, unsigned char *); +unsigned char *decode_u_char(u_char *, unsigned char *); +unsigned int sizeof_u_char(const u_char *); + +unsigned char *encode_u_short(const u_short *, unsigned char *); +unsigned char *decode_u_short(u_short *, unsigned char *); +unsigned int sizeof_u_short(const u_short *); + +unsigned char *encode_u_int(const u_int *, unsigned char *); +unsigned char *decode_u_int(u_int *, unsigned char *); +unsigned int sizeof_u_int(const u_int *); + +unsigned char *encode_u_long(const u_long *, unsigned char *); +unsigned char *decode_u_long(u_long *, unsigned char *); +unsigned int sizeof_u_long(const u_long *); + +unsigned char *encode_unchar(const unchar *, unsigned char *); +unsigned char *decode_unchar(unchar *, unsigned char *); +unsigned int sizeof_unchar(const unchar *); + +unsigned char *encode_ushort(const ushort *, unsigned char *); +unsigned char *decode_ushort(ushort *, unsigned char *); +unsigned int sizeof_ushort(const ushort *); + +unsigned char *encode_uint(const uint *, unsigned char *); +unsigned char *decode_uint(uint *, unsigned char *); +unsigned int sizeof_uint(const uint *); + +unsigned char *encode_ulong(const ulong *, unsigned char *); +unsigned char *decode_ulong(ulong *, unsigned char *); +unsigned int sizeof_ulong(const ulong *); + +unsigned char *encode_u_int8_t(const u_int8_t *, unsigned char *); +unsigned char *decode_u_int8_t(u_int8_t *, unsigned char *); +unsigned int sizeof_u_int8_t(const u_int8_t *); + +unsigned char *encode_int8_t(const int8_t *, unsigned char *); +unsigned char *decode_int8_t(int8_t *, unsigned char *); +unsigned int sizeof_int8_t(const int8_t *); + +unsigned char *encode_u_int16_t(const u_int16_t *, unsigned char *); +unsigned char *decode_u_int16_t(u_int16_t *, unsigned char *); +unsigned int sizeof_u_int16_t(const u_int16_t *); + +unsigned char *encode_int16_t(const int16_t *, unsigned char *); +unsigned char *decode_int16_t(int16_t *, unsigned char *); +unsigned int sizeof_int16_t(const int16_t *); + +unsigned char *encode_u_int32_t(const u_int32_t *, unsigned char *); +unsigned char *decode_u_int32_t(u_int32_t *, unsigned char *); +unsigned int sizeof_u_int32_t(const u_int32_t *); + +unsigned char *encode_int32_t(const int32_t *, unsigned char *); +unsigned char *decode_int32_t(int32_t *, unsigned char *); +unsigned int sizeof_int32_t(const int32_t *); + +unsigned char *encode_uint8_t(const uint8_t *, unsigned char *); +unsigned char *decode_uint8_t(uint8_t *, unsigned char *); +unsigned int sizeof_uint8_t(const uint8_t *); + +unsigned char *encode_uint16_t(const uint16_t *, unsigned char *); +unsigned char *decode_uint16_t(uint16_t *, unsigned char *); +unsigned int sizeof_uint16_t(const uint16_t *); + +unsigned char *encode_uint32_t(const uint32_t *, unsigned char *); +unsigned char *decode_uint32_t(uint32_t *, unsigned char *); +unsigned int sizeof_uint32_t(const uint32_t *); + +unsigned char *encode_up_handle(const up_handle *, unsigned char *); +unsigned char *decode_up_handle(up_handle *, unsigned char *); +unsigned int sizeof_up_handle(const up_handle *); + +unsigned char *encode_up_version(const up_version *, unsigned char *); +unsigned char *decode_up_version(up_version *, unsigned char *); +unsigned int sizeof_up_version(const up_version *); + +unsigned char *encode_up_credtok(const up_credtok *, unsigned char *); +unsigned char *decode_up_credtok(up_credtok *, unsigned char *); +unsigned int sizeof_up_credtok(const up_credtok *); + +unsigned char *encode_uf_uid_t(const uf_uid_t *, unsigned char *); +unsigned char *decode_uf_uid_t(uf_uid_t *, unsigned char *); +unsigned int sizeof_uf_uid_t(const uf_uid_t *); + +unsigned char *encode_uf_gid_t(const uf_gid_t *, unsigned char *); +unsigned char *decode_uf_gid_t(uf_gid_t *, unsigned char *); +unsigned int sizeof_uf_gid_t(const uf_gid_t *); + +unsigned char *encode_uf_nlink_t(const uf_nlink_t *, unsigned char *); +unsigned char *decode_uf_nlink_t(uf_nlink_t *, unsigned char *); +unsigned int sizeof_uf_nlink_t(const uf_nlink_t *); + +unsigned char *encode_uf_dev_t(const uf_dev_t *, unsigned char *); +unsigned char *decode_uf_dev_t(uf_dev_t *, unsigned char *); +unsigned int sizeof_uf_dev_t(const uf_dev_t *); + +unsigned char *encode__userfs_types_004(const _userfs_types_004 *, unsigned char *); +unsigned char *decode__userfs_types_004(_userfs_types_004 *, unsigned char *); +unsigned int sizeof__userfs_types_004(const _userfs_types_004 *); + +unsigned char *encode_up_cred(const up_cred *, unsigned char *); +unsigned char *decode_up_cred(up_cred *, unsigned char *); +unsigned int sizeof_up_cred(const up_cred *); + +unsigned char *encode_up_iattr(const up_iattr *, unsigned char *); +unsigned char *decode_up_iattr(up_iattr *, unsigned char *); +unsigned int sizeof_up_iattr(const up_iattr *); + +unsigned char *encode_up_preamble(const up_preamble *, unsigned char *); +unsigned char *decode_up_preamble(up_preamble *, unsigned char *); +unsigned int sizeof_up_preamble(const up_preamble *); + +unsigned char *encode_upp_repl(const upp_repl *, unsigned char *); +unsigned char *decode_upp_repl(upp_repl *, unsigned char *); +unsigned int sizeof_upp_repl(const upp_repl *); + +unsigned char *encode_up_inode(const up_inode *, unsigned char *); +unsigned char *decode_up_inode(up_inode *, unsigned char *); +unsigned int sizeof_up_inode(const up_inode *); + +unsigned char *encode_up_name(const up_name *, unsigned char *); +unsigned char *decode_up_name(up_name *, unsigned char *); +unsigned int sizeof_up_name(const up_name *); + +unsigned char *encode_upp_iwrite_s(const upp_iwrite_s *, unsigned char *); +unsigned char *decode_upp_iwrite_s(upp_iwrite_s *, unsigned char *); +unsigned int sizeof_upp_iwrite_s(const upp_iwrite_s *); + +unsigned char *encode_upp_iread_s(const upp_iread_s *, unsigned char *); +unsigned char *decode_upp_iread_s(upp_iread_s *, unsigned char *); +unsigned int sizeof_upp_iread_s(const upp_iread_s *); + +unsigned char *encode_upp_iread_r(const upp_iread_r *, unsigned char *); +unsigned char *decode_upp_iread_r(upp_iread_r *, unsigned char *); +unsigned int sizeof_upp_iread_r(const upp_iread_r *); + +unsigned char *encode_upp_unlink_s(const upp_unlink_s *, unsigned char *); +unsigned char *decode_upp_unlink_s(upp_unlink_s *, unsigned char *); +unsigned int sizeof_upp_unlink_s(const upp_unlink_s *); + +unsigned char *encode_upp_readlink_s(const upp_readlink_s *, unsigned char *); +unsigned char *decode_upp_readlink_s(upp_readlink_s *, unsigned char *); +unsigned int sizeof_upp_readlink_s(const upp_readlink_s *); + +unsigned char *encode_upp_readlink_r(const upp_readlink_r *, unsigned char *); +unsigned char *decode_upp_readlink_r(upp_readlink_r *, unsigned char *); +unsigned int sizeof_upp_readlink_r(const upp_readlink_r *); + +unsigned char *encode_upp_followlink_s(const upp_followlink_s *, unsigned char *); +unsigned char *decode_upp_followlink_s(upp_followlink_s *, unsigned char *); +unsigned int sizeof_upp_followlink_s(const upp_followlink_s *); + +unsigned char *encode_upp_followlink_r(const upp_followlink_r *, unsigned char *); +unsigned char *decode_upp_followlink_r(upp_followlink_r *, unsigned char *); +unsigned int sizeof_upp_followlink_r(const upp_followlink_r *); + +unsigned char *encode__userfs_types_005(const _userfs_types_005 *, unsigned char *); +unsigned char *decode__userfs_types_005(_userfs_types_005 *, unsigned char *); +unsigned int sizeof__userfs_types_005(const _userfs_types_005 *); + +unsigned char *encode_upp_create_s(const upp_create_s *, unsigned char *); +unsigned char *decode_upp_create_s(upp_create_s *, unsigned char *); +unsigned int sizeof_upp_create_s(const upp_create_s *); + +unsigned char *encode_upp_create_r(const upp_create_r *, unsigned char *); +unsigned char *decode_upp_create_r(upp_create_r *, unsigned char *); +unsigned int sizeof_upp_create_r(const upp_create_r *); + +unsigned char *encode_upp_lookup_s(const upp_lookup_s *, unsigned char *); +unsigned char *decode_upp_lookup_s(upp_lookup_s *, unsigned char *); +unsigned int sizeof_upp_lookup_s(const upp_lookup_s *); + +unsigned char *encode_upp_lookup_r(const upp_lookup_r *, unsigned char *); +unsigned char *decode_upp_lookup_r(upp_lookup_r *, unsigned char *); +unsigned int sizeof_upp_lookup_r(const upp_lookup_r *); + +unsigned char *encode_upp_read_s(const upp_read_s *, unsigned char *); +unsigned char *decode_upp_read_s(upp_read_s *, unsigned char *); +unsigned int sizeof_upp_read_s(const upp_read_s *); + +unsigned char *encode__userfs_types_006(const _userfs_types_006 *, unsigned char *); +unsigned char *decode__userfs_types_006(_userfs_types_006 *, unsigned char *); +unsigned int sizeof__userfs_types_006(const _userfs_types_006 *); + +unsigned char *encode_upp_read_r(const upp_read_r *, unsigned char *); +unsigned char *decode_upp_read_r(upp_read_r *, unsigned char *); +unsigned int sizeof_upp_read_r(const upp_read_r *); + +unsigned char *encode__userfs_types_007(const _userfs_types_007 *, unsigned char *); +unsigned char *decode__userfs_types_007(_userfs_types_007 *, unsigned char *); +unsigned int sizeof__userfs_types_007(const _userfs_types_007 *); + +unsigned char *encode_upp_write_s(const upp_write_s *, unsigned char *); +unsigned char *decode_upp_write_s(upp_write_s *, unsigned char *); +unsigned int sizeof_upp_write_s(const upp_write_s *); + +unsigned char *encode_upp_write_r(const upp_write_r *, unsigned char *); +unsigned char *decode_upp_write_r(upp_write_r *, unsigned char *); +unsigned int sizeof_upp_write_r(const upp_write_r *); + +unsigned char *encode_upp_readdir_s(const upp_readdir_s *, unsigned char *); +unsigned char *decode_upp_readdir_s(upp_readdir_s *, unsigned char *); +unsigned int sizeof_upp_readdir_s(const upp_readdir_s *); + +unsigned char *encode_upp_readdir_r(const upp_readdir_r *, unsigned char *); +unsigned char *decode_upp_readdir_r(upp_readdir_r *, unsigned char *); +unsigned int sizeof_upp_readdir_r(const upp_readdir_r *); + +unsigned char *encode_upp_multireaddir_s(const upp_multireaddir_s *, unsigned char *); +unsigned char *decode_upp_multireaddir_s(upp_multireaddir_s *, unsigned char *); +unsigned int sizeof_upp_multireaddir_s(const upp_multireaddir_s *); + +unsigned char *encode_upp_multireaddir_r(const upp_multireaddir_r *, unsigned char *); +unsigned char *decode_upp_multireaddir_r(upp_multireaddir_r *, unsigned char *); +unsigned int sizeof_upp_multireaddir_r(const upp_multireaddir_r *); + +unsigned char *encode_upp_mount_r(const upp_mount_r *, unsigned char *); +unsigned char *decode_upp_mount_r(upp_mount_r *, unsigned char *); +unsigned int sizeof_upp_mount_r(const upp_mount_r *); + +unsigned char *encode_upp_iput_s(const upp_iput_s *, unsigned char *); +unsigned char *decode_upp_iput_s(upp_iput_s *, unsigned char *); +unsigned int sizeof_upp_iput_s(const upp_iput_s *); + +unsigned char *encode__userfs_types_008(const _userfs_types_008 *, unsigned char *); +unsigned char *decode__userfs_types_008(_userfs_types_008 *, unsigned char *); +unsigned int sizeof__userfs_types_008(const _userfs_types_008 *); + +unsigned char *encode_upp_open_s(const upp_open_s *, unsigned char *); +unsigned char *decode_upp_open_s(upp_open_s *, unsigned char *); +unsigned int sizeof_upp_open_s(const upp_open_s *); + +unsigned char *encode_upp_open_r(const upp_open_r *, unsigned char *); +unsigned char *decode_upp_open_r(upp_open_r *, unsigned char *); +unsigned int sizeof_upp_open_r(const upp_open_r *); + +unsigned char *encode_upp_close_s(const upp_close_s *, unsigned char *); +unsigned char *decode_upp_close_s(upp_close_s *, unsigned char *); +unsigned int sizeof_upp_close_s(const upp_close_s *); + +unsigned char *encode__userfs_types_009(const _userfs_types_009 *, unsigned char *); +unsigned char *decode__userfs_types_009(_userfs_types_009 *, unsigned char *); +unsigned int sizeof__userfs_types_009(const _userfs_types_009 *); + +unsigned char *encode_upp_permission_s(const upp_permission_s *, unsigned char *); +unsigned char *decode_upp_permission_s(upp_permission_s *, unsigned char *); +unsigned int sizeof_upp_permission_s(const upp_permission_s *); + +unsigned char *encode_upp_rename_s(const upp_rename_s *, unsigned char *); +unsigned char *decode_upp_rename_s(upp_rename_s *, unsigned char *); +unsigned int sizeof_upp_rename_s(const upp_rename_s *); + +unsigned char *encode_upp_link_s(const upp_link_s *, unsigned char *); +unsigned char *decode_upp_link_s(upp_link_s *, unsigned char *); +unsigned int sizeof_upp_link_s(const upp_link_s *); + +unsigned char *encode__userfs_types_010(const _userfs_types_010 *, unsigned char *); +unsigned char *decode__userfs_types_010(_userfs_types_010 *, unsigned char *); +unsigned int sizeof__userfs_types_010(const _userfs_types_010 *); + +unsigned char *encode_upp_symlink_s(const upp_symlink_s *, unsigned char *); +unsigned char *decode_upp_symlink_s(upp_symlink_s *, unsigned char *); +unsigned int sizeof_upp_symlink_s(const upp_symlink_s *); + +unsigned char *encode__userfs_types_011(const _userfs_types_011 *, unsigned char *); +unsigned char *decode__userfs_types_011(_userfs_types_011 *, unsigned char *); +unsigned int sizeof__userfs_types_011(const _userfs_types_011 *); + +unsigned char *encode_upp_statfs_r(const upp_statfs_r *, unsigned char *); +unsigned char *decode_upp_statfs_r(upp_statfs_r *, unsigned char *); +unsigned int sizeof_upp_statfs_r(const upp_statfs_r *); + +unsigned char *encode_upp_truncate_s(const upp_truncate_s *, unsigned char *); +unsigned char *decode_upp_truncate_s(upp_truncate_s *, unsigned char *); +unsigned int sizeof_upp_truncate_s(const upp_truncate_s *); + +unsigned char *encode_upp_notify_change_s(const upp_notify_change_s *, unsigned char *); +unsigned char *decode_upp_notify_change_s(upp_notify_change_s *, unsigned char *); +unsigned int sizeof_upp_notify_change_s(const upp_notify_change_s *); + +unsigned char *encode_upp_inode_valid_s(const upp_inode_valid_s *, unsigned char *); +unsigned char *decode_upp_inode_valid_s(upp_inode_valid_s *, unsigned char *); +unsigned int sizeof_upp_inode_valid_s(const upp_inode_valid_s *); + +unsigned char *encode_upp_inode_valid_r(const upp_inode_valid_r *, unsigned char *); +unsigned char *decode_upp_inode_valid_r(upp_inode_valid_r *, unsigned char *); +unsigned int sizeof_upp_inode_valid_r(const upp_inode_valid_r *); + +#endif /* __USERFS_TYPES_H_SEEN__ */ Added: trunk/kernel/linux/coder.h ============================================================================== --- trunk/kernel/linux/coder.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/linux/coder.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,283 @@ +/* Base type primitives */ + +#ifndef __CODER_H_SEEN__ +#define __CODER_H_SEEN__ + +#ifndef __GNUC__ +#define __inline__ /* */ +#endif + +#ifndef __cplusplus +#ifndef ALLOC +extern void *malloc(unsigned long); +extern void free(void *); +#define ALLOC(s) malloc(s) +#define FREE(s) free(s) +#endif /* ALLOC */ +#endif __cplusplus + +/* Types we use */ +typedef unsigned char Uchar; +typedef unsigned short Ushort; +typedef unsigned long Ulong; +typedef unsigned long Uint; +typedef unsigned long long Ulonglong; +typedef long long longlong; + +/** char **/ +__inline__ static unsigned char *encode_char(const char *ch, unsigned char *buf) +{ + *buf = *ch; + return buf+1; +} + +__inline__ static unsigned char *decode_char(char *ch, unsigned char *buf) +{ + *ch = *buf; + return buf+1; +} + +__inline__ static unsigned int sizeof_char(const char *c) +{ + (void)c; + return 1; +} + +/** unsigned char **/ +__inline__ static unsigned char *encode_Uchar(const Uchar *ch, unsigned char *buf) +{ + *buf = *ch; + return buf+1; +} + +__inline__ static unsigned char *decode_Uchar(Uchar *ch, unsigned char *buf) +{ + *ch = *buf; + return buf+1; +} + +__inline__ static unsigned int sizeof_Uchar(const Uchar *c) +{ + (void)c; + return 1; +} + +/** short **/ +__inline__ static unsigned char *encode_short(const short *sh, unsigned char *buf) +{ + register short sv = *sh; + + buf[0] = (sv >> 8)& 0xff; + buf[1] = sv & 0xff; + return buf+2; +} + +__inline__ static unsigned char *decode_short(short *sh, unsigned char *buf) +{ + *sh = (buf[0] << 8) | buf[1]; + return buf+2; +} + +__inline__ static unsigned int sizeof_short(const short *c) +{ + (void)c; + return 2; +} + +/** unsigned short **/ +__inline__ static unsigned char *encode_Ushort(const Ushort *sh, unsigned char *buf) +{ + register Ushort sv = *sh; + + buf[0] = (sv >> 8)& 0xff; + buf[1] = sv & 0xff; + return buf+2; +} + +__inline__ static unsigned char *decode_Ushort(Ushort *sh, unsigned char *buf) +{ + *sh = (buf[0] << 8) | buf[1]; + return buf+2; +} + +__inline__ static unsigned int sizeof_Ushort(const Ushort *c) +{ + (void)c; + return 2; +} + +/** long **/ +__inline__ static unsigned char *encode_long(const long *l, unsigned char *buf) +{ + register long lv = *l; + + buf[0] = (lv >> 24) & 0xff; + buf[1] = (lv >> 16) & 0xff; + buf[2] = (lv >> 8) & 0xff; + buf[3] = lv & 0xff; + return buf+4; +} + +__inline__ static unsigned char *decode_long(long *l, unsigned char *buf) +{ + *l = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + return buf+4; +} + +__inline__ static unsigned int sizeof_long(const long *c) +{ + (void)c; + return 4; +} + +/** unsigned long **/ +__inline__ static unsigned char *encode_Ulong(const Ulong *l, unsigned char *buf) +{ + register Ulong lv = *l; + + buf[0] = (lv >> 24) & 0xff; + buf[1] = (lv >> 16) & 0xff; + buf[2] = (lv >> 8) & 0xff; + buf[3] = lv & 0xff; + return buf+4; +} + +__inline__ static unsigned char *decode_Ulong(Ulong *l, unsigned char *buf) +{ + *l = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + return buf+4; +} + +__inline__ static unsigned int sizeof_Ulong(const Ulong *c) +{ + (void)c; + return 4; +} + +/** long long */ +__inline__ static unsigned char *encode_longlong(const long long *l, + unsigned char *buf) +{ + register long long lv = *l; + + buf[0] = (lv >> 56) & 0xff; + buf[1] = (lv >> 48) & 0xff; + buf[2] = (lv >> 40) & 0xff; + buf[3] = (lv >> 32) & 0xff; + buf[4] = (lv >> 24) & 0xff; + buf[5] = (lv >> 16) & 0xff; + buf[6] = (lv >> 8) & 0xff; + buf[7] = lv & 0xff; + + return buf+8; +} + +__inline__ static unsigned char *decode_longlong(long long *l, + unsigned char *buf) +{ +#define BUF(x) ((long long)(buf[x])) + *l = (BUF(0) << 56)|(BUF(1) << 48)|(BUF(2) << 40)|(BUF(3) << 32)| + (BUF(4) << 24)|(BUF(5) << 16)|(BUF(6) << 8)|BUF(7); +#undef BUF + return buf+8; +} + +__inline__ static unsigned int sizeof_longlong(const long long *c) +{ + (void)c; + return 8; +} + +/** unsigned long long */ +__inline__ static unsigned char *encode_Ulonglong(const unsigned long long *l, + unsigned char *buf) +{ + register unsigned long long lv = *l; + + buf[0] = (lv >> 56) & 0xff; + buf[1] = (lv >> 48) & 0xff; + buf[2] = (lv >> 40) & 0xff; + buf[3] = (lv >> 32) & 0xff; + buf[4] = (lv >> 24) & 0xff; + buf[5] = (lv >> 16) & 0xff; + buf[6] = (lv >> 8) & 0xff; + buf[7] = lv & 0xff; + + return buf+8; +} + +__inline__ static unsigned char *decode_Ulonglong(unsigned long long *l, + unsigned char *buf) +{ +#define BUF(x) ((unsigned long long)(buf[x])) + *l = (BUF(0) << 56)|(BUF(1) << 48)|(BUF(2) << 40)|(BUF(3) << 32)| + (BUF(4) << 24)|(BUF(5) << 16)|(BUF(6) << 8)|BUF(7); +#undef BUF + return buf+8; +} + +__inline__ static unsigned int sizeof_Ulonglong(const unsigned long long *c) +{ + (void)c; + return 8; +} + +/** void **/ +__inline__ static unsigned char *encode_void(const void *v, unsigned char *buf) +{ + (void)v; + return buf; +} + +__inline__ static unsigned char *decode_void(void *v, unsigned char *buf) +{ + (void)v; + return buf; +} + +__inline__ static unsigned int sizeof_void(const void *c) +{ + (void)c; + return 0; +} + +/* Assuming this host has IEEE 754 floats, this is all OK */ +/** float **/ +__inline__ static unsigned char *encode_float(const float *f, unsigned char *buf) +{ + *(float *)buf = *f; + return buf + sizeof(float); +} + +__inline__ static unsigned char *decode_float(float *f, unsigned char *buf) +{ + *f = *(float *)buf; + return buf + sizeof(float); +} + +__inline__ static unsigned int sizeof_float(const float *c) +{ + (void)c; + return sizeof(float); +} + +/** double **/ +__inline__ static unsigned char *encode_double(const double *d, unsigned char *buf) +{ + *(double *)buf = *d; + return buf + sizeof(double); +} + +__inline__ static unsigned char *decode_double(double *d, unsigned char *buf) +{ + *d = *(double *)buf; + return buf + sizeof(double); +} + +__inline__ static unsigned int sizeof_double(const double *c) +{ + (void)c; + return sizeof(double); +} + +#endif /* __CODER_H_SEEN__ */ Added: trunk/kernel/linux/userfs_fs.h ============================================================================== --- trunk/kernel/linux/userfs_fs.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/linux/userfs_fs.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,102 @@ +/* + * Filesystem stub for filesystems implemented with user-level + * programs. + * + * This file forms the definition of the protocol between the + * kernel and the user process through the file descriptors. + * + * There are two file descriptors passed to the kernel as part + * of the args to mount(). One is for data from the kernel + * to the filesystem, the other from the filesystem to the + * kernel. Control and data information are encoded along + * the same path. + * + * The filesystem process never initiates any transaction - they + * are all generated by the kernel on the behalf of the other + * user processes using the filesystem. + * + * The connction between the user process and the kernel is + * stateful, so if the connection breaks, Something Bad happens - + * I suppose it should be considered a umount - but what about + * outstanding writes? + * + * For much the same reasons as nfs and dosfs, there can be no + * direct mapping from files, making exec() less memory and time + * efficient. I don't see this as a big problem. + * + * Jeremy Fitzhardinge 1993 + */ + +#ifndef _LINUX_USERFS_FS +#define _LINUX_USERFS_FS + +/* + * These operations map closely with the elements in the various + * operations structures. + * + * Things are missing here, or overloaded. Open does create, mknod and + * mkdir. Unlink can also do a rmdir. + */ +typedef enum +{ + userfs_up_create, /* 0 create files, devices, dirs */ + userfs_up_lookup, /* 1 path->file handle */ + userfs_up_close, /* 2 close on fh */ + userfs_up_read, /* 3 read from file */ + userfs_up_write, /* 4 write to file */ + userfs_up_truncate, /* 5 set file length */ + userfs_up_fsync, /* 6 sync file */ + userfs_up_readdir, /* 7 read dir entries */ + userfs_up_link, /* 8 link files */ + userfs_up_unlink, /* 9 unlink file */ + userfs_up_symlink, /* 10 create symlink */ + userfs_up_readlink, /* 11 read link contents */ + userfs_up_followlink, /* 12 resolve path through link */ + userfs_up_mount, /* 13 mount request */ + userfs_up_umount, /* 14 unmount request */ + userfs_up_iread, /* 15 get contents of inode for file */ + userfs_up_iwrite, /* 16 set inode contents */ + userfs_up_statfs, /* 17 stat filesystem wide things */ + userfs_up_iput, /* 18 put an inode after finished */ + userfs_up_open, /* 19 open of a file */ + userfs_up_permission, /* 20 check file permissions */ + userfs_up_rename, /* 21 rename file */ + userfs_up_multireaddir, /* 22 read multiple dir entries */ + userfs_up_notify_change, /* 23 notify inode changes */ + userfs_up_inode_valid, /* 24 ask filesystem whether an inode is valid */ +} up_ops; + +/* increment this when the structure shapes change */ +#define UP_VERSION 16 + +/* + * Max transfer size currently limited to largest allocatable + * block. There's also not much need to make it bigger. + */ +#define USERFS_MAX_XFER (4080) + +#ifdef __KERNEL__ +#include /* For NGROUPS */ +#include + +typedef unsigned char *(*encode_func)(const void *, unsigned char *); +typedef unsigned char *(*decode_func)(void *, unsigned char *); +typedef unsigned int (*sizeof_func)(const void *); + +#define GEN_ENC(var) (encode_func)(var) +#define GEN_DEC(var) (decode_func)(var) +#define GEN_SIZ(var) (sizeof_func)(var) + +void userfs_genpkt(struct super_block *, up_preamble *, up_ops); + +/* Encode and send request, receive and decode reply */ +#define userfs_doop(sb, pre, repl, st, ss, rt, rs)\ + __userfs_doop(sb, pre, repl, \ + GEN_ENC(encode_##st), (void *)ss, \ + GEN_DEC(decode_##rt), (void *)rs, \ + GEN_SIZ(sizeof_##st), GEN_SIZ(sizeof_##rt)) + +int __userfs_doop(struct super_block *, up_preamble *pre, upp_repl *repl, encode_func, void *, decode_func, void *, sizeof_func, sizeof_func); +#endif /* __KERNEL__ */ + +#endif /* _LINUX_USERFS_FS */ Added: trunk/kernel/linux/assert.h ============================================================================== --- trunk/kernel/linux/assert.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/linux/assert.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,28 @@ +/* + * Kernel assertions + */ + +#ifndef __LINUX_ASSERT_H_ +#define __LINUX_ASSERT_H_ + +#ifdef NO_ASSERT +#define assert(x) +#else +#ifdef __cplusplus +#define assert(x) \ + if(!(x)) \ + { \ + printk("Assertion failed in %s:%d: %s\n", \ + __FILE__, __LINE__, #x); \ + } +#else +#define assert(x) \ + if(!(x)) \ + { \ + printk("Assertion failed in %s:%d (%s): %s\n", \ + __FILE__, __LINE__, __FUNCTION__, #x); \ + } +#endif /* __cplusplus */ +#endif /* NO_ASSERT */ + +#endif /* __LINUX_ASSERT_H_ */ Added: trunk/kernel/linux/userfs_fs_sb.h ============================================================================== --- trunk/kernel/linux/userfs_fs_sb.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/linux/userfs_fs_sb.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,31 @@ +/* + * Super-block structure for user-level filesystem support. + */ + +#ifndef _LINUX_USERFS_FS_SB +#define _LINUX_USERFS_FS_SB + +#include + +#define USERFS_SUPER_MAGIC 0x73757265 + +struct userfs_sb_info +{ + struct file *s_toproc; /* To user process */ + struct file *s_fromproc; /* From user process */ + int s_seq; /* Sequence number */ + up_handle s_root; /* root of mounted fs */ + struct inode_operations *s_iops; /* inode ops for this fs */ + + /* These are for serialising access to pipe */ + spinlock_t s_lock; + + /* This is for multiple outstanding operations */ + int s_canread; /* there is something reading */ + int s_nwproc; /* number of processes waiting */ + struct pwlist *s_wlist; /* list of waiting processes */ +}; + +extern struct super_block *userfs_read_super(struct super_block *, void *, int); + +#endif /* _LINUX_USERFS_FS_SB */ Added: trunk/kernel/linux/userfs_fs_f.h ============================================================================== --- trunk/kernel/linux/userfs_fs_f.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/linux/userfs_fs_f.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,14 @@ +/* + * Per file open information for userfs + */ + +#ifndef __LINUX_USERFS_FS_F_H_SEEN__ +#define __LINUX_USERFS_FS_F_H_SEEN__ + +typedef unsigned long up_credtok; + +struct userfs_file_info { + up_credtok cred_tok; /* credentials token */ +}; + +#endif /* __LINUX_USERFS_FS_F_H_SEEN__ */ Added: trunk/kernel/linux/userfs_types.c ============================================================================== --- trunk/kernel/linux/userfs_types.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/linux/userfs_types.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,1436 @@ +/* -*- C -*- + * DO NOT EDIT BY HAND! + * + * This was automatically generated by gencode. + */ +#include "userfs_types.h" + + +unsigned char *encode__userfs_types_001(const _userfs_types_001 *sp, unsigned char *buf) +{ + { + unsigned i; + + for(i = 0; i < 32; i++) { + buf = encode_Ulong(&(*sp)[i], buf); + } + } + return buf; +} + + +unsigned char *encode__userfs_types_002(const _userfs_types_002 *sp, unsigned char *buf) +{ + { + unsigned i; + + for(i = 0; i < 2; i++) { + buf = encode_long(&(*sp)[i], buf); + } + } + return buf; +} + + +unsigned char *encode_up_handle(const up_handle *sp, unsigned char *buf) +{ + buf = encode_Ulong(&sp->handle, buf); + return buf; +} + + +unsigned char *encode_uf_uid_t(const uf_uid_t *sp, unsigned char *buf) +{ + buf = encode_Ushort(sp, buf); + return buf; +} + + +unsigned char *encode__userfs_types_004(const _userfs_types_004 *sp, unsigned char *buf) +{ + { + unsigned i; + + buf = encode_Ulong(&sp->nelem, buf); + for(i = 0; i < sp->nelem; i++) { + buf = encode_long(&sp->elems[i], buf); + } + } + return buf; +} + + +unsigned char *encode_up_cred(const up_cred *sp, unsigned char *buf) +{ + buf = encode_Ushort(&sp->uid, buf); + buf = encode_Ushort(&sp->euid, buf); + buf = encode_Ushort(&sp->suid, buf); + buf = encode_Ushort(&sp->gid, buf); + buf = encode_Ushort(&sp->egid, buf); + buf = encode_Ushort(&sp->sgid, buf); + buf = encode_Ushort(&sp->umask, buf); + buf = encode__userfs_types_004(&sp->groups, buf); + return buf; +} + + +unsigned char *encode_up_iattr(const up_iattr *sp, unsigned char *buf) +{ + buf = encode_Ulong(&sp->ia_valid, buf); + buf = encode_Ushort(&sp->ia_mode, buf); + buf = encode_Ushort(&sp->ia_uid, buf); + buf = encode_Ushort(&sp->ia_gid, buf); + buf = encode_long(&sp->ia_size, buf); + buf = encode_long(&sp->ia_atime, buf); + buf = encode_long(&sp->ia_mtime, buf); + buf = encode_long(&sp->ia_ctime, buf); + return buf; +} + + +unsigned char *encode_up_preamble(const up_preamble *sp, unsigned char *buf) +{ + buf = encode_short(&sp->version, buf); + buf = encode_long(&sp->seq, buf); + buf = encode_Uchar(&sp->op, buf); + buf = encode_Uchar(&sp->isreq, buf); + buf = encode_Ulong(&sp->size, buf); + return buf; +} + + +unsigned char *encode_upp_repl(const upp_repl *sp, unsigned char *buf) +{ + buf = encode_short(&sp->version, buf); + buf = encode_long(&sp->seq, buf); + buf = encode_Uchar(&sp->op, buf); + buf = encode_Uchar(&sp->isreq, buf); + buf = encode_Ulong(&sp->size, buf); + buf = encode_long(&sp->err_no, buf); + return buf; +} + + +unsigned char *encode_up_inode(const up_inode *sp, unsigned char *buf) +{ + buf = encode_Ushort(&sp->mode, buf); + buf = encode_Ushort(&sp->nlink, buf); + buf = encode_Ushort(&sp->uid, buf); + buf = encode_Ushort(&sp->gid, buf); + buf = encode_long(&sp->size, buf); + buf = encode_long(&sp->atime, buf); + buf = encode_long(&sp->mtime, buf); + buf = encode_long(&sp->ctime, buf); + buf = encode_Ushort(&sp->rdev, buf); + buf = encode_Ulong(&sp->blksize, buf); + buf = encode_Ulong(&sp->blocks, buf); + return buf; +} + + +unsigned char *encode_up_name(const up_name *sp, unsigned char *buf) +{ + { + unsigned i; + + buf = encode_Ulong(&sp->nelem, buf); + for(i = 0; i < sp->nelem; i++) { + buf = encode_char(&sp->elems[i], buf); + } + } + return buf; +} + + +unsigned char *encode_upp_iwrite_s(const upp_iwrite_s *sp, unsigned char *buf) +{ + buf = encode_up_inode(&sp->ino, buf); + buf = encode_up_handle(&sp->handle, buf); + return buf; +} + + +unsigned char *encode_upp_iread_s(const upp_iread_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->handle, buf); + return buf; +} + + +unsigned char *encode_upp_iread_r(const upp_iread_r *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->handle, buf); + buf = encode_up_inode(&sp->ino, buf); + return buf; +} + + +unsigned char *encode_upp_unlink_s(const upp_unlink_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->dir, buf); + buf = encode_up_name(&sp->name, buf); + return buf; +} + + +unsigned char *encode_upp_readlink_s(const upp_readlink_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->link, buf); + return buf; +} + + +unsigned char *encode_upp_readlink_r(const upp_readlink_r *sp, unsigned char *buf) +{ + buf = encode_up_name(&sp->name, buf); + return buf; +} + + +unsigned char *encode_upp_followlink_s(const upp_followlink_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->dir, buf); + buf = encode_up_handle(&sp->link, buf); + buf = encode_long(&sp->flag, buf); + buf = encode_long(&sp->mode, buf); + return buf; +} + + +unsigned char *encode_upp_followlink_r(const upp_followlink_r *sp, unsigned char *buf) +{ + buf = encode_up_name(&sp->path, buf); + return buf; +} + + +unsigned char *encode_upp_create_s(const upp_create_s *sp, unsigned char *buf) +{ + buf = encode_long(&sp->mode, buf); + buf = encode_up_handle(&sp->dir, buf); + buf = encode_up_cred(&sp->cred, buf); + buf = encode_long(&sp->rdev, buf); + buf = encode_up_name(&sp->name, buf); + return buf; +} + + +unsigned char *encode_upp_create_r(const upp_create_r *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->file, buf); + return buf; +} + + +unsigned char *encode_upp_lookup_s(const upp_lookup_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->dir, buf); + buf = encode_up_name(&sp->name, buf); + return buf; +} + + +unsigned char *encode_upp_lookup_r(const upp_lookup_r *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->handle, buf); + return buf; +} + + +unsigned char *encode_upp_read_s(const upp_read_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->file, buf); + buf = encode_long(&sp->off, buf); + buf = encode_long(&sp->size, buf); + buf = encode_Ulong(&sp->ctok, buf); + return buf; +} + + +unsigned char *encode__userfs_types_006(const _userfs_types_006 *sp, unsigned char *buf) +{ + { + unsigned i; + + buf = encode_Ulong(&sp->nelem, buf); + for(i = 0; i < sp->nelem; i++) { + buf = encode_Uchar(&sp->elems[i], buf); + } + } + return buf; +} + + +unsigned char *encode_upp_read_r(const upp_read_r *sp, unsigned char *buf) +{ + buf = encode__userfs_types_006(&sp->data, buf); + return buf; +} + + +unsigned char *encode__userfs_types_007(const _userfs_types_007 *sp, unsigned char *buf) +{ + { + unsigned i; + + buf = encode_Ulong(&sp->nelem, buf); + for(i = 0; i < sp->nelem; i++) { + buf = encode_Uchar(&sp->elems[i], buf); + } + } + return buf; +} + + +unsigned char *encode_upp_write_s(const upp_write_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->file, buf); + buf = encode_long(&sp->off, buf); + buf = encode_Ulong(&sp->ctok, buf); + buf = encode__userfs_types_007(&sp->data, buf); + return buf; +} + + +unsigned char *encode_upp_write_r(const upp_write_r *sp, unsigned char *buf) +{ + buf = encode_long(&sp->wrote, buf); + return buf; +} + + +unsigned char *encode_upp_readdir_s(const upp_readdir_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->dir, buf); + buf = encode_long(&sp->off, buf); + buf = encode_Ulong(&sp->ctok, buf); + return buf; +} + + +unsigned char *encode_upp_readdir_r(const upp_readdir_r *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->file, buf); + buf = encode_long(&sp->off, buf); + buf = encode_up_name(&sp->name, buf); + return buf; +} + + +unsigned char *encode_upp_multireaddir_s(const upp_multireaddir_s *sp, unsigned char *buf) +{ + buf = encode_upp_readdir_s(sp, buf); + return buf; +} + + +unsigned char *encode_upp_multireaddir_r(const upp_multireaddir_r *sp, unsigned char *buf) +{ + { + unsigned i; + + buf = encode_Ulong(&sp->nelem, buf); + for(i = 0; i < sp->nelem; i++) { + buf = encode_upp_readdir_r(&sp->elems[i], buf); + } + } + return buf; +} + + +unsigned char *encode_upp_mount_r(const upp_mount_r *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->root, buf); + return buf; +} + + +unsigned char *encode_upp_iput_s(const upp_iput_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->handle, buf); + return buf; +} + + +unsigned char *encode_upp_open_s(const upp_open_s *sp, unsigned char *buf) +{ + buf = encode_up_cred(&sp->cred, buf); + buf = encode_up_handle(&sp->file, buf); + return buf; +} + + +unsigned char *encode_upp_open_r(const upp_open_r *sp, unsigned char *buf) +{ + buf = encode_Ulong(&sp->ctok, buf); + return buf; +} + + +unsigned char *encode_upp_close_s(const upp_close_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->file, buf); + buf = encode_Ulong(&sp->ctok, buf); + return buf; +} + + +unsigned char *encode_upp_permission_s(const upp_permission_s *sp, unsigned char *buf) +{ + buf = encode_up_cred(&sp->cred, buf); + buf = encode_up_handle(&sp->file, buf); + buf = encode_long(&sp->mask, buf); + return buf; +} + + +unsigned char *encode_upp_rename_s(const upp_rename_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->odir, buf); + buf = encode_up_name(&sp->oname, buf); + buf = encode_up_handle(&sp->ndir, buf); + buf = encode_up_name(&sp->nname, buf); + return buf; +} + + +unsigned char *encode_upp_link_s(const upp_link_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->ofile, buf); + buf = encode_up_handle(&sp->dir, buf); + buf = encode_up_name(&sp->name, buf); + return buf; +} + + +unsigned char *encode_upp_symlink_s(const upp_symlink_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->dir, buf); + buf = encode_up_name(&sp->name, buf); + buf = encode_up_name(&sp->symname, buf); + buf = encode_up_cred(&sp->cred, buf); + return buf; +} + + +unsigned char *encode__userfs_types_011(const _userfs_types_011 *sp, unsigned char *buf) +{ + { + unsigned i; + + for(i = 0; i < 2; i++) { + buf = encode_long(&(*sp)[i], buf); + } + } + return buf; +} + + +unsigned char *encode_upp_statfs_r(const upp_statfs_r *sp, unsigned char *buf) +{ + buf = encode_long(&sp->bsize, buf); + buf = encode_long(&sp->blocks, buf); + buf = encode_long(&sp->bfree, buf); + buf = encode_long(&sp->bavail, buf); + buf = encode_long(&sp->files, buf); + buf = encode_long(&sp->ffree, buf); + buf = encode__userfs_types_011(&sp->fsid, buf); + buf = encode_long(&sp->namelen, buf); + return buf; +} + + +unsigned char *encode_upp_truncate_s(const upp_truncate_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->file, buf); + buf = encode_long(&sp->size, buf); + return buf; +} + + +unsigned char *encode_upp_notify_change_s(const upp_notify_change_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->handle, buf); + buf = encode_up_iattr(&sp->iattr, buf); + return buf; +} + + +unsigned char *encode_upp_inode_valid_s(const upp_inode_valid_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->handle, buf); + buf = encode_Ulong(&sp->version, buf); + return buf; +} + + +unsigned char *encode_upp_inode_valid_r(const upp_inode_valid_r *sp, unsigned char *buf) +{ + buf = encode_Ulong(&sp->version, buf); + buf = encode_char(&sp->valid, buf); + return buf; +} + + +unsigned char *decode__userfs_types_001(_userfs_types_001 *sp, unsigned char *buf) +{ + { + unsigned i; + + for(i = 0; i < 32; i++) { + buf = decode_Ulong(sp[i], buf); + } + } + return buf; +} + + +unsigned char *decode__userfs_types_002(_userfs_types_002 *sp, unsigned char *buf) +{ + { + unsigned i; + + for(i = 0; i < 2; i++) { + buf = decode_long(sp[i], buf); + } + } + return buf; +} + + +unsigned char *decode_up_handle(up_handle *sp, unsigned char *buf) +{ + buf = decode_Ulong(&sp->handle, buf); + return buf; +} + + +unsigned char *decode_uf_uid_t(uf_uid_t *sp, unsigned char *buf) +{ + buf = decode_Ushort(sp, buf); + return buf; +} + + +unsigned char *decode__userfs_types_004(_userfs_types_004 *sp, unsigned char *buf) +{ + { + unsigned i; + buf = decode_Ulong(&sp->nelem, buf); + if (sp->nelem == 0) + { + sp->elems = 0; + return buf; + } + sp->elems = (long *)ALLOC(sizeof(long) * sp->nelem); + if (sp->elems == 0) { + return buf; + } + for(i = 0; i < sp->nelem; i++) { + buf = decode_long(&sp->elems[i], buf); + } + } + return buf; +} + + +unsigned char *decode_up_cred(up_cred *sp, unsigned char *buf) +{ + buf = decode_Ushort(&sp->uid, buf); + buf = decode_Ushort(&sp->euid, buf); + buf = decode_Ushort(&sp->suid, buf); + buf = decode_Ushort(&sp->gid, buf); + buf = decode_Ushort(&sp->egid, buf); + buf = decode_Ushort(&sp->sgid, buf); + buf = decode_Ushort(&sp->umask, buf); + buf = decode__userfs_types_004(&sp->groups, buf); + return buf; +} + + +unsigned char *decode_up_iattr(up_iattr *sp, unsigned char *buf) +{ + buf = decode_Ulong(&sp->ia_valid, buf); + buf = decode_Ushort(&sp->ia_mode, buf); + buf = decode_Ushort(&sp->ia_uid, buf); + buf = decode_Ushort(&sp->ia_gid, buf); + buf = decode_long(&sp->ia_size, buf); + buf = decode_long(&sp->ia_atime, buf); + buf = decode_long(&sp->ia_mtime, buf); + buf = decode_long(&sp->ia_ctime, buf); + return buf; +} + + +unsigned char *decode_up_preamble(up_preamble *sp, unsigned char *buf) +{ + buf = decode_short(&sp->version, buf); + buf = decode_long(&sp->seq, buf); + buf = decode_Uchar(&sp->op, buf); + buf = decode_Uchar(&sp->isreq, buf); + buf = decode_Ulong(&sp->size, buf); + return buf; +} + + +unsigned char *decode_upp_repl(upp_repl *sp, unsigned char *buf) +{ + buf = decode_short(&sp->version, buf); + buf = decode_long(&sp->seq, buf); + buf = decode_Uchar(&sp->op, buf); + buf = decode_Uchar(&sp->isreq, buf); + buf = decode_Ulong(&sp->size, buf); + buf = decode_long(&sp->err_no, buf); + return buf; +} + + +unsigned char *decode_up_inode(up_inode *sp, unsigned char *buf) +{ + buf = decode_Ushort(&sp->mode, buf); + buf = decode_Ushort(&sp->nlink, buf); + buf = decode_Ushort(&sp->uid, buf); + buf = decode_Ushort(&sp->gid, buf); + buf = decode_long(&sp->size, buf); + buf = decode_long(&sp->atime, buf); + buf = decode_long(&sp->mtime, buf); + buf = decode_long(&sp->ctime, buf); + buf = decode_Ushort(&sp->rdev, buf); + buf = decode_Ulong(&sp->blksize, buf); + buf = decode_Ulong(&sp->blocks, buf); + return buf; +} + + +unsigned char *decode_up_name(up_name *sp, unsigned char *buf) +{ + { + unsigned i; + buf = decode_Ulong(&sp->nelem, buf); + if (sp->nelem == 0) + { + sp->elems = 0; + return buf; + } + sp->elems = (char *)ALLOC(sizeof(char) * sp->nelem); + if (sp->elems == 0) { + return buf; + } + for(i = 0; i < sp->nelem; i++) { + buf = decode_char(&sp->elems[i], buf); + } + } + return buf; +} + + +unsigned char *decode_upp_iwrite_s(upp_iwrite_s *sp, unsigned char *buf) +{ + buf = decode_up_inode(&sp->ino, buf); + buf = decode_up_handle(&sp->handle, buf); + return buf; +} + + +unsigned char *decode_upp_iread_s(upp_iread_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->handle, buf); + return buf; +} + + +unsigned char *decode_upp_iread_r(upp_iread_r *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->handle, buf); + buf = decode_up_inode(&sp->ino, buf); + return buf; +} + + +unsigned char *decode_upp_unlink_s(upp_unlink_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->dir, buf); + buf = decode_up_name(&sp->name, buf); + return buf; +} + + +unsigned char *decode_upp_readlink_s(upp_readlink_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->link, buf); + return buf; +} + + +unsigned char *decode_upp_readlink_r(upp_readlink_r *sp, unsigned char *buf) +{ + buf = decode_up_name(&sp->name, buf); + return buf; +} + + +unsigned char *decode_upp_followlink_s(upp_followlink_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->dir, buf); + buf = decode_up_handle(&sp->link, buf); + buf = decode_long(&sp->flag, buf); + buf = decode_long(&sp->mode, buf); + return buf; +} + + +unsigned char *decode_upp_followlink_r(upp_followlink_r *sp, unsigned char *buf) +{ + buf = decode_up_name(&sp->path, buf); + return buf; +} + + +unsigned char *decode_upp_create_s(upp_create_s *sp, unsigned char *buf) +{ + buf = decode_long(&sp->mode, buf); + buf = decode_up_handle(&sp->dir, buf); + buf = decode_up_cred(&sp->cred, buf); + buf = decode_long(&sp->rdev, buf); + buf = decode_up_name(&sp->name, buf); + return buf; +} + + +unsigned char *decode_upp_create_r(upp_create_r *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->file, buf); + return buf; +} + + +unsigned char *decode_upp_lookup_s(upp_lookup_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->dir, buf); + buf = decode_up_name(&sp->name, buf); + return buf; +} + + +unsigned char *decode_upp_lookup_r(upp_lookup_r *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->handle, buf); + return buf; +} + + +unsigned char *decode_upp_read_s(upp_read_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->file, buf); + buf = decode_long(&sp->off, buf); + buf = decode_long(&sp->size, buf); + buf = decode_Ulong(&sp->ctok, buf); + return buf; +} + + +unsigned char *decode__userfs_types_006(_userfs_types_006 *sp, unsigned char *buf) +{ + { + unsigned i; + buf = decode_Ulong(&sp->nelem, buf); + if (sp->nelem == 0) + { + sp->elems = 0; + return buf; + } + sp->elems = (Uchar *)ALLOC(sizeof(Uchar) * sp->nelem); + if (sp->elems == 0) { + return buf; + } + for(i = 0; i < sp->nelem; i++) { + buf = decode_Uchar(&sp->elems[i], buf); + } + } + return buf; +} + + +unsigned char *decode_upp_read_r(upp_read_r *sp, unsigned char *buf) +{ + buf = decode__userfs_types_006(&sp->data, buf); + return buf; +} + + +unsigned char *decode__userfs_types_007(_userfs_types_007 *sp, unsigned char *buf) +{ + { + unsigned i; + buf = decode_Ulong(&sp->nelem, buf); + if (sp->nelem == 0) + { + sp->elems = 0; + return buf; + } + sp->elems = (Uchar *)ALLOC(sizeof(Uchar) * sp->nelem); + if (sp->elems == 0) { + return buf; + } + for(i = 0; i < sp->nelem; i++) { + buf = decode_Uchar(&sp->elems[i], buf); + } + } + return buf; +} + + +unsigned char *decode_upp_write_s(upp_write_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->file, buf); + buf = decode_long(&sp->off, buf); + buf = decode_Ulong(&sp->ctok, buf); + buf = decode__userfs_types_007(&sp->data, buf); + return buf; +} + + +unsigned char *decode_upp_write_r(upp_write_r *sp, unsigned char *buf) +{ + buf = decode_long(&sp->wrote, buf); + return buf; +} + + +unsigned char *decode_upp_readdir_s(upp_readdir_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->dir, buf); + buf = decode_long(&sp->off, buf); + buf = decode_Ulong(&sp->ctok, buf); + return buf; +} + + +unsigned char *decode_upp_readdir_r(upp_readdir_r *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->file, buf); + buf = decode_long(&sp->off, buf); + buf = decode_up_name(&sp->name, buf); + return buf; +} + + +unsigned char *decode_upp_multireaddir_s(upp_multireaddir_s *sp, unsigned char *buf) +{ + buf = decode_upp_readdir_s(sp, buf); + return buf; +} + + +unsigned char *decode_upp_multireaddir_r(upp_multireaddir_r *sp, unsigned char *buf) +{ + { + unsigned i; + buf = decode_Ulong(&sp->nelem, buf); + if (sp->nelem == 0) + { + sp->elems = 0; + return buf; + } + sp->elems = (upp_readdir_r *)ALLOC(sizeof(upp_readdir_r) * sp->nelem); + if (sp->elems == 0) { + return buf; + } + for(i = 0; i < sp->nelem; i++) { + buf = decode_upp_readdir_r(&sp->elems[i], buf); + } + } + return buf; +} + + +unsigned char *decode_upp_mount_r(upp_mount_r *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->root, buf); + return buf; +} + + +unsigned char *decode_upp_iput_s(upp_iput_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->handle, buf); + return buf; +} + + +unsigned char *decode_upp_open_s(upp_open_s *sp, unsigned char *buf) +{ + buf = decode_up_cred(&sp->cred, buf); + buf = decode_up_handle(&sp->file, buf); + return buf; +} + + +unsigned char *decode_upp_open_r(upp_open_r *sp, unsigned char *buf) +{ + buf = decode_Ulong(&sp->ctok, buf); + return buf; +} + + +unsigned char *decode_upp_close_s(upp_close_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->file, buf); + buf = decode_Ulong(&sp->ctok, buf); + return buf; +} + + +unsigned char *decode_upp_permission_s(upp_permission_s *sp, unsigned char *buf) +{ + buf = decode_up_cred(&sp->cred, buf); + buf = decode_up_handle(&sp->file, buf); + buf = decode_long(&sp->mask, buf); + return buf; +} + + +unsigned char *decode_upp_rename_s(upp_rename_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->odir, buf); + buf = decode_up_name(&sp->oname, buf); + buf = decode_up_handle(&sp->ndir, buf); + buf = decode_up_name(&sp->nname, buf); + return buf; +} + + +unsigned char *decode_upp_link_s(upp_link_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->ofile, buf); + buf = decode_up_handle(&sp->dir, buf); + buf = decode_up_name(&sp->name, buf); + return buf; +} + + +unsigned char *decode_upp_symlink_s(upp_symlink_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->dir, buf); + buf = decode_up_name(&sp->name, buf); + buf = decode_up_name(&sp->symname, buf); + buf = decode_up_cred(&sp->cred, buf); + return buf; +} + + +unsigned char *decode__userfs_types_011(_userfs_types_011 *sp, unsigned char *buf) +{ + { + unsigned i; + + for(i = 0; i < 2; i++) { + buf = decode_long(sp[i], buf); + } + } + return buf; +} + + +unsigned char *decode_upp_statfs_r(upp_statfs_r *sp, unsigned char *buf) +{ + buf = decode_long(&sp->bsize, buf); + buf = decode_long(&sp->blocks, buf); + buf = decode_long(&sp->bfree, buf); + buf = decode_long(&sp->bavail, buf); + buf = decode_long(&sp->files, buf); + buf = decode_long(&sp->ffree, buf); + buf = decode__userfs_types_011(&sp->fsid, buf); + buf = decode_long(&sp->namelen, buf); + return buf; +} + + +unsigned char *decode_upp_truncate_s(upp_truncate_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->file, buf); + buf = decode_long(&sp->size, buf); + return buf; +} + + +unsigned char *decode_upp_notify_change_s(upp_notify_change_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->handle, buf); + buf = decode_up_iattr(&sp->iattr, buf); + return buf; +} + + +unsigned char *decode_upp_inode_valid_s(upp_inode_valid_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->handle, buf); + buf = decode_Ulong(&sp->version, buf); + return buf; +} + + +unsigned char *decode_upp_inode_valid_r(upp_inode_valid_r *sp, unsigned char *buf) +{ + buf = decode_Ulong(&sp->version, buf); + buf = decode_char(&sp->valid, buf); + return buf; +} +unsigned int sizeof__userfs_types_001(const _userfs_types_001 *sp) +{ + unsigned int sz=0; + + { + unsigned i; + for(i = 0; i < 32; i++) { + sz += sizeof_Ulong(sp[i]); + } + } + return sz; +} +unsigned int sizeof__userfs_types_002(const _userfs_types_002 *sp) +{ + unsigned int sz=0; + + { + unsigned i; + for(i = 0; i < 2; i++) { + sz += sizeof_long(sp[i]); + } + } + return sz; +} +unsigned int sizeof_up_handle(const up_handle *sp) +{ + unsigned int sz=0; + + sz += sizeof_Ulong(&sp->handle); + return sz; +} +unsigned int sizeof_uf_uid_t(const uf_uid_t *sp) +{ + unsigned int sz=0; + + sz += sizeof_Ushort(sp); + return sz; +} +unsigned int sizeof__userfs_types_004(const _userfs_types_004 *sp) +{ + unsigned int sz=0; + + sz += sizeof_Ulong(&sp->nelem); + { + unsigned i; + for(i = 0; i < sp->nelem; i++) { + sz += sizeof_long(&sp->elems[i]); + } + } + return sz; +} +unsigned int sizeof_up_cred(const up_cred *sp) +{ + unsigned int sz=0; + + sz += sizeof_Ushort(&sp->uid); + sz += sizeof_Ushort(&sp->euid); + sz += sizeof_Ushort(&sp->suid); + sz += sizeof_Ushort(&sp->gid); + sz += sizeof_Ushort(&sp->egid); + sz += sizeof_Ushort(&sp->sgid); + sz += sizeof_Ushort(&sp->umask); + sz += sizeof__userfs_types_004(&sp->groups); + return sz; +} +unsigned int sizeof_up_iattr(const up_iattr *sp) +{ + unsigned int sz=0; + + sz += sizeof_Ulong(&sp->ia_valid); + sz += sizeof_Ushort(&sp->ia_mode); + sz += sizeof_Ushort(&sp->ia_uid); + sz += sizeof_Ushort(&sp->ia_gid); + sz += sizeof_long(&sp->ia_size); + sz += sizeof_long(&sp->ia_atime); + sz += sizeof_long(&sp->ia_mtime); + sz += sizeof_long(&sp->ia_ctime); + return sz; +} +unsigned int sizeof_up_preamble(const up_preamble *sp) +{ + unsigned int sz=0; + + sz += sizeof_short(&sp->version); + sz += sizeof_long(&sp->seq); + sz += sizeof_Uchar(&sp->op); + sz += sizeof_Uchar(&sp->isreq); + sz += sizeof_Ulong(&sp->size); + return sz; +} +unsigned int sizeof_upp_repl(const upp_repl *sp) +{ + unsigned int sz=0; + + sz += sizeof_short(&sp->version); + sz += sizeof_long(&sp->seq); + sz += sizeof_Uchar(&sp->op); + sz += sizeof_Uchar(&sp->isreq); + sz += sizeof_Ulong(&sp->size); + sz += sizeof_long(&sp->err_no); + return sz; +} +unsigned int sizeof_up_inode(const up_inode *sp) +{ + unsigned int sz=0; + + sz += sizeof_Ushort(&sp->mode); + sz += sizeof_Ushort(&sp->nlink); + sz += sizeof_Ushort(&sp->uid); + sz += sizeof_Ushort(&sp->gid); + sz += sizeof_long(&sp->size); + sz += sizeof_long(&sp->atime); + sz += sizeof_long(&sp->mtime); + sz += sizeof_long(&sp->ctime); + sz += sizeof_Ushort(&sp->rdev); + sz += sizeof_Ulong(&sp->blksize); + sz += sizeof_Ulong(&sp->blocks); + return sz; +} +unsigned int sizeof_up_name(const up_name *sp) +{ + unsigned int sz=0; + + sz += sizeof_Ulong(&sp->nelem); + { + unsigned i; + for(i = 0; i < sp->nelem; i++) { + sz += sizeof_char(&sp->elems[i]); + } + } + return sz; +} +unsigned int sizeof_upp_iwrite_s(const upp_iwrite_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_inode(&sp->ino); + sz += sizeof_up_handle(&sp->handle); + return sz; +} +unsigned int sizeof_upp_iread_s(const upp_iread_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->handle); + return sz; +} +unsigned int sizeof_upp_iread_r(const upp_iread_r *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->handle); + sz += sizeof_up_inode(&sp->ino); + return sz; +} +unsigned int sizeof_upp_unlink_s(const upp_unlink_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->dir); + sz += sizeof_up_name(&sp->name); + return sz; +} +unsigned int sizeof_upp_readlink_s(const upp_readlink_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->link); + return sz; +} +unsigned int sizeof_upp_readlink_r(const upp_readlink_r *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_name(&sp->name); + return sz; +} +unsigned int sizeof_upp_followlink_s(const upp_followlink_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->dir); + sz += sizeof_up_handle(&sp->link); + sz += sizeof_long(&sp->flag); + sz += sizeof_long(&sp->mode); + return sz; +} +unsigned int sizeof_upp_followlink_r(const upp_followlink_r *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_name(&sp->path); + return sz; +} +unsigned int sizeof_upp_create_s(const upp_create_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_long(&sp->mode); + sz += sizeof_up_handle(&sp->dir); + sz += sizeof_up_cred(&sp->cred); + sz += sizeof_long(&sp->rdev); + sz += sizeof_up_name(&sp->name); + return sz; +} +unsigned int sizeof_upp_create_r(const upp_create_r *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->file); + return sz; +} +unsigned int sizeof_upp_lookup_s(const upp_lookup_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->dir); + sz += sizeof_up_name(&sp->name); + return sz; +} +unsigned int sizeof_upp_lookup_r(const upp_lookup_r *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->handle); + return sz; +} +unsigned int sizeof_upp_read_s(const upp_read_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->file); + sz += sizeof_long(&sp->off); + sz += sizeof_long(&sp->size); + sz += sizeof_Ulong(&sp->ctok); + return sz; +} +unsigned int sizeof__userfs_types_006(const _userfs_types_006 *sp) +{ + unsigned int sz=0; + + sz += sizeof_Ulong(&sp->nelem); + { + unsigned i; + for(i = 0; i < sp->nelem; i++) { + sz += sizeof_Uchar(&sp->elems[i]); + } + } + return sz; +} +unsigned int sizeof_upp_read_r(const upp_read_r *sp) +{ + unsigned int sz=0; + + sz += sizeof__userfs_types_006(&sp->data); + return sz; +} +unsigned int sizeof__userfs_types_007(const _userfs_types_007 *sp) +{ + unsigned int sz=0; + + sz += sizeof_Ulong(&sp->nelem); + { + unsigned i; + for(i = 0; i < sp->nelem; i++) { + sz += sizeof_Uchar(&sp->elems[i]); + } + } + return sz; +} +unsigned int sizeof_upp_write_s(const upp_write_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->file); + sz += sizeof_long(&sp->off); + sz += sizeof_Ulong(&sp->ctok); + sz += sizeof__userfs_types_007(&sp->data); + return sz; +} +unsigned int sizeof_upp_write_r(const upp_write_r *sp) +{ + unsigned int sz=0; + + sz += sizeof_long(&sp->wrote); + return sz; +} +unsigned int sizeof_upp_readdir_s(const upp_readdir_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->dir); + sz += sizeof_long(&sp->off); + sz += sizeof_Ulong(&sp->ctok); + return sz; +} +unsigned int sizeof_upp_readdir_r(const upp_readdir_r *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->file); + sz += sizeof_long(&sp->off); + sz += sizeof_up_name(&sp->name); + return sz; +} +unsigned int sizeof_upp_multireaddir_s(const upp_multireaddir_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_upp_readdir_s(sp); + return sz; +} +unsigned int sizeof_upp_multireaddir_r(const upp_multireaddir_r *sp) +{ + unsigned int sz=0; + + sz += sizeof_Ulong(&sp->nelem); + { + unsigned i; + for(i = 0; i < sp->nelem; i++) { + sz += sizeof_upp_readdir_r(&sp->elems[i]); + } + } + return sz; +} +unsigned int sizeof_upp_mount_r(const upp_mount_r *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->root); + return sz; +} +unsigned int sizeof_upp_iput_s(const upp_iput_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->handle); + return sz; +} +unsigned int sizeof_upp_open_s(const upp_open_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_cred(&sp->cred); + sz += sizeof_up_handle(&sp->file); + return sz; +} +unsigned int sizeof_upp_open_r(const upp_open_r *sp) +{ + unsigned int sz=0; + + sz += sizeof_Ulong(&sp->ctok); + return sz; +} +unsigned int sizeof_upp_close_s(const upp_close_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->file); + sz += sizeof_Ulong(&sp->ctok); + return sz; +} +unsigned int sizeof_upp_permission_s(const upp_permission_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_cred(&sp->cred); + sz += sizeof_up_handle(&sp->file); + sz += sizeof_long(&sp->mask); + return sz; +} +unsigned int sizeof_upp_rename_s(const upp_rename_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->odir); + sz += sizeof_up_name(&sp->oname); + sz += sizeof_up_handle(&sp->ndir); + sz += sizeof_up_name(&sp->nname); + return sz; +} +unsigned int sizeof_upp_link_s(const upp_link_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->ofile); + sz += sizeof_up_handle(&sp->dir); + sz += sizeof_up_name(&sp->name); + return sz; +} +unsigned int sizeof_upp_symlink_s(const upp_symlink_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->dir); + sz += sizeof_up_name(&sp->name); + sz += sizeof_up_name(&sp->symname); + sz += sizeof_up_cred(&sp->cred); + return sz; +} +unsigned int sizeof__userfs_types_011(const _userfs_types_011 *sp) +{ + unsigned int sz=0; + + { + unsigned i; + for(i = 0; i < 2; i++) { + sz += sizeof_long(sp[i]); + } + } + return sz; +} +unsigned int sizeof_upp_statfs_r(const upp_statfs_r *sp) +{ + unsigned int sz=0; + + sz += sizeof_long(&sp->bsize); + sz += sizeof_long(&sp->blocks); + sz += sizeof_long(&sp->bfree); + sz += sizeof_long(&sp->bavail); + sz += sizeof_long(&sp->files); + sz += sizeof_long(&sp->ffree); + sz += sizeof__userfs_types_011(&sp->fsid); + sz += sizeof_long(&sp->namelen); + return sz; +} +unsigned int sizeof_upp_truncate_s(const upp_truncate_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->file); + sz += sizeof_long(&sp->size); + return sz; +} +unsigned int sizeof_upp_notify_change_s(const upp_notify_change_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->handle); + sz += sizeof_up_iattr(&sp->iattr); + return sz; +} +unsigned int sizeof_upp_inode_valid_s(const upp_inode_valid_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->handle); + sz += sizeof_Ulong(&sp->version); + return sz; +} +unsigned int sizeof_upp_inode_valid_r(const upp_inode_valid_r *sp) +{ + unsigned int sz=0; + + sz += sizeof_Ulong(&sp->version); + sz += sizeof_char(&sp->valid); + return sz; +} Added: trunk/kernel/linux/userfs_fs_i.h ============================================================================== --- trunk/kernel/linux/userfs_fs_i.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/linux/userfs_fs_i.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,25 @@ +/* + * Inode data for userfs + */ + +#ifndef _LINUX_USERFS_FS_I +#define _LINUX_USERFS_FS_I + +/* + * What a handle looks like + */ +typedef struct +{ + unsigned long handle; +} up_handle; + +typedef unsigned long up_version; + +struct userfs_inode_info +{ + up_handle handle; + struct userfs_dir_ra *dir_ra; + up_version version; +}; + +#endif /* _LINUX_USERFS_FS_I */ Added: trunk/kernel/linux/Makefile ============================================================================== --- trunk/kernel/linux/Makefile 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/linux/Makefile 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,25 @@ +# Generate some "headers" + +TOP=../.. +CPPFLAGS=-I.. + +include $(TOP)/rules + +.SUFFIXES: .ty + +.ty.c: + $(GENCODE) $(CPPFLAGS) -sed $< > $@ + +.ty.h: + $(GENHDR) $(CPPFLAGS) $< > $@ + +dep depend all:: userfs_types.c userfs_types.h coder.h + +userfs_types.c: userfs_types.ty $(GENCODE) +userfs_types.h: userfs_types.ty $(GENHDR) + +coder.h: + ln -s $(GENDIR)/coder.h . + +clean:: + rm -f userfs_types.[ch] coder.h *~ Added: trunk/kernel/src/linux/userfs_mount.h ============================================================================== --- trunk/kernel/src/linux/userfs_mount.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/src/linux/userfs_mount.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,30 @@ +/* + * Information passed from user process to the kernel as the + * 3rd argument to mount(2). + */ + +#ifndef _LINUX_USERFS_MOUNT +#define _LINUX_USERFS_MOUNT + +/* + * WARNING! Do not delete or change the order of these fields. If + * a new field is required then add it to the end. The version field + * tracks which fields are present. This will ensure some measure of + * mount-to-kernel version compatibilty. Some of these aren't used yet + * but here they are anyway. + */ + +/* Change this if things are added to the structure below */ +#define USERFS_VERSION 3 + + +struct userfs_mount +{ + int version; /* v1 - version of structure */ + int tokern; /* v1 - fd of stream into the kernel */ + int fromkern; /* v1 - from kernel */ + int magic; /* v2 - magic */ + int seq; /* v3 - initial sequence number */ +}; + +#endif /* _LINUX_USERFS_MOUNT */ Added: trunk/kernel/src/linux/userfs_types.h ============================================================================== --- trunk/kernel/src/linux/userfs_types.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/src/linux/userfs_types.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,895 @@ +/* -*- C -*- + * DO NOT EDIT BY HAND! + * + * This was automatically generated from "userfs_types.ty" by genhdr. + */ + +#ifndef __USERFS_TYPES_H_SEEN__ +#define __USERFS_TYPES_H_SEEN__ + +#ifndef __KERNEL__ +#include +#include +typedef __kernel_suseconds_t suseconds_t; +typedef __u8 uint8_t; +typedef __u16 uint16_t; +typedef __u32 uint32_t; +#undef __FD_ZERO +#undef __FD_SET +#undef __FD_CLR +#undef __FD_ISSET +#endif +#if !defined(ALLOC) +# if defined(__KERNEL__) +# include +# include +# include +# define ALLOC(x) kmalloc(x, GFP_KERNEL) +# define FREE(x) kfree(x) +# else +# define ALLOC ALLOC +# include +# include +#ifdef __GLIBC__ +#include +#include +typedef unsigned char unchar; +#endif +static __inline__ void *ALLOC(int alloc) +{ + void *mem = malloc(alloc); + + assert(mem != 0); + return mem; +} +#define FREE(x) free(x) +# endif /* __KERNEL__ */ +#endif /* ALLOC */ +#include +#include +#include +#define UP_REPL 0 /* Is a reply */ +#define UP_REQ 1 /* Is a request */ +#define UP_ENQ 2 /* Is capability enquiry */ +#ifndef _NO_CODER_H_ +/* Type encode/decode routines */ +#include "coder.h" /* Standard routines */ +#endif /* _NO_CODER_H_ */ +/* Encoded types */ + +typedef Ulong _userfs_types_001[32]; +typedef long _userfs_types_002[2]; +typedef Ulong _userfs_types_003[32]; +typedef ushort uf_uid_t; +typedef ushort uf_gid_t; +typedef ushort uf_nlink_t; +typedef ushort uf_dev_t; +typedef struct +{ + Ulong nelem; + long* elems; +} _userfs_types_004; +typedef struct +{ + uf_uid_t uid; + uf_uid_t euid; + uf_uid_t suid; + uf_uid_t gid; + uf_uid_t egid; + uf_uid_t sgid; + uf_uid_t umask; + _userfs_types_004 groups; +} up_cred; +typedef struct +{ + Ulong ia_valid; + umode_t ia_mode; + uf_uid_t ia_uid; + uf_gid_t ia_gid; + off_t ia_size; + time_t ia_atime; + time_t ia_mtime; + time_t ia_ctime; +} up_iattr; +typedef struct +{ + __s16 version; + long seq; + Uchar op; + Uchar isreq; + Ulong size; +} up_preamble; +typedef struct +{ + __s16 version; + long seq; + Uchar op; + Uchar isreq; + Ulong size; + long err_no; +} upp_repl; +typedef struct +{ + umode_t mode; + uf_nlink_t nlink; + uf_uid_t uid; + uf_gid_t gid; + off_t size; + time_t atime; + time_t mtime; + time_t ctime; + uf_dev_t rdev; + Ulong blksize; + Ulong blocks; +} up_inode; +typedef struct +{ + Ulong nelem; + __s8* elems; +} up_name; +typedef struct +{ + up_inode ino; + up_handle handle; +} upp_iwrite_s; +typedef struct +{ + up_handle handle; +} upp_iread_s; +typedef struct +{ + up_handle handle; + up_inode ino; +} upp_iread_r; +typedef struct +{ + up_handle dir; + up_name name; +} upp_unlink_s; +typedef struct +{ + up_handle link; +} upp_readlink_s; +typedef struct +{ + up_name name; +} upp_readlink_r; +typedef struct +{ + up_handle dir; + up_handle link; + long flag; + long mode; +} upp_followlink_s; +typedef struct +{ + up_name path; +} upp_followlink_r; +typedef struct +{ + Ulong nelem; + long* elems; +} _userfs_types_005; +typedef struct +{ + long mode; + up_handle dir; + up_cred cred; + long rdev; + up_name name; +} upp_create_s; +typedef struct +{ + up_handle file; +} upp_create_r; +typedef struct +{ + up_handle dir; + up_name name; +} upp_lookup_s; +typedef struct +{ + up_handle handle; +} upp_lookup_r; +typedef struct +{ + up_handle file; + off_t off; + off_t size; + up_credtok ctok; +} upp_read_s; +typedef struct +{ + Ulong nelem; + Uchar* elems; +} _userfs_types_006; +typedef struct +{ + _userfs_types_006 data; +} upp_read_r; +typedef struct +{ + Ulong nelem; + Uchar* elems; +} _userfs_types_007; +typedef struct +{ + up_handle file; + off_t off; + up_credtok ctok; + _userfs_types_007 data; +} upp_write_s; +typedef struct +{ + off_t wrote; +} upp_write_r; +typedef struct +{ + up_handle dir; + off_t off; + up_credtok ctok; +} upp_readdir_s; +typedef struct +{ + up_handle file; + off_t off; + up_name name; +} upp_readdir_r; +typedef upp_readdir_s upp_multireaddir_s; +typedef struct +{ + Ulong nelem; + upp_readdir_r* elems; +} upp_multireaddir_r; +typedef struct +{ + up_handle root; +} upp_mount_r; +typedef struct +{ + up_handle handle; +} upp_iput_s; +typedef struct +{ + Ulong nelem; + long* elems; +} _userfs_types_008; +typedef struct +{ + up_cred cred; + up_handle file; +} upp_open_s; +typedef struct +{ + up_credtok ctok; +} upp_open_r; +typedef struct +{ + up_handle file; + up_credtok ctok; +} upp_close_s; +typedef struct +{ + Ulong nelem; + long* elems; +} _userfs_types_009; +typedef struct +{ + up_cred cred; + up_handle file; + long mask; +} upp_permission_s; +typedef struct +{ + up_handle odir; + up_name oname; + up_handle ndir; + up_name nname; +} upp_rename_s; +typedef struct +{ + up_handle ofile; + up_handle dir; + up_name name; +} upp_link_s; +typedef struct +{ + Ulong nelem; + long* elems; +} _userfs_types_010; +typedef struct +{ + up_handle dir; + up_name name; + up_name symname; + up_cred cred; +} upp_symlink_s; +typedef long _userfs_types_011[2]; +typedef struct +{ + __kernel_off_t bsize; + __kernel_off_t blocks; + __kernel_off_t bfree; + __kernel_off_t bavail; + __kernel_off_t files; + __kernel_off_t ffree; + _userfs_types_011 fsid; + __kernel_off_t namelen; +} upp_statfs_r; +typedef struct +{ + up_handle file; + off_t size; +} upp_truncate_s; +typedef struct +{ + up_handle handle; + up_iattr iattr; +} upp_notify_change_s; +typedef struct +{ + up_handle handle; + up_version version; +} upp_inode_valid_s; +typedef struct +{ + up_version version; + __s8 valid; +} upp_inode_valid_r; +static unsigned char *encode_char(const char *, unsigned char *); +static unsigned char *decode_char(char *, unsigned char *); +static unsigned int sizeof_char(const char *); + +static unsigned char *encode_short(const short *, unsigned char *); +static unsigned char *decode_short(short *, unsigned char *); +static unsigned int sizeof_short(const short *); + +static unsigned char *encode_long(const long *, unsigned char *); +static unsigned char *decode_long(long *, unsigned char *); +static unsigned int sizeof_long(const long *); + +static unsigned char *encode_longlong(const longlong *, unsigned char *); +static unsigned char *decode_longlong(longlong *, unsigned char *); +static unsigned int sizeof_longlong(const longlong *); + +static unsigned char *encode_float(const float *, unsigned char *); +static unsigned char *decode_float(float *, unsigned char *); +static unsigned int sizeof_float(const float *); + +static unsigned char *encode_double(const double *, unsigned char *); +static unsigned char *decode_double(double *, unsigned char *); +static unsigned int sizeof_double(const double *); + +static unsigned char *encode_void(const void *, unsigned char *); +static unsigned char *decode_void(void *, unsigned char *); +static unsigned int sizeof_void(const void *); + +static unsigned char *encode_Uchar(const Uchar *, unsigned char *); +static unsigned char *decode_Uchar(Uchar *, unsigned char *); +static unsigned int sizeof_Uchar(const Uchar *); + +static unsigned char *encode_Ushort(const Ushort *, unsigned char *); +static unsigned char *decode_Ushort(Ushort *, unsigned char *); +static unsigned int sizeof_Ushort(const Ushort *); + +static unsigned char *encode_Ulong(const Ulong *, unsigned char *); +static unsigned char *decode_Ulong(Ulong *, unsigned char *); +static unsigned int sizeof_Ulong(const Ulong *); + +static unsigned char *encode_Ulonglong(const Ulonglong *, unsigned char *); +static unsigned char *decode_Ulonglong(Ulonglong *, unsigned char *); +static unsigned int sizeof_Ulonglong(const Ulonglong *); + +unsigned char *encode_Uint(const Uint *, unsigned char *); +unsigned char *decode_Uint(Uint *, unsigned char *); +unsigned int sizeof_Uint(const Uint *); + +unsigned char *encode_int(const int *, unsigned char *); +unsigned char *decode_int(int *, unsigned char *); +unsigned int sizeof_int(const int *); + +unsigned char *encode__userfs_types_001(const _userfs_types_001 *, unsigned char *); +unsigned char *decode__userfs_types_001(_userfs_types_001 *, unsigned char *); +unsigned int sizeof__userfs_types_001(const _userfs_types_001 *); + +unsigned char *encode___kernel_fd_set(const __kernel_fd_set *, unsigned char *); +unsigned char *decode___kernel_fd_set(__kernel_fd_set *, unsigned char *); +unsigned int sizeof___kernel_fd_set(const __kernel_fd_set *); + +unsigned char *encode___kernel_key_t(const __kernel_key_t *, unsigned char *); +unsigned char *decode___kernel_key_t(__kernel_key_t *, unsigned char *); +unsigned int sizeof___kernel_key_t(const __kernel_key_t *); + +unsigned char *encode___kernel_dev_t(const __kernel_dev_t *, unsigned char *); +unsigned char *decode___kernel_dev_t(__kernel_dev_t *, unsigned char *); +unsigned int sizeof___kernel_dev_t(const __kernel_dev_t *); + +unsigned char *encode___kernel_ino_t(const __kernel_ino_t *, unsigned char *); +unsigned char *decode___kernel_ino_t(__kernel_ino_t *, unsigned char *); +unsigned int sizeof___kernel_ino_t(const __kernel_ino_t *); + +unsigned char *encode___kernel_mode_t(const __kernel_mode_t *, unsigned char *); +unsigned char *decode___kernel_mode_t(__kernel_mode_t *, unsigned char *); +unsigned int sizeof___kernel_mode_t(const __kernel_mode_t *); + +unsigned char *encode___kernel_nlink_t(const __kernel_nlink_t *, unsigned char *); +unsigned char *decode___kernel_nlink_t(__kernel_nlink_t *, unsigned char *); +unsigned int sizeof___kernel_nlink_t(const __kernel_nlink_t *); + +unsigned char *encode___kernel_off_t(const __kernel_off_t *, unsigned char *); +unsigned char *decode___kernel_off_t(__kernel_off_t *, unsigned char *); +unsigned int sizeof___kernel_off_t(const __kernel_off_t *); + +unsigned char *encode___kernel_pid_t(const __kernel_pid_t *, unsigned char *); +unsigned char *decode___kernel_pid_t(__kernel_pid_t *, unsigned char *); +unsigned int sizeof___kernel_pid_t(const __kernel_pid_t *); + +unsigned char *encode___kernel_ipc_pid_t(const __kernel_ipc_pid_t *, unsigned char *); +unsigned char *decode___kernel_ipc_pid_t(__kernel_ipc_pid_t *, unsigned char *); +unsigned int sizeof___kernel_ipc_pid_t(const __kernel_ipc_pid_t *); + +unsigned char *encode___kernel_uid_t(const __kernel_uid_t *, unsigned char *); +unsigned char *decode___kernel_uid_t(__kernel_uid_t *, unsigned char *); +unsigned int sizeof___kernel_uid_t(const __kernel_uid_t *); + +unsigned char *encode___kernel_gid_t(const __kernel_gid_t *, unsigned char *); +unsigned char *decode___kernel_gid_t(__kernel_gid_t *, unsigned char *); +unsigned int sizeof___kernel_gid_t(const __kernel_gid_t *); + +unsigned char *encode___kernel_size_t(const __kernel_size_t *, unsigned char *); +unsigned char *decode___kernel_size_t(__kernel_size_t *, unsigned char *); +unsigned int sizeof___kernel_size_t(const __kernel_size_t *); + +unsigned char *encode___kernel_ssize_t(const __kernel_ssize_t *, unsigned char *); +unsigned char *decode___kernel_ssize_t(__kernel_ssize_t *, unsigned char *); +unsigned int sizeof___kernel_ssize_t(const __kernel_ssize_t *); + +unsigned char *encode___kernel_ptrdiff_t(const __kernel_ptrdiff_t *, unsigned char *); +unsigned char *decode___kernel_ptrdiff_t(__kernel_ptrdiff_t *, unsigned char *); +unsigned int sizeof___kernel_ptrdiff_t(const __kernel_ptrdiff_t *); + +unsigned char *encode___kernel_time_t(const __kernel_time_t *, unsigned char *); +unsigned char *decode___kernel_time_t(__kernel_time_t *, unsigned char *); +unsigned int sizeof___kernel_time_t(const __kernel_time_t *); + +unsigned char *encode___kernel_suseconds_t(const __kernel_suseconds_t *, unsigned char *); +unsigned char *decode___kernel_suseconds_t(__kernel_suseconds_t *, unsigned char *); +unsigned int sizeof___kernel_suseconds_t(const __kernel_suseconds_t *); + +unsigned char *encode___kernel_clock_t(const __kernel_clock_t *, unsigned char *); +unsigned char *decode___kernel_clock_t(__kernel_clock_t *, unsigned char *); +unsigned int sizeof___kernel_clock_t(const __kernel_clock_t *); + +unsigned char *encode___kernel_daddr_t(const __kernel_daddr_t *, unsigned char *); +unsigned char *decode___kernel_daddr_t(__kernel_daddr_t *, unsigned char *); +unsigned int sizeof___kernel_daddr_t(const __kernel_daddr_t *); + +unsigned char *encode___kernel_caddr_t(const __kernel_caddr_t *, unsigned char *); +unsigned char *decode___kernel_caddr_t(__kernel_caddr_t *, unsigned char *); +unsigned int sizeof___kernel_caddr_t(const __kernel_caddr_t *); + +unsigned char *encode___kernel_uid16_t(const /* __kernel_uid16_t */ unsigned short *, unsigned char *); +unsigned char *decode___kernel_uid16_t(/* __kernel_uid16_t */ unsigned short *, unsigned char *); +unsigned int sizeof___kernel_uid16_t(const /* __kernel_uid16_t */ unsigned short *); + +unsigned char *encode___kernel_gid16_t(const /* __kernel_gid16_t */ unsigned short *, unsigned char *); +unsigned char *decode___kernel_gid16_t(/* __kernel_gid16_t */ unsigned short *, unsigned char *); +unsigned int sizeof___kernel_gid16_t(const /* __kernel_gid16_t */ unsigned short *); + +unsigned char *encode___kernel_uid32_t(const /*__kernel_uid32_t */ unsigned int *, unsigned char *); +unsigned char *decode___kernel_uid32_t(/*__kernel_uid32_t */ unsigned int *, unsigned char *); +unsigned int sizeof___kernel_uid32_t(const /*__kernel_uid32_t */ unsigned int *); + +unsigned char *encode___kernel_gid32_t(const /*__kernel_gid32_t */ unsigned int *, unsigned char *); +unsigned char *decode___kernel_gid32_t(/*__kernel_gid32_t */ unsigned int *, unsigned char *); +unsigned int sizeof___kernel_gid32_t(const /*__kernel_gid32_t */ unsigned int *); + +unsigned char *encode___kernel_old_uid_t(const /*__kernel_old_uid_t */ unsigned short *, unsigned char *); +unsigned char *decode___kernel_old_uid_t(/*__kernel_old_uid_t */ unsigned short *, unsigned char *); +unsigned int sizeof___kernel_old_uid_t(const /*__kernel_old_uid_t */ unsigned short *); + +unsigned char *encode___kernel_old_gid_t(const /*__kernel_old_gid_t */ unsigned short *, unsigned char *); +unsigned char *decode___kernel_old_gid_t(/*__kernel_old_gid_t */ unsigned short *, unsigned char *); +unsigned int sizeof___kernel_old_gid_t(const /*__kernel_old_gid_t */ unsigned short *); + +unsigned char *encode__userfs_types_002(const _userfs_types_002 *, unsigned char *); +unsigned char *decode__userfs_types_002(_userfs_types_002 *, unsigned char *); +unsigned int sizeof__userfs_types_002(const _userfs_types_002 *); + +unsigned char *encode___kernel_fsid_t(const __kernel_fsid_t *, unsigned char *); +unsigned char *decode___kernel_fsid_t(__kernel_fsid_t *, unsigned char *); +unsigned int sizeof___kernel_fsid_t(const __kernel_fsid_t *); + +unsigned char *encode_umode_t(const umode_t *, unsigned char *); +unsigned char *decode_umode_t(umode_t *, unsigned char *); +unsigned int sizeof_umode_t(const umode_t *); + +unsigned char *encode___s8(const __s8 *, unsigned char *); +unsigned char *decode___s8(__s8 *, unsigned char *); +unsigned int sizeof___s8(const __s8 *); + +unsigned char *encode___u8(const __u8 *, unsigned char *); +unsigned char *decode___u8(__u8 *, unsigned char *); +unsigned int sizeof___u8(const __u8 *); + +unsigned char *encode___s16(const __s16 *, unsigned char *); +unsigned char *decode___s16(__s16 *, unsigned char *); +unsigned int sizeof___s16(const __s16 *); + +unsigned char *encode___u16(const __u16 *, unsigned char *); +unsigned char *decode___u16(__u16 *, unsigned char *); +unsigned int sizeof___u16(const __u16 *); + +unsigned char *encode___s32(const __s32 *, unsigned char *); +unsigned char *decode___s32(__s32 *, unsigned char *); +unsigned int sizeof___s32(const __s32 *); + +unsigned char *encode___u32(const __u32 *, unsigned char *); +unsigned char *decode___u32(__u32 *, unsigned char *); +unsigned int sizeof___u32(const __u32 *); + +unsigned char *encode__userfs_types_003(const _userfs_types_003 *, unsigned char *); +unsigned char *decode__userfs_types_003(_userfs_types_003 *, unsigned char *); +unsigned int sizeof__userfs_types_003(const _userfs_types_003 *); + +unsigned char *encode_fd_set(const fd_set *, unsigned char *); +unsigned char *decode_fd_set(fd_set *, unsigned char *); +unsigned int sizeof_fd_set(const fd_set *); + +unsigned char *encode_dev_t(const dev_t *, unsigned char *); +unsigned char *decode_dev_t(dev_t *, unsigned char *); +unsigned int sizeof_dev_t(const dev_t *); + +unsigned char *encode_ino_t(const ino_t *, unsigned char *); +unsigned char *decode_ino_t(ino_t *, unsigned char *); +unsigned int sizeof_ino_t(const ino_t *); + +unsigned char *encode_mode_t(const mode_t *, unsigned char *); +unsigned char *decode_mode_t(mode_t *, unsigned char *); +unsigned int sizeof_mode_t(const mode_t *); + +unsigned char *encode_nlink_t(const nlink_t *, unsigned char *); +unsigned char *decode_nlink_t(nlink_t *, unsigned char *); +unsigned int sizeof_nlink_t(const nlink_t *); + +unsigned char *encode_off_t(const off_t *, unsigned char *); +unsigned char *decode_off_t(off_t *, unsigned char *); +unsigned int sizeof_off_t(const off_t *); + +unsigned char *encode_pid_t(const pid_t *, unsigned char *); +unsigned char *decode_pid_t(pid_t *, unsigned char *); +unsigned int sizeof_pid_t(const pid_t *); + +unsigned char *encode_daddr_t(const daddr_t *, unsigned char *); +unsigned char *decode_daddr_t(daddr_t *, unsigned char *); +unsigned int sizeof_daddr_t(const daddr_t *); + +unsigned char *encode_key_t(const key_t *, unsigned char *); +unsigned char *decode_key_t(key_t *, unsigned char *); +unsigned int sizeof_key_t(const key_t *); + +unsigned char *encode_suseconds_t(const suseconds_t *, unsigned char *); +unsigned char *decode_suseconds_t(suseconds_t *, unsigned char *); +unsigned int sizeof_suseconds_t(const suseconds_t *); + +unsigned char *encode_uid_t(const uid_t *, unsigned char *); +unsigned char *decode_uid_t(uid_t *, unsigned char *); +unsigned int sizeof_uid_t(const uid_t *); + +unsigned char *encode_gid_t(const gid_t *, unsigned char *); +unsigned char *decode_gid_t(gid_t *, unsigned char *); +unsigned int sizeof_gid_t(const gid_t *); + +unsigned char *encode_size_t(const size_t *, unsigned char *); +unsigned char *decode_size_t(size_t *, unsigned char *); +unsigned int sizeof_size_t(const size_t *); + +unsigned char *encode_ssize_t(const ssize_t *, unsigned char *); +unsigned char *decode_ssize_t(ssize_t *, unsigned char *); +unsigned int sizeof_ssize_t(const ssize_t *); + +unsigned char *encode_ptrdiff_t(const ptrdiff_t *, unsigned char *); +unsigned char *decode_ptrdiff_t(ptrdiff_t *, unsigned char *); +unsigned int sizeof_ptrdiff_t(const ptrdiff_t *); + +unsigned char *encode_time_t(const time_t *, unsigned char *); +unsigned char *decode_time_t(time_t *, unsigned char *); +unsigned int sizeof_time_t(const time_t *); + +unsigned char *encode_clock_t(const clock_t *, unsigned char *); +unsigned char *decode_clock_t(clock_t *, unsigned char *); +unsigned int sizeof_clock_t(const clock_t *); + +unsigned char *encode_caddr_t(const caddr_t *, unsigned char *); +unsigned char *decode_caddr_t(caddr_t *, unsigned char *); +unsigned int sizeof_caddr_t(const caddr_t *); + +unsigned char *encode_u_char(const u_char *, unsigned char *); +unsigned char *decode_u_char(u_char *, unsigned char *); +unsigned int sizeof_u_char(const u_char *); + +unsigned char *encode_u_short(const u_short *, unsigned char *); +unsigned char *decode_u_short(u_short *, unsigned char *); +unsigned int sizeof_u_short(const u_short *); + +unsigned char *encode_u_int(const u_int *, unsigned char *); +unsigned char *decode_u_int(u_int *, unsigned char *); +unsigned int sizeof_u_int(const u_int *); + +unsigned char *encode_u_long(const u_long *, unsigned char *); +unsigned char *decode_u_long(u_long *, unsigned char *); +unsigned int sizeof_u_long(const u_long *); + +unsigned char *encode_unchar(const unchar *, unsigned char *); +unsigned char *decode_unchar(unchar *, unsigned char *); +unsigned int sizeof_unchar(const unchar *); + +unsigned char *encode_ushort(const ushort *, unsigned char *); +unsigned char *decode_ushort(ushort *, unsigned char *); +unsigned int sizeof_ushort(const ushort *); + +unsigned char *encode_uint(const uint *, unsigned char *); +unsigned char *decode_uint(uint *, unsigned char *); +unsigned int sizeof_uint(const uint *); + +unsigned char *encode_ulong(const ulong *, unsigned char *); +unsigned char *decode_ulong(ulong *, unsigned char *); +unsigned int sizeof_ulong(const ulong *); + +unsigned char *encode_u_int8_t(const u_int8_t *, unsigned char *); +unsigned char *decode_u_int8_t(u_int8_t *, unsigned char *); +unsigned int sizeof_u_int8_t(const u_int8_t *); + +unsigned char *encode_int8_t(const int8_t *, unsigned char *); +unsigned char *decode_int8_t(int8_t *, unsigned char *); +unsigned int sizeof_int8_t(const int8_t *); + +unsigned char *encode_u_int16_t(const u_int16_t *, unsigned char *); +unsigned char *decode_u_int16_t(u_int16_t *, unsigned char *); +unsigned int sizeof_u_int16_t(const u_int16_t *); + +unsigned char *encode_int16_t(const int16_t *, unsigned char *); +unsigned char *decode_int16_t(int16_t *, unsigned char *); +unsigned int sizeof_int16_t(const int16_t *); + +unsigned char *encode_u_int32_t(const u_int32_t *, unsigned char *); +unsigned char *decode_u_int32_t(u_int32_t *, unsigned char *); +unsigned int sizeof_u_int32_t(const u_int32_t *); + +unsigned char *encode_int32_t(const int32_t *, unsigned char *); +unsigned char *decode_int32_t(int32_t *, unsigned char *); +unsigned int sizeof_int32_t(const int32_t *); + +unsigned char *encode_uint8_t(const uint8_t *, unsigned char *); +unsigned char *decode_uint8_t(uint8_t *, unsigned char *); +unsigned int sizeof_uint8_t(const uint8_t *); + +unsigned char *encode_uint16_t(const uint16_t *, unsigned char *); +unsigned char *decode_uint16_t(uint16_t *, unsigned char *); +unsigned int sizeof_uint16_t(const uint16_t *); + +unsigned char *encode_uint32_t(const uint32_t *, unsigned char *); +unsigned char *decode_uint32_t(uint32_t *, unsigned char *); +unsigned int sizeof_uint32_t(const uint32_t *); + +unsigned char *encode_up_handle(const up_handle *, unsigned char *); +unsigned char *decode_up_handle(up_handle *, unsigned char *); +unsigned int sizeof_up_handle(const up_handle *); + +unsigned char *encode_up_version(const up_version *, unsigned char *); +unsigned char *decode_up_version(up_version *, unsigned char *); +unsigned int sizeof_up_version(const up_version *); + +unsigned char *encode_up_credtok(const up_credtok *, unsigned char *); +unsigned char *decode_up_credtok(up_credtok *, unsigned char *); +unsigned int sizeof_up_credtok(const up_credtok *); + +unsigned char *encode_uf_uid_t(const uf_uid_t *, unsigned char *); +unsigned char *decode_uf_uid_t(uf_uid_t *, unsigned char *); +unsigned int sizeof_uf_uid_t(const uf_uid_t *); + +unsigned char *encode_uf_gid_t(const uf_gid_t *, unsigned char *); +unsigned char *decode_uf_gid_t(uf_gid_t *, unsigned char *); +unsigned int sizeof_uf_gid_t(const uf_gid_t *); + +unsigned char *encode_uf_nlink_t(const uf_nlink_t *, unsigned char *); +unsigned char *decode_uf_nlink_t(uf_nlink_t *, unsigned char *); +unsigned int sizeof_uf_nlink_t(const uf_nlink_t *); + +unsigned char *encode_uf_dev_t(const uf_dev_t *, unsigned char *); +unsigned char *decode_uf_dev_t(uf_dev_t *, unsigned char *); +unsigned int sizeof_uf_dev_t(const uf_dev_t *); + +unsigned char *encode__userfs_types_004(const _userfs_types_004 *, unsigned char *); +unsigned char *decode__userfs_types_004(_userfs_types_004 *, unsigned char *); +unsigned int sizeof__userfs_types_004(const _userfs_types_004 *); + +unsigned char *encode_up_cred(const up_cred *, unsigned char *); +unsigned char *decode_up_cred(up_cred *, unsigned char *); +unsigned int sizeof_up_cred(const up_cred *); + +unsigned char *encode_up_iattr(const up_iattr *, unsigned char *); +unsigned char *decode_up_iattr(up_iattr *, unsigned char *); +unsigned int sizeof_up_iattr(const up_iattr *); + +unsigned char *encode_up_preamble(const up_preamble *, unsigned char *); +unsigned char *decode_up_preamble(up_preamble *, unsigned char *); +unsigned int sizeof_up_preamble(const up_preamble *); + +unsigned char *encode_upp_repl(const upp_repl *, unsigned char *); +unsigned char *decode_upp_repl(upp_repl *, unsigned char *); +unsigned int sizeof_upp_repl(const upp_repl *); + +unsigned char *encode_up_inode(const up_inode *, unsigned char *); +unsigned char *decode_up_inode(up_inode *, unsigned char *); +unsigned int sizeof_up_inode(const up_inode *); + +unsigned char *encode_up_name(const up_name *, unsigned char *); +unsigned char *decode_up_name(up_name *, unsigned char *); +unsigned int sizeof_up_name(const up_name *); + +unsigned char *encode_upp_iwrite_s(const upp_iwrite_s *, unsigned char *); +unsigned char *decode_upp_iwrite_s(upp_iwrite_s *, unsigned char *); +unsigned int sizeof_upp_iwrite_s(const upp_iwrite_s *); + +unsigned char *encode_upp_iread_s(const upp_iread_s *, unsigned char *); +unsigned char *decode_upp_iread_s(upp_iread_s *, unsigned char *); +unsigned int sizeof_upp_iread_s(const upp_iread_s *); + +unsigned char *encode_upp_iread_r(const upp_iread_r *, unsigned char *); +unsigned char *decode_upp_iread_r(upp_iread_r *, unsigned char *); +unsigned int sizeof_upp_iread_r(const upp_iread_r *); + +unsigned char *encode_upp_unlink_s(const upp_unlink_s *, unsigned char *); +unsigned char *decode_upp_unlink_s(upp_unlink_s *, unsigned char *); +unsigned int sizeof_upp_unlink_s(const upp_unlink_s *); + +unsigned char *encode_upp_readlink_s(const upp_readlink_s *, unsigned char *); +unsigned char *decode_upp_readlink_s(upp_readlink_s *, unsigned char *); +unsigned int sizeof_upp_readlink_s(const upp_readlink_s *); + +unsigned char *encode_upp_readlink_r(const upp_readlink_r *, unsigned char *); +unsigned char *decode_upp_readlink_r(upp_readlink_r *, unsigned char *); +unsigned int sizeof_upp_readlink_r(const upp_readlink_r *); + +unsigned char *encode_upp_followlink_s(const upp_followlink_s *, unsigned char *); +unsigned char *decode_upp_followlink_s(upp_followlink_s *, unsigned char *); +unsigned int sizeof_upp_followlink_s(const upp_followlink_s *); + +unsigned char *encode_upp_followlink_r(const upp_followlink_r *, unsigned char *); +unsigned char *decode_upp_followlink_r(upp_followlink_r *, unsigned char *); +unsigned int sizeof_upp_followlink_r(const upp_followlink_r *); + +unsigned char *encode__userfs_types_005(const _userfs_types_005 *, unsigned char *); +unsigned char *decode__userfs_types_005(_userfs_types_005 *, unsigned char *); +unsigned int sizeof__userfs_types_005(const _userfs_types_005 *); + +unsigned char *encode_upp_create_s(const upp_create_s *, unsigned char *); +unsigned char *decode_upp_create_s(upp_create_s *, unsigned char *); +unsigned int sizeof_upp_create_s(const upp_create_s *); + +unsigned char *encode_upp_create_r(const upp_create_r *, unsigned char *); +unsigned char *decode_upp_create_r(upp_create_r *, unsigned char *); +unsigned int sizeof_upp_create_r(const upp_create_r *); + +unsigned char *encode_upp_lookup_s(const upp_lookup_s *, unsigned char *); +unsigned char *decode_upp_lookup_s(upp_lookup_s *, unsigned char *); +unsigned int sizeof_upp_lookup_s(const upp_lookup_s *); + +unsigned char *encode_upp_lookup_r(const upp_lookup_r *, unsigned char *); +unsigned char *decode_upp_lookup_r(upp_lookup_r *, unsigned char *); +unsigned int sizeof_upp_lookup_r(const upp_lookup_r *); + +unsigned char *encode_upp_read_s(const upp_read_s *, unsigned char *); +unsigned char *decode_upp_read_s(upp_read_s *, unsigned char *); +unsigned int sizeof_upp_read_s(const upp_read_s *); + +unsigned char *encode__userfs_types_006(const _userfs_types_006 *, unsigned char *); +unsigned char *decode__userfs_types_006(_userfs_types_006 *, unsigned char *); +unsigned int sizeof__userfs_types_006(const _userfs_types_006 *); + +unsigned char *encode_upp_read_r(const upp_read_r *, unsigned char *); +unsigned char *decode_upp_read_r(upp_read_r *, unsigned char *); +unsigned int sizeof_upp_read_r(const upp_read_r *); + +unsigned char *encode__userfs_types_007(const _userfs_types_007 *, unsigned char *); +unsigned char *decode__userfs_types_007(_userfs_types_007 *, unsigned char *); +unsigned int sizeof__userfs_types_007(const _userfs_types_007 *); + +unsigned char *encode_upp_write_s(const upp_write_s *, unsigned char *); +unsigned char *decode_upp_write_s(upp_write_s *, unsigned char *); +unsigned int sizeof_upp_write_s(const upp_write_s *); + +unsigned char *encode_upp_write_r(const upp_write_r *, unsigned char *); +unsigned char *decode_upp_write_r(upp_write_r *, unsigned char *); +unsigned int sizeof_upp_write_r(const upp_write_r *); + +unsigned char *encode_upp_readdir_s(const upp_readdir_s *, unsigned char *); +unsigned char *decode_upp_readdir_s(upp_readdir_s *, unsigned char *); +unsigned int sizeof_upp_readdir_s(const upp_readdir_s *); + +unsigned char *encode_upp_readdir_r(const upp_readdir_r *, unsigned char *); +unsigned char *decode_upp_readdir_r(upp_readdir_r *, unsigned char *); +unsigned int sizeof_upp_readdir_r(const upp_readdir_r *); + +unsigned char *encode_upp_multireaddir_s(const upp_multireaddir_s *, unsigned char *); +unsigned char *decode_upp_multireaddir_s(upp_multireaddir_s *, unsigned char *); +unsigned int sizeof_upp_multireaddir_s(const upp_multireaddir_s *); + +unsigned char *encode_upp_multireaddir_r(const upp_multireaddir_r *, unsigned char *); +unsigned char *decode_upp_multireaddir_r(upp_multireaddir_r *, unsigned char *); +unsigned int sizeof_upp_multireaddir_r(const upp_multireaddir_r *); + +unsigned char *encode_upp_mount_r(const upp_mount_r *, unsigned char *); +unsigned char *decode_upp_mount_r(upp_mount_r *, unsigned char *); +unsigned int sizeof_upp_mount_r(const upp_mount_r *); + +unsigned char *encode_upp_iput_s(const upp_iput_s *, unsigned char *); +unsigned char *decode_upp_iput_s(upp_iput_s *, unsigned char *); +unsigned int sizeof_upp_iput_s(const upp_iput_s *); + +unsigned char *encode__userfs_types_008(const _userfs_types_008 *, unsigned char *); +unsigned char *decode__userfs_types_008(_userfs_types_008 *, unsigned char *); +unsigned int sizeof__userfs_types_008(const _userfs_types_008 *); + +unsigned char *encode_upp_open_s(const upp_open_s *, unsigned char *); +unsigned char *decode_upp_open_s(upp_open_s *, unsigned char *); +unsigned int sizeof_upp_open_s(const upp_open_s *); + +unsigned char *encode_upp_open_r(const upp_open_r *, unsigned char *); +unsigned char *decode_upp_open_r(upp_open_r *, unsigned char *); +unsigned int sizeof_upp_open_r(const upp_open_r *); + +unsigned char *encode_upp_close_s(const upp_close_s *, unsigned char *); +unsigned char *decode_upp_close_s(upp_close_s *, unsigned char *); +unsigned int sizeof_upp_close_s(const upp_close_s *); + +unsigned char *encode__userfs_types_009(const _userfs_types_009 *, unsigned char *); +unsigned char *decode__userfs_types_009(_userfs_types_009 *, unsigned char *); +unsigned int sizeof__userfs_types_009(const _userfs_types_009 *); + +unsigned char *encode_upp_permission_s(const upp_permission_s *, unsigned char *); +unsigned char *decode_upp_permission_s(upp_permission_s *, unsigned char *); +unsigned int sizeof_upp_permission_s(const upp_permission_s *); + +unsigned char *encode_upp_rename_s(const upp_rename_s *, unsigned char *); +unsigned char *decode_upp_rename_s(upp_rename_s *, unsigned char *); +unsigned int sizeof_upp_rename_s(const upp_rename_s *); + +unsigned char *encode_upp_link_s(const upp_link_s *, unsigned char *); +unsigned char *decode_upp_link_s(upp_link_s *, unsigned char *); +unsigned int sizeof_upp_link_s(const upp_link_s *); + +unsigned char *encode__userfs_types_010(const _userfs_types_010 *, unsigned char *); +unsigned char *decode__userfs_types_010(_userfs_types_010 *, unsigned char *); +unsigned int sizeof__userfs_types_010(const _userfs_types_010 *); + +unsigned char *encode_upp_symlink_s(const upp_symlink_s *, unsigned char *); +unsigned char *decode_upp_symlink_s(upp_symlink_s *, unsigned char *); +unsigned int sizeof_upp_symlink_s(const upp_symlink_s *); + +unsigned char *encode__userfs_types_011(const _userfs_types_011 *, unsigned char *); +unsigned char *decode__userfs_types_011(_userfs_types_011 *, unsigned char *); +unsigned int sizeof__userfs_types_011(const _userfs_types_011 *); + +unsigned char *encode_upp_statfs_r(const upp_statfs_r *, unsigned char *); +unsigned char *decode_upp_statfs_r(upp_statfs_r *, unsigned char *); +unsigned int sizeof_upp_statfs_r(const upp_statfs_r *); + +unsigned char *encode_upp_truncate_s(const upp_truncate_s *, unsigned char *); +unsigned char *decode_upp_truncate_s(upp_truncate_s *, unsigned char *); +unsigned int sizeof_upp_truncate_s(const upp_truncate_s *); + +unsigned char *encode_upp_notify_change_s(const upp_notify_change_s *, unsigned char *); +unsigned char *decode_upp_notify_change_s(upp_notify_change_s *, unsigned char *); +unsigned int sizeof_upp_notify_change_s(const upp_notify_change_s *); + +unsigned char *encode_upp_inode_valid_s(const upp_inode_valid_s *, unsigned char *); +unsigned char *decode_upp_inode_valid_s(upp_inode_valid_s *, unsigned char *); +unsigned int sizeof_upp_inode_valid_s(const upp_inode_valid_s *); + +unsigned char *encode_upp_inode_valid_r(const upp_inode_valid_r *, unsigned char *); +unsigned char *decode_upp_inode_valid_r(upp_inode_valid_r *, unsigned char *); +unsigned int sizeof_upp_inode_valid_r(const upp_inode_valid_r *); + +#endif /* __USERFS_TYPES_H_SEEN__ */ Added: trunk/kernel/src/linux/userfs_fs.h ============================================================================== --- trunk/kernel/src/linux/userfs_fs.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/src/linux/userfs_fs.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,102 @@ +/* + * Filesystem stub for filesystems implemented with user-level + * programs. + * + * This file forms the definition of the protocol between the + * kernel and the user process through the file descriptors. + * + * There are two file descriptors passed to the kernel as part + * of the args to mount(). One is for data from the kernel + * to the filesystem, the other from the filesystem to the + * kernel. Control and data information are encoded along + * the same path. + * + * The filesystem process never initiates any transaction - they + * are all generated by the kernel on the behalf of the other + * user processes using the filesystem. + * + * The connction between the user process and the kernel is + * stateful, so if the connection breaks, Something Bad happens - + * I suppose it should be considered a umount - but what about + * outstanding writes? + * + * For much the same reasons as nfs and dosfs, there can be no + * direct mapping from files, making exec() less memory and time + * efficient. I don't see this as a big problem. + * + * Jeremy Fitzhardinge 1993 + */ + +#ifndef _LINUX_USERFS_FS +#define _LINUX_USERFS_FS + +/* + * These operations map closely with the elements in the various + * operations structures. + * + * Things are missing here, or overloaded. Open does create, mknod and + * mkdir. Unlink can also do a rmdir. + */ +typedef enum +{ + userfs_up_create, /* 0 create files, devices, dirs */ + userfs_up_lookup, /* 1 path->file handle */ + userfs_up_close, /* 2 close on fh */ + userfs_up_read, /* 3 read from file */ + userfs_up_write, /* 4 write to file */ + userfs_up_truncate, /* 5 set file length */ + userfs_up_fsync, /* 6 sync file */ + userfs_up_readdir, /* 7 read dir entries */ + userfs_up_link, /* 8 link files */ + userfs_up_unlink, /* 9 unlink file */ + userfs_up_symlink, /* 10 create symlink */ + userfs_up_readlink, /* 11 read link contents */ + userfs_up_followlink, /* 12 resolve path through link */ + userfs_up_mount, /* 13 mount request */ + userfs_up_umount, /* 14 unmount request */ + userfs_up_iread, /* 15 get contents of inode for file */ + userfs_up_iwrite, /* 16 set inode contents */ + userfs_up_statfs, /* 17 stat filesystem wide things */ + userfs_up_iput, /* 18 put an inode after finished */ + userfs_up_open, /* 19 open of a file */ + userfs_up_permission, /* 20 check file permissions */ + userfs_up_rename, /* 21 rename file */ + userfs_up_multireaddir, /* 22 read multiple dir entries */ + userfs_up_notify_change, /* 23 notify inode changes */ + userfs_up_inode_valid, /* 24 ask filesystem whether an inode is valid */ +} up_ops; + +/* increment this when the structure shapes change */ +#define UP_VERSION 16 + +/* + * Max transfer size currently limited to largest allocatable + * block. There's also not much need to make it bigger. + */ +#define USERFS_MAX_XFER (4080) + +#ifdef __KERNEL__ +#include /* For NGROUPS */ +#include + +typedef unsigned char *(*encode_func)(const void *, unsigned char *); +typedef unsigned char *(*decode_func)(void *, unsigned char *); +typedef unsigned int (*sizeof_func)(const void *); + +#define GEN_ENC(var) (encode_func)(var) +#define GEN_DEC(var) (decode_func)(var) +#define GEN_SIZ(var) (sizeof_func)(var) + +void userfs_genpkt(struct super_block *, up_preamble *, up_ops); + +/* Encode and send request, receive and decode reply */ +#define userfs_doop(sb, pre, repl, st, ss, rt, rs)\ + __userfs_doop(sb, pre, repl, \ + GEN_ENC(encode_##st), (void *)ss, \ + GEN_DEC(decode_##rt), (void *)rs, \ + GEN_SIZ(sizeof_##st), GEN_SIZ(sizeof_##rt)) + +int __userfs_doop(struct super_block *, up_preamble *pre, upp_repl *repl, encode_func, void *, decode_func, void *, sizeof_func, sizeof_func); +#endif /* __KERNEL__ */ + +#endif /* _LINUX_USERFS_FS */ Added: trunk/kernel/src/linux/userfs_fs_sb.h ============================================================================== --- trunk/kernel/src/linux/userfs_fs_sb.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/src/linux/userfs_fs_sb.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,32 @@ +/* + * Super-block structure for user-level filesystem support. + */ + +#ifndef _LINUX_USERFS_FS_SB +#define _LINUX_USERFS_FS_SB + +#include + +#define USERFS_SUPER_MAGIC 0x73757265 + +struct userfs_sb_info +{ + struct file *s_toproc; /* To user process */ + struct file *s_fromproc; /* From user process */ + int s_seq; /* Sequence number */ + up_handle s_root; /* root of mounted fs */ + struct inode_operations *s_iops; /* inode ops for this fs */ + + /* These are for serialising access to pipe */ + spinlock_t s_lock; + wait_queue_t s_wait; + + /* This is for multiple outstanding operations */ + int s_canread; /* there is something reading */ + int s_nwproc; /* number of processes waiting */ + struct pwlist *s_wlist; /* list of waiting processes */ +}; + +extern struct super_block *userfs_read_super(struct super_block *, void *, int); + +#endif /* _LINUX_USERFS_FS_SB */ Added: trunk/kernel/src/linux/userfs_fs_f.h ============================================================================== --- trunk/kernel/src/linux/userfs_fs_f.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/src/linux/userfs_fs_f.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,14 @@ +/* + * Per file open information for userfs + */ + +#ifndef __LINUX_USERFS_FS_F_H_SEEN__ +#define __LINUX_USERFS_FS_F_H_SEEN__ + +typedef unsigned long up_credtok; + +struct userfs_file_info { + up_credtok cred_tok; /* credentials token */ +}; + +#endif /* __LINUX_USERFS_FS_F_H_SEEN__ */ Added: trunk/kernel/src/linux/userfs_types.c ============================================================================== --- trunk/kernel/src/linux/userfs_types.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/src/linux/userfs_types.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,1436 @@ +/* -*- C -*- + * DO NOT EDIT BY HAND! + * + * This was automatically generated by gencode. + */ +#include "userfs_types.h" + + +unsigned char *encode__userfs_types_001(const _userfs_types_001 *sp, unsigned char *buf) +{ + { + unsigned i; + + for(i = 0; i < 32; i++) { + buf = encode_Ulong(&(*sp)[i], buf); + } + } + return buf; +} + + +unsigned char *encode__userfs_types_002(const _userfs_types_002 *sp, unsigned char *buf) +{ + { + unsigned i; + + for(i = 0; i < 2; i++) { + buf = encode_long(&(*sp)[i], buf); + } + } + return buf; +} + + +unsigned char *encode_up_handle(const up_handle *sp, unsigned char *buf) +{ + buf = encode_Ulong(&sp->handle, buf); + return buf; +} + + +unsigned char *encode_uf_uid_t(const uf_uid_t *sp, unsigned char *buf) +{ + buf = encode_Ushort(sp, buf); + return buf; +} + + +unsigned char *encode__userfs_types_004(const _userfs_types_004 *sp, unsigned char *buf) +{ + { + unsigned i; + + buf = encode_Ulong(&sp->nelem, buf); + for(i = 0; i < sp->nelem; i++) { + buf = encode_long(&sp->elems[i], buf); + } + } + return buf; +} + + +unsigned char *encode_up_cred(const up_cred *sp, unsigned char *buf) +{ + buf = encode_Ushort(&sp->uid, buf); + buf = encode_Ushort(&sp->euid, buf); + buf = encode_Ushort(&sp->suid, buf); + buf = encode_Ushort(&sp->gid, buf); + buf = encode_Ushort(&sp->egid, buf); + buf = encode_Ushort(&sp->sgid, buf); + buf = encode_Ushort(&sp->umask, buf); + buf = encode__userfs_types_004(&sp->groups, buf); + return buf; +} + + +unsigned char *encode_up_iattr(const up_iattr *sp, unsigned char *buf) +{ + buf = encode_Ulong(&sp->ia_valid, buf); + buf = encode_Ushort(&sp->ia_mode, buf); + buf = encode_Ushort(&sp->ia_uid, buf); + buf = encode_Ushort(&sp->ia_gid, buf); + buf = encode_long(&sp->ia_size, buf); + buf = encode_long(&sp->ia_atime, buf); + buf = encode_long(&sp->ia_mtime, buf); + buf = encode_long(&sp->ia_ctime, buf); + return buf; +} + + +unsigned char *encode_up_preamble(const up_preamble *sp, unsigned char *buf) +{ + buf = encode_short(&sp->version, buf); + buf = encode_long(&sp->seq, buf); + buf = encode_Uchar(&sp->op, buf); + buf = encode_Uchar(&sp->isreq, buf); + buf = encode_Ulong(&sp->size, buf); + return buf; +} + + +unsigned char *encode_upp_repl(const upp_repl *sp, unsigned char *buf) +{ + buf = encode_short(&sp->version, buf); + buf = encode_long(&sp->seq, buf); + buf = encode_Uchar(&sp->op, buf); + buf = encode_Uchar(&sp->isreq, buf); + buf = encode_Ulong(&sp->size, buf); + buf = encode_long(&sp->err_no, buf); + return buf; +} + + +unsigned char *encode_up_inode(const up_inode *sp, unsigned char *buf) +{ + buf = encode_Ushort(&sp->mode, buf); + buf = encode_Ushort(&sp->nlink, buf); + buf = encode_Ushort(&sp->uid, buf); + buf = encode_Ushort(&sp->gid, buf); + buf = encode_long(&sp->size, buf); + buf = encode_long(&sp->atime, buf); + buf = encode_long(&sp->mtime, buf); + buf = encode_long(&sp->ctime, buf); + buf = encode_Ushort(&sp->rdev, buf); + buf = encode_Ulong(&sp->blksize, buf); + buf = encode_Ulong(&sp->blocks, buf); + return buf; +} + + +unsigned char *encode_up_name(const up_name *sp, unsigned char *buf) +{ + { + unsigned i; + + buf = encode_Ulong(&sp->nelem, buf); + for(i = 0; i < sp->nelem; i++) { + buf = encode_char(&sp->elems[i], buf); + } + } + return buf; +} + + +unsigned char *encode_upp_iwrite_s(const upp_iwrite_s *sp, unsigned char *buf) +{ + buf = encode_up_inode(&sp->ino, buf); + buf = encode_up_handle(&sp->handle, buf); + return buf; +} + + +unsigned char *encode_upp_iread_s(const upp_iread_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->handle, buf); + return buf; +} + + +unsigned char *encode_upp_iread_r(const upp_iread_r *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->handle, buf); + buf = encode_up_inode(&sp->ino, buf); + return buf; +} + + +unsigned char *encode_upp_unlink_s(const upp_unlink_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->dir, buf); + buf = encode_up_name(&sp->name, buf); + return buf; +} + + +unsigned char *encode_upp_readlink_s(const upp_readlink_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->link, buf); + return buf; +} + + +unsigned char *encode_upp_readlink_r(const upp_readlink_r *sp, unsigned char *buf) +{ + buf = encode_up_name(&sp->name, buf); + return buf; +} + + +unsigned char *encode_upp_followlink_s(const upp_followlink_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->dir, buf); + buf = encode_up_handle(&sp->link, buf); + buf = encode_long(&sp->flag, buf); + buf = encode_long(&sp->mode, buf); + return buf; +} + + +unsigned char *encode_upp_followlink_r(const upp_followlink_r *sp, unsigned char *buf) +{ + buf = encode_up_name(&sp->path, buf); + return buf; +} + + +unsigned char *encode_upp_create_s(const upp_create_s *sp, unsigned char *buf) +{ + buf = encode_long(&sp->mode, buf); + buf = encode_up_handle(&sp->dir, buf); + buf = encode_up_cred(&sp->cred, buf); + buf = encode_long(&sp->rdev, buf); + buf = encode_up_name(&sp->name, buf); + return buf; +} + + +unsigned char *encode_upp_create_r(const upp_create_r *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->file, buf); + return buf; +} + + +unsigned char *encode_upp_lookup_s(const upp_lookup_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->dir, buf); + buf = encode_up_name(&sp->name, buf); + return buf; +} + + +unsigned char *encode_upp_lookup_r(const upp_lookup_r *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->handle, buf); + return buf; +} + + +unsigned char *encode_upp_read_s(const upp_read_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->file, buf); + buf = encode_long(&sp->off, buf); + buf = encode_long(&sp->size, buf); + buf = encode_Ulong(&sp->ctok, buf); + return buf; +} + + +unsigned char *encode__userfs_types_006(const _userfs_types_006 *sp, unsigned char *buf) +{ + { + unsigned i; + + buf = encode_Ulong(&sp->nelem, buf); + for(i = 0; i < sp->nelem; i++) { + buf = encode_Uchar(&sp->elems[i], buf); + } + } + return buf; +} + + +unsigned char *encode_upp_read_r(const upp_read_r *sp, unsigned char *buf) +{ + buf = encode__userfs_types_006(&sp->data, buf); + return buf; +} + + +unsigned char *encode__userfs_types_007(const _userfs_types_007 *sp, unsigned char *buf) +{ + { + unsigned i; + + buf = encode_Ulong(&sp->nelem, buf); + for(i = 0; i < sp->nelem; i++) { + buf = encode_Uchar(&sp->elems[i], buf); + } + } + return buf; +} + + +unsigned char *encode_upp_write_s(const upp_write_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->file, buf); + buf = encode_long(&sp->off, buf); + buf = encode_Ulong(&sp->ctok, buf); + buf = encode__userfs_types_007(&sp->data, buf); + return buf; +} + + +unsigned char *encode_upp_write_r(const upp_write_r *sp, unsigned char *buf) +{ + buf = encode_long(&sp->wrote, buf); + return buf; +} + + +unsigned char *encode_upp_readdir_s(const upp_readdir_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->dir, buf); + buf = encode_long(&sp->off, buf); + buf = encode_Ulong(&sp->ctok, buf); + return buf; +} + + +unsigned char *encode_upp_readdir_r(const upp_readdir_r *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->file, buf); + buf = encode_long(&sp->off, buf); + buf = encode_up_name(&sp->name, buf); + return buf; +} + + +unsigned char *encode_upp_multireaddir_s(const upp_multireaddir_s *sp, unsigned char *buf) +{ + buf = encode_upp_readdir_s(sp, buf); + return buf; +} + + +unsigned char *encode_upp_multireaddir_r(const upp_multireaddir_r *sp, unsigned char *buf) +{ + { + unsigned i; + + buf = encode_Ulong(&sp->nelem, buf); + for(i = 0; i < sp->nelem; i++) { + buf = encode_upp_readdir_r(&sp->elems[i], buf); + } + } + return buf; +} + + +unsigned char *encode_upp_mount_r(const upp_mount_r *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->root, buf); + return buf; +} + + +unsigned char *encode_upp_iput_s(const upp_iput_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->handle, buf); + return buf; +} + + +unsigned char *encode_upp_open_s(const upp_open_s *sp, unsigned char *buf) +{ + buf = encode_up_cred(&sp->cred, buf); + buf = encode_up_handle(&sp->file, buf); + return buf; +} + + +unsigned char *encode_upp_open_r(const upp_open_r *sp, unsigned char *buf) +{ + buf = encode_Ulong(&sp->ctok, buf); + return buf; +} + + +unsigned char *encode_upp_close_s(const upp_close_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->file, buf); + buf = encode_Ulong(&sp->ctok, buf); + return buf; +} + + +unsigned char *encode_upp_permission_s(const upp_permission_s *sp, unsigned char *buf) +{ + buf = encode_up_cred(&sp->cred, buf); + buf = encode_up_handle(&sp->file, buf); + buf = encode_long(&sp->mask, buf); + return buf; +} + + +unsigned char *encode_upp_rename_s(const upp_rename_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->odir, buf); + buf = encode_up_name(&sp->oname, buf); + buf = encode_up_handle(&sp->ndir, buf); + buf = encode_up_name(&sp->nname, buf); + return buf; +} + + +unsigned char *encode_upp_link_s(const upp_link_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->ofile, buf); + buf = encode_up_handle(&sp->dir, buf); + buf = encode_up_name(&sp->name, buf); + return buf; +} + + +unsigned char *encode_upp_symlink_s(const upp_symlink_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->dir, buf); + buf = encode_up_name(&sp->name, buf); + buf = encode_up_name(&sp->symname, buf); + buf = encode_up_cred(&sp->cred, buf); + return buf; +} + + +unsigned char *encode__userfs_types_011(const _userfs_types_011 *sp, unsigned char *buf) +{ + { + unsigned i; + + for(i = 0; i < 2; i++) { + buf = encode_long(&(*sp)[i], buf); + } + } + return buf; +} + + +unsigned char *encode_upp_statfs_r(const upp_statfs_r *sp, unsigned char *buf) +{ + buf = encode_long(&sp->bsize, buf); + buf = encode_long(&sp->blocks, buf); + buf = encode_long(&sp->bfree, buf); + buf = encode_long(&sp->bavail, buf); + buf = encode_long(&sp->files, buf); + buf = encode_long(&sp->ffree, buf); + buf = encode__userfs_types_011(&sp->fsid, buf); + buf = encode_long(&sp->namelen, buf); + return buf; +} + + +unsigned char *encode_upp_truncate_s(const upp_truncate_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->file, buf); + buf = encode_long(&sp->size, buf); + return buf; +} + + +unsigned char *encode_upp_notify_change_s(const upp_notify_change_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->handle, buf); + buf = encode_up_iattr(&sp->iattr, buf); + return buf; +} + + +unsigned char *encode_upp_inode_valid_s(const upp_inode_valid_s *sp, unsigned char *buf) +{ + buf = encode_up_handle(&sp->handle, buf); + buf = encode_Ulong(&sp->version, buf); + return buf; +} + + +unsigned char *encode_upp_inode_valid_r(const upp_inode_valid_r *sp, unsigned char *buf) +{ + buf = encode_Ulong(&sp->version, buf); + buf = encode_char(&sp->valid, buf); + return buf; +} + + +unsigned char *decode__userfs_types_001(_userfs_types_001 *sp, unsigned char *buf) +{ + { + unsigned i; + + for(i = 0; i < 32; i++) { + buf = decode_Ulong(sp[i], buf); + } + } + return buf; +} + + +unsigned char *decode__userfs_types_002(_userfs_types_002 *sp, unsigned char *buf) +{ + { + unsigned i; + + for(i = 0; i < 2; i++) { + buf = decode_long(sp[i], buf); + } + } + return buf; +} + + +unsigned char *decode_up_handle(up_handle *sp, unsigned char *buf) +{ + buf = decode_Ulong(&sp->handle, buf); + return buf; +} + + +unsigned char *decode_uf_uid_t(uf_uid_t *sp, unsigned char *buf) +{ + buf = decode_Ushort(sp, buf); + return buf; +} + + +unsigned char *decode__userfs_types_004(_userfs_types_004 *sp, unsigned char *buf) +{ + { + unsigned i; + buf = decode_Ulong(&sp->nelem, buf); + if (sp->nelem == 0) + { + sp->elems = 0; + return buf; + } + sp->elems = (long *)ALLOC(sizeof(long) * sp->nelem); + if (sp->elems == 0) { + return buf; + } + for(i = 0; i < sp->nelem; i++) { + buf = decode_long(&sp->elems[i], buf); + } + } + return buf; +} + + +unsigned char *decode_up_cred(up_cred *sp, unsigned char *buf) +{ + buf = decode_Ushort(&sp->uid, buf); + buf = decode_Ushort(&sp->euid, buf); + buf = decode_Ushort(&sp->suid, buf); + buf = decode_Ushort(&sp->gid, buf); + buf = decode_Ushort(&sp->egid, buf); + buf = decode_Ushort(&sp->sgid, buf); + buf = decode_Ushort(&sp->umask, buf); + buf = decode__userfs_types_004(&sp->groups, buf); + return buf; +} + + +unsigned char *decode_up_iattr(up_iattr *sp, unsigned char *buf) +{ + buf = decode_Ulong(&sp->ia_valid, buf); + buf = decode_Ushort(&sp->ia_mode, buf); + buf = decode_Ushort(&sp->ia_uid, buf); + buf = decode_Ushort(&sp->ia_gid, buf); + buf = decode_long(&sp->ia_size, buf); + buf = decode_long(&sp->ia_atime, buf); + buf = decode_long(&sp->ia_mtime, buf); + buf = decode_long(&sp->ia_ctime, buf); + return buf; +} + + +unsigned char *decode_up_preamble(up_preamble *sp, unsigned char *buf) +{ + buf = decode_short(&sp->version, buf); + buf = decode_long(&sp->seq, buf); + buf = decode_Uchar(&sp->op, buf); + buf = decode_Uchar(&sp->isreq, buf); + buf = decode_Ulong(&sp->size, buf); + return buf; +} + + +unsigned char *decode_upp_repl(upp_repl *sp, unsigned char *buf) +{ + buf = decode_short(&sp->version, buf); + buf = decode_long(&sp->seq, buf); + buf = decode_Uchar(&sp->op, buf); + buf = decode_Uchar(&sp->isreq, buf); + buf = decode_Ulong(&sp->size, buf); + buf = decode_long(&sp->err_no, buf); + return buf; +} + + +unsigned char *decode_up_inode(up_inode *sp, unsigned char *buf) +{ + buf = decode_Ushort(&sp->mode, buf); + buf = decode_Ushort(&sp->nlink, buf); + buf = decode_Ushort(&sp->uid, buf); + buf = decode_Ushort(&sp->gid, buf); + buf = decode_long(&sp->size, buf); + buf = decode_long(&sp->atime, buf); + buf = decode_long(&sp->mtime, buf); + buf = decode_long(&sp->ctime, buf); + buf = decode_Ushort(&sp->rdev, buf); + buf = decode_Ulong(&sp->blksize, buf); + buf = decode_Ulong(&sp->blocks, buf); + return buf; +} + + +unsigned char *decode_up_name(up_name *sp, unsigned char *buf) +{ + { + unsigned i; + buf = decode_Ulong(&sp->nelem, buf); + if (sp->nelem == 0) + { + sp->elems = 0; + return buf; + } + sp->elems = (char *)ALLOC(sizeof(char) * sp->nelem); + if (sp->elems == 0) { + return buf; + } + for(i = 0; i < sp->nelem; i++) { + buf = decode_char(&sp->elems[i], buf); + } + } + return buf; +} + + +unsigned char *decode_upp_iwrite_s(upp_iwrite_s *sp, unsigned char *buf) +{ + buf = decode_up_inode(&sp->ino, buf); + buf = decode_up_handle(&sp->handle, buf); + return buf; +} + + +unsigned char *decode_upp_iread_s(upp_iread_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->handle, buf); + return buf; +} + + +unsigned char *decode_upp_iread_r(upp_iread_r *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->handle, buf); + buf = decode_up_inode(&sp->ino, buf); + return buf; +} + + +unsigned char *decode_upp_unlink_s(upp_unlink_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->dir, buf); + buf = decode_up_name(&sp->name, buf); + return buf; +} + + +unsigned char *decode_upp_readlink_s(upp_readlink_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->link, buf); + return buf; +} + + +unsigned char *decode_upp_readlink_r(upp_readlink_r *sp, unsigned char *buf) +{ + buf = decode_up_name(&sp->name, buf); + return buf; +} + + +unsigned char *decode_upp_followlink_s(upp_followlink_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->dir, buf); + buf = decode_up_handle(&sp->link, buf); + buf = decode_long(&sp->flag, buf); + buf = decode_long(&sp->mode, buf); + return buf; +} + + +unsigned char *decode_upp_followlink_r(upp_followlink_r *sp, unsigned char *buf) +{ + buf = decode_up_name(&sp->path, buf); + return buf; +} + + +unsigned char *decode_upp_create_s(upp_create_s *sp, unsigned char *buf) +{ + buf = decode_long(&sp->mode, buf); + buf = decode_up_handle(&sp->dir, buf); + buf = decode_up_cred(&sp->cred, buf); + buf = decode_long(&sp->rdev, buf); + buf = decode_up_name(&sp->name, buf); + return buf; +} + + +unsigned char *decode_upp_create_r(upp_create_r *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->file, buf); + return buf; +} + + +unsigned char *decode_upp_lookup_s(upp_lookup_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->dir, buf); + buf = decode_up_name(&sp->name, buf); + return buf; +} + + +unsigned char *decode_upp_lookup_r(upp_lookup_r *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->handle, buf); + return buf; +} + + +unsigned char *decode_upp_read_s(upp_read_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->file, buf); + buf = decode_long(&sp->off, buf); + buf = decode_long(&sp->size, buf); + buf = decode_Ulong(&sp->ctok, buf); + return buf; +} + + +unsigned char *decode__userfs_types_006(_userfs_types_006 *sp, unsigned char *buf) +{ + { + unsigned i; + buf = decode_Ulong(&sp->nelem, buf); + if (sp->nelem == 0) + { + sp->elems = 0; + return buf; + } + sp->elems = (Uchar *)ALLOC(sizeof(Uchar) * sp->nelem); + if (sp->elems == 0) { + return buf; + } + for(i = 0; i < sp->nelem; i++) { + buf = decode_Uchar(&sp->elems[i], buf); + } + } + return buf; +} + + +unsigned char *decode_upp_read_r(upp_read_r *sp, unsigned char *buf) +{ + buf = decode__userfs_types_006(&sp->data, buf); + return buf; +} + + +unsigned char *decode__userfs_types_007(_userfs_types_007 *sp, unsigned char *buf) +{ + { + unsigned i; + buf = decode_Ulong(&sp->nelem, buf); + if (sp->nelem == 0) + { + sp->elems = 0; + return buf; + } + sp->elems = (Uchar *)ALLOC(sizeof(Uchar) * sp->nelem); + if (sp->elems == 0) { + return buf; + } + for(i = 0; i < sp->nelem; i++) { + buf = decode_Uchar(&sp->elems[i], buf); + } + } + return buf; +} + + +unsigned char *decode_upp_write_s(upp_write_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->file, buf); + buf = decode_long(&sp->off, buf); + buf = decode_Ulong(&sp->ctok, buf); + buf = decode__userfs_types_007(&sp->data, buf); + return buf; +} + + +unsigned char *decode_upp_write_r(upp_write_r *sp, unsigned char *buf) +{ + buf = decode_long(&sp->wrote, buf); + return buf; +} + + +unsigned char *decode_upp_readdir_s(upp_readdir_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->dir, buf); + buf = decode_long(&sp->off, buf); + buf = decode_Ulong(&sp->ctok, buf); + return buf; +} + + +unsigned char *decode_upp_readdir_r(upp_readdir_r *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->file, buf); + buf = decode_long(&sp->off, buf); + buf = decode_up_name(&sp->name, buf); + return buf; +} + + +unsigned char *decode_upp_multireaddir_s(upp_multireaddir_s *sp, unsigned char *buf) +{ + buf = decode_upp_readdir_s(sp, buf); + return buf; +} + + +unsigned char *decode_upp_multireaddir_r(upp_multireaddir_r *sp, unsigned char *buf) +{ + { + unsigned i; + buf = decode_Ulong(&sp->nelem, buf); + if (sp->nelem == 0) + { + sp->elems = 0; + return buf; + } + sp->elems = (upp_readdir_r *)ALLOC(sizeof(upp_readdir_r) * sp->nelem); + if (sp->elems == 0) { + return buf; + } + for(i = 0; i < sp->nelem; i++) { + buf = decode_upp_readdir_r(&sp->elems[i], buf); + } + } + return buf; +} + + +unsigned char *decode_upp_mount_r(upp_mount_r *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->root, buf); + return buf; +} + + +unsigned char *decode_upp_iput_s(upp_iput_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->handle, buf); + return buf; +} + + +unsigned char *decode_upp_open_s(upp_open_s *sp, unsigned char *buf) +{ + buf = decode_up_cred(&sp->cred, buf); + buf = decode_up_handle(&sp->file, buf); + return buf; +} + + +unsigned char *decode_upp_open_r(upp_open_r *sp, unsigned char *buf) +{ + buf = decode_Ulong(&sp->ctok, buf); + return buf; +} + + +unsigned char *decode_upp_close_s(upp_close_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->file, buf); + buf = decode_Ulong(&sp->ctok, buf); + return buf; +} + + +unsigned char *decode_upp_permission_s(upp_permission_s *sp, unsigned char *buf) +{ + buf = decode_up_cred(&sp->cred, buf); + buf = decode_up_handle(&sp->file, buf); + buf = decode_long(&sp->mask, buf); + return buf; +} + + +unsigned char *decode_upp_rename_s(upp_rename_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->odir, buf); + buf = decode_up_name(&sp->oname, buf); + buf = decode_up_handle(&sp->ndir, buf); + buf = decode_up_name(&sp->nname, buf); + return buf; +} + + +unsigned char *decode_upp_link_s(upp_link_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->ofile, buf); + buf = decode_up_handle(&sp->dir, buf); + buf = decode_up_name(&sp->name, buf); + return buf; +} + + +unsigned char *decode_upp_symlink_s(upp_symlink_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->dir, buf); + buf = decode_up_name(&sp->name, buf); + buf = decode_up_name(&sp->symname, buf); + buf = decode_up_cred(&sp->cred, buf); + return buf; +} + + +unsigned char *decode__userfs_types_011(_userfs_types_011 *sp, unsigned char *buf) +{ + { + unsigned i; + + for(i = 0; i < 2; i++) { + buf = decode_long(sp[i], buf); + } + } + return buf; +} + + +unsigned char *decode_upp_statfs_r(upp_statfs_r *sp, unsigned char *buf) +{ + buf = decode_long(&sp->bsize, buf); + buf = decode_long(&sp->blocks, buf); + buf = decode_long(&sp->bfree, buf); + buf = decode_long(&sp->bavail, buf); + buf = decode_long(&sp->files, buf); + buf = decode_long(&sp->ffree, buf); + buf = decode__userfs_types_011(&sp->fsid, buf); + buf = decode_long(&sp->namelen, buf); + return buf; +} + + +unsigned char *decode_upp_truncate_s(upp_truncate_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->file, buf); + buf = decode_long(&sp->size, buf); + return buf; +} + + +unsigned char *decode_upp_notify_change_s(upp_notify_change_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->handle, buf); + buf = decode_up_iattr(&sp->iattr, buf); + return buf; +} + + +unsigned char *decode_upp_inode_valid_s(upp_inode_valid_s *sp, unsigned char *buf) +{ + buf = decode_up_handle(&sp->handle, buf); + buf = decode_Ulong(&sp->version, buf); + return buf; +} + + +unsigned char *decode_upp_inode_valid_r(upp_inode_valid_r *sp, unsigned char *buf) +{ + buf = decode_Ulong(&sp->version, buf); + buf = decode_char(&sp->valid, buf); + return buf; +} +unsigned int sizeof__userfs_types_001(const _userfs_types_001 *sp) +{ + unsigned int sz=0; + + { + unsigned i; + for(i = 0; i < 32; i++) { + sz += sizeof_Ulong(sp[i]); + } + } + return sz; +} +unsigned int sizeof__userfs_types_002(const _userfs_types_002 *sp) +{ + unsigned int sz=0; + + { + unsigned i; + for(i = 0; i < 2; i++) { + sz += sizeof_long(sp[i]); + } + } + return sz; +} +unsigned int sizeof_up_handle(const up_handle *sp) +{ + unsigned int sz=0; + + sz += sizeof_Ulong(&sp->handle); + return sz; +} +unsigned int sizeof_uf_uid_t(const uf_uid_t *sp) +{ + unsigned int sz=0; + + sz += sizeof_Ushort(sp); + return sz; +} +unsigned int sizeof__userfs_types_004(const _userfs_types_004 *sp) +{ + unsigned int sz=0; + + sz += sizeof_Ulong(&sp->nelem); + { + unsigned i; + for(i = 0; i < sp->nelem; i++) { + sz += sizeof_long(&sp->elems[i]); + } + } + return sz; +} +unsigned int sizeof_up_cred(const up_cred *sp) +{ + unsigned int sz=0; + + sz += sizeof_Ushort(&sp->uid); + sz += sizeof_Ushort(&sp->euid); + sz += sizeof_Ushort(&sp->suid); + sz += sizeof_Ushort(&sp->gid); + sz += sizeof_Ushort(&sp->egid); + sz += sizeof_Ushort(&sp->sgid); + sz += sizeof_Ushort(&sp->umask); + sz += sizeof__userfs_types_004(&sp->groups); + return sz; +} +unsigned int sizeof_up_iattr(const up_iattr *sp) +{ + unsigned int sz=0; + + sz += sizeof_Ulong(&sp->ia_valid); + sz += sizeof_Ushort(&sp->ia_mode); + sz += sizeof_Ushort(&sp->ia_uid); + sz += sizeof_Ushort(&sp->ia_gid); + sz += sizeof_long(&sp->ia_size); + sz += sizeof_long(&sp->ia_atime); + sz += sizeof_long(&sp->ia_mtime); + sz += sizeof_long(&sp->ia_ctime); + return sz; +} +unsigned int sizeof_up_preamble(const up_preamble *sp) +{ + unsigned int sz=0; + + sz += sizeof_short(&sp->version); + sz += sizeof_long(&sp->seq); + sz += sizeof_Uchar(&sp->op); + sz += sizeof_Uchar(&sp->isreq); + sz += sizeof_Ulong(&sp->size); + return sz; +} +unsigned int sizeof_upp_repl(const upp_repl *sp) +{ + unsigned int sz=0; + + sz += sizeof_short(&sp->version); + sz += sizeof_long(&sp->seq); + sz += sizeof_Uchar(&sp->op); + sz += sizeof_Uchar(&sp->isreq); + sz += sizeof_Ulong(&sp->size); + sz += sizeof_long(&sp->err_no); + return sz; +} +unsigned int sizeof_up_inode(const up_inode *sp) +{ + unsigned int sz=0; + + sz += sizeof_Ushort(&sp->mode); + sz += sizeof_Ushort(&sp->nlink); + sz += sizeof_Ushort(&sp->uid); + sz += sizeof_Ushort(&sp->gid); + sz += sizeof_long(&sp->size); + sz += sizeof_long(&sp->atime); + sz += sizeof_long(&sp->mtime); + sz += sizeof_long(&sp->ctime); + sz += sizeof_Ushort(&sp->rdev); + sz += sizeof_Ulong(&sp->blksize); + sz += sizeof_Ulong(&sp->blocks); + return sz; +} +unsigned int sizeof_up_name(const up_name *sp) +{ + unsigned int sz=0; + + sz += sizeof_Ulong(&sp->nelem); + { + unsigned i; + for(i = 0; i < sp->nelem; i++) { + sz += sizeof_char(&sp->elems[i]); + } + } + return sz; +} +unsigned int sizeof_upp_iwrite_s(const upp_iwrite_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_inode(&sp->ino); + sz += sizeof_up_handle(&sp->handle); + return sz; +} +unsigned int sizeof_upp_iread_s(const upp_iread_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->handle); + return sz; +} +unsigned int sizeof_upp_iread_r(const upp_iread_r *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->handle); + sz += sizeof_up_inode(&sp->ino); + return sz; +} +unsigned int sizeof_upp_unlink_s(const upp_unlink_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->dir); + sz += sizeof_up_name(&sp->name); + return sz; +} +unsigned int sizeof_upp_readlink_s(const upp_readlink_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->link); + return sz; +} +unsigned int sizeof_upp_readlink_r(const upp_readlink_r *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_name(&sp->name); + return sz; +} +unsigned int sizeof_upp_followlink_s(const upp_followlink_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->dir); + sz += sizeof_up_handle(&sp->link); + sz += sizeof_long(&sp->flag); + sz += sizeof_long(&sp->mode); + return sz; +} +unsigned int sizeof_upp_followlink_r(const upp_followlink_r *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_name(&sp->path); + return sz; +} +unsigned int sizeof_upp_create_s(const upp_create_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_long(&sp->mode); + sz += sizeof_up_handle(&sp->dir); + sz += sizeof_up_cred(&sp->cred); + sz += sizeof_long(&sp->rdev); + sz += sizeof_up_name(&sp->name); + return sz; +} +unsigned int sizeof_upp_create_r(const upp_create_r *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->file); + return sz; +} +unsigned int sizeof_upp_lookup_s(const upp_lookup_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->dir); + sz += sizeof_up_name(&sp->name); + return sz; +} +unsigned int sizeof_upp_lookup_r(const upp_lookup_r *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->handle); + return sz; +} +unsigned int sizeof_upp_read_s(const upp_read_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->file); + sz += sizeof_long(&sp->off); + sz += sizeof_long(&sp->size); + sz += sizeof_Ulong(&sp->ctok); + return sz; +} +unsigned int sizeof__userfs_types_006(const _userfs_types_006 *sp) +{ + unsigned int sz=0; + + sz += sizeof_Ulong(&sp->nelem); + { + unsigned i; + for(i = 0; i < sp->nelem; i++) { + sz += sizeof_Uchar(&sp->elems[i]); + } + } + return sz; +} +unsigned int sizeof_upp_read_r(const upp_read_r *sp) +{ + unsigned int sz=0; + + sz += sizeof__userfs_types_006(&sp->data); + return sz; +} +unsigned int sizeof__userfs_types_007(const _userfs_types_007 *sp) +{ + unsigned int sz=0; + + sz += sizeof_Ulong(&sp->nelem); + { + unsigned i; + for(i = 0; i < sp->nelem; i++) { + sz += sizeof_Uchar(&sp->elems[i]); + } + } + return sz; +} +unsigned int sizeof_upp_write_s(const upp_write_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->file); + sz += sizeof_long(&sp->off); + sz += sizeof_Ulong(&sp->ctok); + sz += sizeof__userfs_types_007(&sp->data); + return sz; +} +unsigned int sizeof_upp_write_r(const upp_write_r *sp) +{ + unsigned int sz=0; + + sz += sizeof_long(&sp->wrote); + return sz; +} +unsigned int sizeof_upp_readdir_s(const upp_readdir_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->dir); + sz += sizeof_long(&sp->off); + sz += sizeof_Ulong(&sp->ctok); + return sz; +} +unsigned int sizeof_upp_readdir_r(const upp_readdir_r *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->file); + sz += sizeof_long(&sp->off); + sz += sizeof_up_name(&sp->name); + return sz; +} +unsigned int sizeof_upp_multireaddir_s(const upp_multireaddir_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_upp_readdir_s(sp); + return sz; +} +unsigned int sizeof_upp_multireaddir_r(const upp_multireaddir_r *sp) +{ + unsigned int sz=0; + + sz += sizeof_Ulong(&sp->nelem); + { + unsigned i; + for(i = 0; i < sp->nelem; i++) { + sz += sizeof_upp_readdir_r(&sp->elems[i]); + } + } + return sz; +} +unsigned int sizeof_upp_mount_r(const upp_mount_r *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->root); + return sz; +} +unsigned int sizeof_upp_iput_s(const upp_iput_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->handle); + return sz; +} +unsigned int sizeof_upp_open_s(const upp_open_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_cred(&sp->cred); + sz += sizeof_up_handle(&sp->file); + return sz; +} +unsigned int sizeof_upp_open_r(const upp_open_r *sp) +{ + unsigned int sz=0; + + sz += sizeof_Ulong(&sp->ctok); + return sz; +} +unsigned int sizeof_upp_close_s(const upp_close_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->file); + sz += sizeof_Ulong(&sp->ctok); + return sz; +} +unsigned int sizeof_upp_permission_s(const upp_permission_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_cred(&sp->cred); + sz += sizeof_up_handle(&sp->file); + sz += sizeof_long(&sp->mask); + return sz; +} +unsigned int sizeof_upp_rename_s(const upp_rename_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->odir); + sz += sizeof_up_name(&sp->oname); + sz += sizeof_up_handle(&sp->ndir); + sz += sizeof_up_name(&sp->nname); + return sz; +} +unsigned int sizeof_upp_link_s(const upp_link_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->ofile); + sz += sizeof_up_handle(&sp->dir); + sz += sizeof_up_name(&sp->name); + return sz; +} +unsigned int sizeof_upp_symlink_s(const upp_symlink_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->dir); + sz += sizeof_up_name(&sp->name); + sz += sizeof_up_name(&sp->symname); + sz += sizeof_up_cred(&sp->cred); + return sz; +} +unsigned int sizeof__userfs_types_011(const _userfs_types_011 *sp) +{ + unsigned int sz=0; + + { + unsigned i; + for(i = 0; i < 2; i++) { + sz += sizeof_long(sp[i]); + } + } + return sz; +} +unsigned int sizeof_upp_statfs_r(const upp_statfs_r *sp) +{ + unsigned int sz=0; + + sz += sizeof_long(&sp->bsize); + sz += sizeof_long(&sp->blocks); + sz += sizeof_long(&sp->bfree); + sz += sizeof_long(&sp->bavail); + sz += sizeof_long(&sp->files); + sz += sizeof_long(&sp->ffree); + sz += sizeof__userfs_types_011(&sp->fsid); + sz += sizeof_long(&sp->namelen); + return sz; +} +unsigned int sizeof_upp_truncate_s(const upp_truncate_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->file); + sz += sizeof_long(&sp->size); + return sz; +} +unsigned int sizeof_upp_notify_change_s(const upp_notify_change_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->handle); + sz += sizeof_up_iattr(&sp->iattr); + return sz; +} +unsigned int sizeof_upp_inode_valid_s(const upp_inode_valid_s *sp) +{ + unsigned int sz=0; + + sz += sizeof_up_handle(&sp->handle); + sz += sizeof_Ulong(&sp->version); + return sz; +} +unsigned int sizeof_upp_inode_valid_r(const upp_inode_valid_r *sp) +{ + unsigned int sz=0; + + sz += sizeof_Ulong(&sp->version); + sz += sizeof_char(&sp->valid); + return sz; +} Added: trunk/kernel/src/linux/userfs_fs_i.h ============================================================================== --- trunk/kernel/src/linux/userfs_fs_i.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/src/linux/userfs_fs_i.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,25 @@ +/* + * Inode data for userfs + */ + +#ifndef _LINUX_USERFS_FS_I +#define _LINUX_USERFS_FS_I + +/* + * What a handle looks like + */ +typedef struct +{ + unsigned long handle; +} up_handle; + +typedef unsigned long up_version; + +struct userfs_inode_info +{ + up_handle handle; + struct userfs_dir_ra *dir_ra; + up_version version; +}; + +#endif /* _LINUX_USERFS_FS_I */ Added: trunk/kernel/src/inode.c ============================================================================== --- trunk/kernel/src/inode.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/src/inode.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,785 @@ +/* + * General inody operations for user process filesystem implmentation + * + * Jeremy Fitzhardinge , 1993-1996 + */ + +#include "userfs.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* this following code relies on the kernel being locked with SMP */ + +/* see linux/fs/inode.c */ +void __wait_on_inode(struct inode * inode) +{ + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&inode->i_wait, &wait); +repeat: + set_current_state(TASK_UNINTERRUPTIBLE); + if (inode->i_state & I_LOCK) { + schedule(); + goto repeat; + } + remove_wait_queue(&inode->i_wait, &wait); + current->state = TASK_RUNNING; +} + +/* see linux/fs/inode.c */ +void wait_on_inode(struct inode * inode) +{ + if(inode->i_state & I_LOCK) + __wait_on_inode(inode); +} + +void userfs_lock_inode(struct inode * inode) +{ + wait_on_inode(inode); + inode->i_state |= I_LOCK; +} + +void userfs_unlock_inode(struct inode * inode) +{ + inode->i_state &= ~I_LOCK; + wake_up(&inode->i_wait); +} + +k_static struct dentry *userfs_lookup(struct inode *dir, struct dentry *de) +{ + int ret = -ENOENT; + up_preamble pre; + upp_repl repl; + upp_lookup_s snd; + upp_lookup_r rcv; + struct inode *result = NULL; + +#ifdef DEBUG + printk("userfs_lookup(%p,%p)\n",dir,de); +#endif + + if (!dir) + return ERR_PTR(-ENOENT); + + if (!S_ISDIR(dir->i_mode)) + { + return ERR_PTR(-ENOTDIR); + } + + userfs_genpkt(dir->i_sb, &pre, userfs_up_lookup); + + snd.name.nelem = de->d_name.len; + snd.name.elems = (char *)de->d_name.name; + snd.dir = U_INOP(dir)->handle; + + if ((ret = userfs_doop(dir->i_sb, &pre, &repl, + upp_lookup_s, &snd, + upp_lookup_r, &rcv)) != 0) + printk("userfs_lookup: userfs_doop failed %d\n", ret); + + if (ret != 0) + return ERR_PTR(ret); + + if (repl.err_no == 0) + { + result = iget(dir->i_sb, rcv.handle.handle); + if(result) + { + U_INOP(result)->handle.handle = rcv.handle.handle; + } + else + { + return ERR_PTR(-EACCES); + } + } + + /* + * Must add the directory entry even if we can't find one + * so that the kernel can create new entries. + */ + d_add(de,result); + + return NULL; +} + +void userfs_setcred(up_cred *cr) +{ + cr->uid = current->uid; + cr->suid = current->suid; + cr->euid = current->euid; + cr->gid = current->gid; + cr->sgid = current->sgid; + cr->egid = current->egid; + cr->umask = current->fs->umask; + + cr->groups.elems = (long *)current->groups; + cr->groups.nelem = current->ngroups; +} + +/* + * This code is common to create, mkdir and mknod + */ +k_static int do_create(struct inode *dir, struct dentry *de, + int mode, dev_t rdev) +{ + struct inode *ino = NULL; + int ret = 0; + up_preamble pre; + upp_repl repl; + upp_create_s snd; + upp_create_r rcv; + +#ifdef DEBUG + printk("do_create(...)\n"); +#endif + + if (!dir || !S_ISDIR(dir->i_mode)) + { + return -ENOTDIR; + } + + userfs_lock_inode(dir); + + dir->i_version = ++event; + userfs_genpkt(dir->i_sb, &pre, userfs_up_create); + + snd.mode = mode; + snd.dir = U_INOP(dir)->handle; + userfs_setcred(&snd.cred); + snd.name.elems = (char *)de->d_name.name; + snd.name.nelem = de->d_name.len; + snd.rdev = rdev; + + if ((ret = userfs_doop(dir->i_sb, &pre, &repl, + upp_create_s, &snd, upp_create_r, &rcv)) != 0) + { + printk("do_create(userfs): userfs_doop failed: %d\n", ret); + if (ret==-ERESTARTSYS) + printk("do_create(userfs): userfs_doop will be restarted\n"); + goto out; + } + + if(repl.err_no) + { + ret = -repl.err_no; + goto out; + } + + assert(dir->i_sb != NULL); + ino = get_empty_inode(); + if (ino == NULL) + { + printk("userfs_create: iget failed for %lx\n", rcv.file.handle); + ret = -ENOMEM; + goto out; + } + + U_INOP(ino)->handle.handle = rcv.file.handle; + ino->i_ino = rcv.file.handle; + ino->i_sb = dir->i_sb; + + userfs_read_inode(ino); + + insert_inode_hash(ino); + + d_instantiate(de,ino); + +out: + userfs_unlock_inode(dir); + + return ret; +} + +k_static int userfs_create(struct inode *dir, struct dentry *de, int mode) +{ + return do_create(dir, de, S_IFREG | mode, 0); +} + +k_static int userfs_mknod(struct inode *dir, struct dentry *de, + int mode, int rdev) +{ + return do_create(dir, de, mode, rdev); +} + +k_static int userfs_mkdir(struct inode *dir, struct dentry *de, int mode) +{ + return do_create(dir, de, S_IFDIR | mode, 0); +} + +/* Actually do the readlink - doesn't eat ino */ +k_static int do_readlink(struct inode *ino, up_name *res) +{ + int ret; + upp_readlink_s snd; + upp_readlink_r rcv; + up_preamble pre; + upp_repl repl; + + rcv.name.elems = NULL; + rcv.name.nelem = 0; + + if (!S_ISLNK(ino->i_mode)) + return -EINVAL; + + userfs_genpkt(ino->i_sb, &pre, userfs_up_readlink); + + snd.link = U_INOP(ino)->handle; + + if ((ret = userfs_doop(ino->i_sb, &pre, &repl, + upp_readlink_s, &snd, + upp_readlink_r, &rcv)) != 0) + { + printk("do_readlink(userfs): userfs_doop failed %d\n", ret); + return ret; + } + + if (repl.err_no != 0) + return -repl.err_no; + + *res = rcv.name; + + return 0; +} + +k_static int userfs_readlink(struct dentry *de, char *name, int nlen) +{ + int ret; + up_name path; + +#ifdef DEBUG + printk("userfs_readlink(%p,%s,%d)\n",de,name,nlen); +#endif + path.elems = NULL; + + ret = do_readlink(de->d_inode, &path); + + if (ret != 0) + goto out; + + ret = MIN(nlen, path.nelem); + + if (ret > 0) + if(copy_to_user(name, path.elems, ret)) + ret = -EPERM; + +out: + if (path.elems != NULL) + FREE(path.elems); + + iput(de->d_inode); + return ret; +} + +int do_followlink(struct inode *dir, struct dentry *base, int follow, int useread) +{ + up_name path; + char *fpath; + int fplen; + int ret; + struct dentry *result = NULL; + struct nameidata nd; + + nd.dentry=base; + nd.flags=follow; + +#ifdef DEBUG + printk("do_followlink(%p,%p,...)\n",dir,base); +#endif + if (dir == NULL) + { + dir = current->fs->root->d_inode; + dir->i_count.counter++; + } + + if (!base || !base->d_inode) + { + iput(dir); + return -ENOENT; + } + + if (!S_ISLNK(base->d_inode->i_mode)) + { + iput(dir); + return 0; + } + + path.elems = NULL; + + if (current->link_count > 5) + { + result = ERR_PTR(-ELOOP); + goto out; + } + + if (useread) + { + ret = do_readlink(base->d_inode, &path); + if (ret != 0) { + result = ERR_PTR(ret); + goto out; + } + } + else + { + up_preamble pre; + upp_repl repl; + upp_followlink_s snd; + upp_followlink_r rcv; + + rcv.path.nelem = 0; + + userfs_genpkt(dir->i_sb, &pre, userfs_up_followlink); + + snd.dir = U_INOP(dir)->handle; + snd.link = U_INOP(base->d_inode)->handle; + snd.flag = 0; /* flag */ + snd.mode = 0; /* mode */ + + ret = userfs_doop(dir->i_sb, &pre, &repl, + upp_followlink_s, &snd, + upp_followlink_r, &rcv); + if(ret != 0) + { + printk("userfs_followlink: userfs_doop failed %d\n", + ret); + result = ERR_PTR(ret); + goto out; + } + + if (repl.err_no != 0) + { + result = ERR_PTR(-repl.err_no); + goto out; + } + path = rcv.path; + } + + fplen = path.nelem; + fpath = (char *)kmalloc(fplen+1, GFP_KERNEL); + memcpy(fpath, (char *)path.elems, fplen); + fpath[fplen] = '\0'; + + current->link_count++; + /* result = lookup_dentry(fpath, base, follow); + * struct nameidata { + * struct dentry *dentry; + * struct vfsmount *mnt; + * struct qstr last; + * unsigned int flags; + * int last_type; + *}; + */ + + path_walk(fpath, &nd); + current->link_count--; + + kfree(fpath); /* , fplen+1); */ + + out: + if (path.elems != NULL) + FREE(path.elems); + + dput(base); + iput(dir); + + return 0; /* nd.dentry; */ +} + +/* Do a followlink, using the followlink operation */ +int userfs_followlink(struct dentry *dir, struct nameidata *nd) +{ + return do_followlink(dir->d_inode, nd->dentry, nd->flags, 0); +} + +/* Do a followlink, using readlink to get the info */ +int userfs_followlink2(struct dentry *dir, struct nameidata *nd) +{ + return do_followlink(dir->d_inode, nd->dentry, nd->flags, 1); +} + +k_static int userfs_symlink(struct inode *dir, struct dentry *de, + const char *symname) +{ + int ret; + up_preamble pre; + upp_repl repl; + upp_symlink_s snd; + +#ifdef DEBUG + printk("userfs_symlink(%p,%p,%s)\n",dir,de,symname); +#endif + if (!dir || !S_ISDIR(dir->i_mode)) + return -ENOTDIR; + + userfs_genpkt(dir->i_sb, &pre, userfs_up_symlink); + + snd.dir = U_INOP(dir)->handle; + snd.name.elems = (char *)de->d_name.name; + snd.name.nelem = de->d_name.len; + snd.symname.elems = (char *)symname; + snd.symname.nelem = strlen(symname); + userfs_setcred(&snd.cred); + + if ((ret = userfs_doop(dir->i_sb, &pre, &repl, + upp_symlink_s, &snd, void, NULL)) != 0) + printk("userfs_symlink: userfs_doop failed: %d\n", ret); + else + ret = -repl.err_no; + + return ret; +} + +k_static int userfs_unlink(struct inode *dir, struct dentry *de) +{ + up_preamble pre; + upp_unlink_s snd; + upp_repl rcv; + int ret; + +#ifdef DEBUG + printk("userfs_unlink(%p,%p)\n",dir,de); +#endif + if (!dir || !S_ISDIR(dir->i_mode)) + return -ENOTDIR; + + userfs_genpkt(dir->i_sb, &pre, userfs_up_unlink); + + snd.dir = U_INOP(dir)->handle; + snd.name.nelem = de->d_name.len; + snd.name.elems = (char *)de->d_name.name; + + if ((ret = userfs_doop(dir->i_sb, &pre, &rcv, upp_unlink_s, &snd, void, NULL)) != 0) + printk("userfs_unlink: userfs_doop failed %d\n", ret); + else + ret = -rcv.err_no; + + if(!ret) + d_delete(de); + + return ret; +} + +int userfs_link(struct dentry * old, struct inode * dir, struct dentry *new) +{ + int ret; + up_preamble pre; + upp_repl repl; + upp_link_s snd; + +#ifdef DEBUG + printk("userfs_link(%p,%p,%p)\n",old,dir,new); +#endif + if (!dir || !S_ISDIR(dir->i_mode)) + return -EBADF; + + if (!old || !old->d_inode) + { + ret = -ENOENT; + goto out; + } + + userfs_genpkt(dir->i_sb, &pre, userfs_up_link); + + snd.ofile = U_INOP(old->d_inode)->handle; + snd.dir = U_INOP(dir)->handle; + snd.name.elems = (char *)new->d_name.name; + snd.name.nelem = new->d_name.len; + + if ((ret = userfs_doop(dir->i_sb, &pre, &repl, + upp_link_s, &snd, void, NULL)) != 0) + printk("userfs_link: userfs_doop failed: %d\n", ret); + else + ret = -repl.err_no; + + out: + iput(dir); + + if (old) + dput(old); + + return ret; +} + +k_static void userfs_truncate(struct inode *ino) +{ + up_preamble pre; + upp_truncate_s snd; + upp_repl repl; + int ret; + +#ifdef DEBUG + printk("userfs_truncate(%p)\n",ino); +#endif + userfs_genpkt(ino->i_sb, &pre, userfs_up_truncate); + + snd.file = U_INOP(ino)->handle; + snd.size = ino->i_size; + + if ((ret = userfs_doop(ino->i_sb, &pre, &repl, upp_truncate_s, &snd, void, NULL)) != 0) + printk("userfs_truncate: userfs_doop failed %d\n", ret); + else + ret = repl.err_no; +} + +k_static int userfs_permission(struct inode *ino, int mask) +{ + up_preamble pre; + upp_permission_s snd; + upp_repl repl; + int ret; + +#ifdef DEBUG + printk("userfs_permission(%p,%d)\n",ino,mask); +#endif + userfs_genpkt(ino->i_sb, &pre, userfs_up_permission); + + userfs_setcred(&snd.cred); + snd.mask = mask; + snd.file = U_INOP(ino)->handle; + + if ((ret = userfs_doop(ino->i_sb, &pre, &repl, upp_permission_s, &snd, void, NULL)) != 0) + printk("userfs_permission: userfs_doop failed %d\n", ret); + else + ret = repl.err_no; + + return ret == 0; +} + +k_static int userfs_rename(struct inode *odir, struct dentry *ode, + struct inode *ndir, struct dentry *nde) +{ + up_preamble pre; + upp_rename_s snd; + upp_repl repl; + int ret; + +#ifdef DEBUG + printk("userfs_rename(...)\n"); +#endif + if (!odir || !S_ISDIR(odir->i_mode) || + !ndir || !S_ISDIR(ndir->i_mode)) + return -ENOTDIR; + + assert(odir->i_sb == ndir->i_sb); + + userfs_genpkt(odir->i_sb, &pre, userfs_up_rename); + + snd.odir = U_INOP(odir)->handle; + snd.oname.elems = (char *)ode->d_name.name; + snd.oname.nelem = ode->d_name.len; + + snd.ndir = U_INOP(ndir)->handle; + snd.nname.elems = (char *)nde->d_name.name; + snd.nname.nelem = nde->d_name.len; + + if ((ret = userfs_doop(odir->i_sb, &pre, &repl, upp_rename_s, &snd, void, NULL)) != 0) + { + printk("userfs_rename: userfs_doop failed %d\n", ret); + return ret; + } + if(repl.err_no) + return -repl.err_no; + + return 0; +} + +/* Ask process if operation is supported */ +int userfs_probe(struct super_block *sb, up_ops op) +{ + up_preamble pre; + upp_repl repl; + int ret; + +#ifdef DEBUG + printk("userfs_probe()\n"); +#endif + userfs_genpkt(sb, &pre, op); + + pre.isreq = UP_ENQ; + + if ((ret = userfs_doop(sb, &pre, &repl, void, NULL, void, NULL)) != 0) + { + printk("userfs_probe: userfs_doop failed: %d\n", ret); + return 0; + } + + return repl.err_no == 0; +} + +/* disable things that process won't cope with */ +struct inode_operations *userfs_probe_iops(struct super_block *sb) +{ + struct inode_operations *iops; + +#ifdef DEBUG + printk("userfs_probe_iops(%p)\n",sb); +#endif + iops = (struct inode_operations *)kmalloc(sizeof(*iops), GFP_KERNEL); + + *iops = userfs_inode_operations; + + /* iops->default_file_ops = userfs_probe_fops(sb); */ + + if (!userfs_probe(sb, userfs_up_lookup)) + iops->lookup = NULL; + if (!userfs_probe(sb, userfs_up_create)) + { + printk("Sorry, you can't create stuff.\n"); + iops->create = NULL; + iops->mkdir = NULL; + iops->mknod = NULL; + } + if (!userfs_probe(sb, userfs_up_link)) + iops->link = NULL; + if (!userfs_probe(sb, userfs_up_unlink)) + { + iops->unlink = NULL; + iops->rmdir = NULL; + } + if (!userfs_probe(sb, userfs_up_rename)) + iops->rename = NULL; + if (!userfs_probe(sb, userfs_up_readlink)) + iops->readlink = NULL; + if (!userfs_probe(sb, userfs_up_symlink)) + iops->symlink = NULL; + + /* + * If the proc supports readlink but not followlink, + * implement followlink in terms of readlink. + * Is this really the Right Thing? + */ + if (!userfs_probe(sb, userfs_up_followlink)) + { + if (iops->readlink) + iops->follow_link = userfs_followlink2; + else + iops->follow_link = NULL; + } + if (!userfs_probe(sb, userfs_up_permission)) + iops->permission = NULL; + if (!userfs_probe(sb, userfs_up_truncate)) + iops->truncate = NULL; + + return iops; +} + +#define PG_LOCK(page) set_bit(PG_locked, &(page)->flags) +#define PG_UNLOCK(page) clear_bit(PG_locked, &(page)->flags) +#define PG_CLRERROR(page) clear_bit(PG_error, &(page)->flags) +#define PG_UPTODATE(page) set_bit(PG_uptodate, &(page)->flags) +#define PG_ISUPTODATE(page) (Page_Uptodate((page))) + +k_static int userfs_readpage(struct file *file, struct page *page) +{ + unsigned long address; + off_t off; + struct inode *inode = file -> f_dentry -> d_inode; + + address = (unsigned long) page_address(page); + atomic_inc(&page->count); + if (PG_ISUPTODATE(page)) { + free_page(address); + return 0; + } + + PG_LOCK(page); + PG_CLRERROR(page); + + /* + * Unfortunately we don't get the file pointer passed here, so + * we can't get the credentials token. It wouldn't really make + * sense anyway. + */ + printk("userfs_readpaqge: calling do_userfs_read: off=%ld\n", page->index*PAGE_SIZE); +/* off = do_userfs_read(inode, 0, page->index, + (char *)address, PAGE_SIZE, 0); */ + off = do_userfs_read(inode, 0, page->index*PAGE_SIZE, + (char *)address, PAGE_SIZE, 0); + printk("userfs_readpaqge: do_userfs_read returned %ld\n", off); + if (off < PAGE_SIZE) + { + off_t fix = off < 0 ? 0 : off; + printk("userfs_readpaqge: off=%ld < PAGE_SIZE=%ld, fix=%ld\n", off, PAGE_SIZE, fix); + + memset((char *)address+fix, 0, PAGE_SIZE-fix); + } + + PG_UPTODATE(page); + PG_UNLOCK(page); + + wake_up(&page->wait); + free_page(address); + return 0; +} +/* +struct inode_operations { + int (*create) (struct inode *,struct dentry *,int); + struct dentry * (*lookup) (struct inode *,struct dentry *); + int (*link) (struct dentry *,struct inode *,struct dentry *); + int (*unlink) (struct inode *,struct dentry *); + int (*symlink) (struct inode *,struct dentry *,const char *); + int (*mkdir) (struct inode *,struct dentry *,int); + int (*rmdir) (struct inode *,struct dentry *); + int (*mknod) (struct inode *,struct dentry *,int,int); + int (*rename) (struct inode *, struct dentry *, + struct inode *, struct dentry *); + int (*readlink) (struct dentry *, char *,int); + int (*follow_link) (struct dentry *, struct nameidata *); + void (*truncate) (struct inode *); + int (*permission) (struct inode *, int); + int (*revalidate) (struct dentry *); + int (*setattr) (struct dentry *, struct iattr *); + int (*getattr) (struct dentry *, struct iattr *); +}; +*/ + +struct inode_operations userfs_inode_operations = +{ +/* &userfs_file_operations, */ + userfs_create, /* create */ + userfs_lookup, /* lookup */ + userfs_link, /* link */ + userfs_unlink, /* unlink */ + userfs_symlink, /* symlink */ + userfs_mkdir, /* mkdir */ + userfs_unlink, /* rmdir */ + userfs_mknod, /* mknod */ + userfs_rename, /* rename */ + userfs_readlink, /* readlink */ + userfs_followlink, /* follow_link */ +/* userfs_readpage,*/ /* readpage */ +/* NULL, */ /* writepage */ +/* NULL, */ /* bmap */ + userfs_truncate, /* truncate */ + userfs_permission, /* permission */ +/* NULL, */ /* smap */ +/* NULL, */ /* updatepage */ + NULL, /* revalidate */ + NULL, /* setattr */ + NULL, /* getattr */ +}; + +struct address_space_operations userfs_aops = +{ +/* readpage: ext2_readpage, + writepage: ext2_writepage, + sync_page: block_sync_page, + prepare_write: ext2_prepare_write, + commit_write: generic_commit_write, + bmap: ext2_bmap +*/ + readpage: userfs_readpage, +}; + Added: trunk/kernel/src/super.c ============================================================================== --- trunk/kernel/src/super.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/src/super.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,609 @@ +/* + * Super block/filesystem wide operations + * + * Jeremy Fitzhardinge , May 1993 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define __NO_VERSION__ +#include + +#include +#include +#include + +#include "userfs.h" + +static void userfs_free_super(struct super_block *sb) +{ +#ifdef DEBUG + printk("userfs_free_super()\n"); +#endif + + if(!sb) + { + printk("warning: sb was NULL!\n"); + return; + } + + userfs_close_chan(sb); + + if (sb->s_op != &userfs_super_operations) + kfree(sb->s_op); /*, sizeof(struct super_operations)); */ + +/* kfree_s(U_SBP(sb)->s_iops->default_file_ops, + sizeof(struct file_operations)); */ + kfree(U_SBP(sb)->s_iops); /*, sizeof(struct inode_operations)); */ + + sb->s_dev = 0; + + if (U_SBP(sb)->s_nwproc != 0) + { +#ifdef DEBUG + printk("kissing process... "); +#endif + assert(U_SBP(sb)->s_wlist != NULL); + userfs_kiss(sb, UP_WALL, UP_FINISH); +#ifdef DEBUG + printk("ok\n"); +#endif + } + + assert(U_SBP(sb)->s_nwproc == 0); + assert(U_SBP(sb)->s_wlist == NULL); + + MOD_DEC_USE_COUNT; +#ifdef DEBUG + printk("bye.\n"); +#endif + +} + +static void userfs_put_super(struct super_block *sb) +{ + up_preamble snd; + upp_repl repl; + int ret; + + userfs_genpkt(sb, &snd, userfs_up_umount); + + /* lock_super(sb); - we get this lock for free now in 2.4 */ + if ((ret = userfs_doop(sb, &snd, &repl, void, NULL, void, NULL)) != 0) + printk("userfs_put_super: userfs_doop returns %d\n", ret); + + /* unlock_super(sb); */ + + if (repl.err_no != 0) + printk("userfs_put_super: up_umount failed with %ld\n", repl.err_no); + userfs_free_super(sb); +} + +static void userfs_free_inode(struct inode *ino) +{ + if (! (ino->i_state&I_FREEING) ) + ino->i_state |= I_FREEING; + if (ino->i_data.nrpages) + truncate_inode_pages(&ino->i_data, 0); + if (ino->i_count.counter > 1) + return; + +#ifdef USE_MULTIDIRREAD + userfs_free_dirra(ino); +#endif + + /* Make sure the inode isn't cached */ + clear_inode(ino); +} + +static void userfs_put_inode(struct inode *ino) +{ + up_preamble pre; + upp_iput_s pkt; + upp_repl repl; + int ret; + +#ifdef DEBUG + printk("userfs_put_inode(%lX)\n",U_INOP(ino)->handle.handle); +#endif + userfs_genpkt(ino->i_sb, &pre, userfs_up_iput); + pkt.handle = U_INOP(ino)->handle; + + userfs_lock_inode(ino); + + if ((ret = userfs_doop(ino->i_sb, &pre, &repl, upp_iput_s, &pkt, void, NULL)) != 0) + printk("userfs_put_inode: userfs_doop failed %d\n", ret); + else + { + if (repl.err_no != 0) + printk("userfs_put_inode: operation failed with %ld\n", + repl.err_no); + } + userfs_unlock_inode(ino); + userfs_free_inode(ino); +} +static int userfs_statfs_stub(struct super_block *sb, struct statfs *buf) +/* static int userfs_statfs_stub(struct super_block *sb, struct statfs *buf, int bufsz) */ +{ + struct statfs sfs; + + memset(&sfs, 0, sizeof(sfs)); + + sfs.f_type = USERFS_SUPER_MAGIC; + sfs.f_bsize = 1024; + sfs.f_blocks = 0; + sfs.f_bfree = 0; + sfs.f_bavail = 0; + sfs.f_files = 0; + sfs.f_ffree = 0; + sfs.f_namelen = NAME_MAX; + + copy_to_user(buf, &sfs, sizeof(sfs)); + + return 0; +} + +static int userfs_statfs(struct super_block *sb, struct statfs *buf) +/* static int userfs_statfs(struct super_block *sb, struct statfs *buf, int bufsz) */ +{ + up_preamble pre; + upp_repl repl; + upp_statfs_r rcv; + int ret; + struct statfs sfs; + + userfs_genpkt(sb, &pre, userfs_up_statfs); + + if ((ret = userfs_doop(sb, &pre, &repl, + void, NULL, upp_statfs_r, &rcv)) != 0) + { + printk("userfs_statfs: userfs_doop failed: %d\n", ret); + memset(&sfs, 0, sizeof(struct statfs)); + + return EBADF; + } + else + { + int i; + + sfs.f_type = USERFS_SUPER_MAGIC; + sfs.f_bsize = rcv.bsize; + sfs.f_blocks = rcv.blocks; + sfs.f_bfree = rcv.bfree; + sfs.f_bavail = rcv.bavail; + sfs.f_files = rcv.files; + sfs.f_ffree = rcv.ffree; + for(i = 0; i < sizeof(sfs.f_fsid.val)/sizeof(*sfs.f_fsid.val); i++) + sfs.f_fsid.val[i] = rcv.fsid[i]; + sfs.f_namelen = rcv.namelen; + } + + copy_to_user(buf, &sfs, sizeof(sfs)); + + return 0; +} + +struct super_block * +userfs_read_super(struct super_block *sb, void *raw_data, int flag) +{ + struct file *toproc; + struct file *fromproc; + struct userfs_mount *mntinfo = (struct userfs_mount *)raw_data; + up_preamble snd; + upp_mount_r rcv; + upp_repl repl; + int ret; + struct inode *root=NULL; + struct files_struct *files; + +#ifdef DEBUG + printk("userfs_read_super entered infd=%X outfd=%X\n", + mntinfo->fromkern, + mntinfo->tokern); +#endif + + MOD_INC_USE_COUNT; + + /* don't alloc - it's in the superblock struct already */ + memset(U_SBP(sb), 0, sizeof(*U_SBP(sb))); + + toproc = fromproc = NULL; + + U_SBP(sb)->s_toproc = toproc; + U_SBP(sb)->s_fromproc = fromproc; + + if (raw_data == NULL) + { + printk("userfs_read_super: extra mount data missing\n"); + goto fail; + } + + if (mntinfo->version != USERFS_VERSION) + { + printk("userfs_read_super: mount data version %d, kernel is %d\n", + mntinfo->version, USERFS_VERSION); + goto fail; + } + + if (mntinfo->magic != USERFS_SUPER_MAGIC) + { + printk("userfs: client tried to mount with incorrect magic number in parameter block\n"); + goto fail; + } + + spin_lock_init(&(U_SBP(sb)->s_lock)); + +#ifdef DEBUG + if(!current->files) + printk("userfs_read_super current->files is null\n"); +#endif + +#ifdef DEBUG + printk("userfs_read_super getting from kern fd\n"); +#endif + task_lock(current); + files = current->files; + if (files) /* do we want to do this!? */ + atomic_inc(&files->count); + task_unlock(current); + if ((toproc = fcheck_files(files, mntinfo->fromkern)) == NULL ) + { + printk("userfs_read_super: bad fromkern fd %d\n", + mntinfo->fromkern); + goto fail; + } + +#ifdef DEBUG + printk("userfs_read_super checking fd is writeable\n"); +#endif + + if( !(toproc->f_mode&FMODE_WRITE) ) + { + printk("userfs_read_super: bad fromkern fd %d\n", + mntinfo->fromkern); + goto fail; + } + + U_SBP(sb)->s_toproc = toproc; + +#ifdef DEBUG + printk("userfs_read_super getting to kernel fd\n"); +#endif + task_lock(current); + files = current->files; + if (files) + atomic_inc(&files->count); + task_unlock(current); + if ((fromproc = fcheck_files(files, mntinfo->tokern)) == NULL ) + { + printk("userfs_read_super: bad tokern fd %d\n", + mntinfo->tokern); + goto fail; + } + +#ifdef DEBUG + printk("userfs_read_super checking fd is readable\n"); +#endif + + if ( !(fromproc->f_mode&FMODE_READ)) + { + printk("userfs_read_super: bad tokern fd %d\n", + mntinfo->tokern); + goto fail; + } + + U_SBP(sb)->s_fromproc = fromproc; + + toproc->f_count.counter++; + fromproc->f_count.counter++; + + sb->s_magic = USERFS_SUPER_MAGIC; + sb->s_blocksize = 1024; + sb->s_op = &userfs_super_operations; + sb->s_flags = 0; + + U_SBP(sb)->s_seq = mntinfo->seq; + U_SBP(sb)->s_iops = &userfs_inode_operations; + + U_SBP(sb)->s_nwproc = 0; + U_SBP(sb)->s_canread = 0; + U_SBP(sb)->s_wlist = NULL; + +#ifdef DEBUG + printk("userfs_read_super requesting superblock mount\n"); +#endif + + userfs_genpkt(sb, &snd, userfs_up_mount); + + ret = userfs_doop(sb, &snd, &repl, void, NULL, upp_mount_r, &rcv); + + if (ret != 0) + { + printk("userfs_read_super: userfs_doop failed with %d\n", ret); + goto fail; + } + + if (repl.err_no != 0) + { + printk("userfs_read_super: mount failed with %ld\n", + repl.err_no); + goto fail; + } + + U_SBP(sb)->s_root = rcv.root; + +#ifdef DEBUG + printk("userfs_read_super requesting process capabilities\n"); +#endif + + sb->s_op = userfs_probe_sops(sb); + U_SBP(sb)->s_iops = userfs_probe_iops(sb); + +#ifdef DEBUG + printk("userfs_read_super allocating root dirent\n"); +#endif + + root = iget(sb,U_SBP(sb)->s_root.handle); + if(!root) + goto fail; + + U_INOP(root)->handle.handle = U_SBP(sb)->s_root.handle; + + if (!(sb->s_root = d_alloc_root(root))) + { + printk("userfs_read_super: get root inode %ld failed\n", + U_SBP(sb)->s_root.handle); + goto fail; + } + +#ifdef DEBUG + printk("read superblock %lX\n",U_INOP(root)->handle.handle); +#endif + + return sb; + +fail: + printk("userfs_read_super"": failed\n"); + + if (sb != NULL) + { + sb->s_dev = 0; + sb->s_op = NULL; + sb->s_magic = 0; + userfs_close_chan(sb); + } + + MOD_DEC_USE_COUNT; + + return NULL; +} + +extern struct inode_operations userfs_inode_operations; + +void userfs_set_inode(struct inode *inode, const up_inode *rcv) +{ + inode->i_mode = rcv->mode; + inode->i_nlink = rcv->nlink; + inode->i_uid = rcv->uid; + inode->i_gid = rcv->gid; + inode->i_size = rcv->size; + inode->i_atime = rcv->atime; + inode->i_mtime = rcv->mtime; + inode->i_ctime = rcv->ctime; + inode->i_blksize = rcv->blksize; + inode->i_blocks = rcv->blocks; + inode->i_rdev = rcv->rdev; + + /* these things seem to be new to kernel 2.2.6 */ + inode->i_version = ++event; /* something unique, i guess */ + inode->i_attr_flags = 0; /* also set to zero in ext2 */ + inode->i_flags = 0; /* don't know the meaning */ +} + +extern struct address_space_operations userfs_aops; +extern struct inode_operations userfs_inode_operations; +extern struct file_operations userfs_file_operations; + +void userfs_read_inode(struct inode *inode) +{ + up_preamble pre; + upp_repl repl; + upp_iread_s snd; + upp_iread_r rcv; + int ret; + + if(!inode) + { + printk("inode pointer NULL!"); + return; + } + +#ifdef DEBUG + printk("Reading inode %lX\n",inode->i_ino); +#endif + + inode->i_op = NULL; + inode->i_mode = 0; + inode->i_flags = 0; + inode->i_mapping->a_ops = NULL; + inode->i_fop = NULL; + + userfs_genpkt(inode->i_sb, &pre, userfs_up_iread); + + snd.handle.handle = inode->i_ino; + + if ((ret = userfs_doop(inode->i_sb, &pre, &repl, upp_iread_s, &snd, upp_iread_r, &rcv)) != 0) + { + printk("userfs_read_inode: failed to do upp_iread: %d\n", ret); + return; + } + + if (repl.err_no != 0) + { + printk("userfs_read_inode: inode read failed: ino=%ld, errno = %ld\n", + inode->i_ino, repl.err_no); + memset(&rcv, 0, sizeof(rcv)); + } + else + { + assert(rcv.handle.handle == inode->i_ino); + assert(inode->i_nlink != 0); + + if ((rcv.handle.handle == inode->i_ino) && (inode->i_nlink != 0)) + { + inode->i_op = U_SBP(inode->i_sb)->s_iops; + inode->i_mapping->a_ops = &userfs_aops; + inode->i_fop = &userfs_file_operations; + } + else + { + printk("Bad: different inode handle returned.\n"); + memset(&rcv, 0, sizeof(rcv)); + } + } + + U_INOP(inode)->handle = rcv.handle; + U_INOP(inode)->dir_ra = NULL; + U_INOP(inode)->version = 0; + + userfs_set_inode(inode, &rcv.ino); +} + +k_static void userfs_pack_iattr(up_iattr *target, const struct iattr *source) +{ + target->ia_valid = source->ia_valid; + target->ia_mode = source->ia_mode; + target->ia_uid = source->ia_uid; + target->ia_gid = source->ia_gid; + target->ia_size = source->ia_size; + target->ia_atime = source->ia_atime; + target->ia_mtime = source->ia_mtime; + target->ia_ctime = source->ia_ctime; +} + +k_static int userfs_notify_change(struct dentry *dentry, struct iattr *iattr) +{ + up_preamble pre; + upp_notify_change_s snd; + upp_repl rcv; + int ret; + struct inode *inode = dentry->d_inode; + + userfs_genpkt(inode->i_sb, &pre, userfs_up_notify_change); + + snd.handle = U_INOP(inode)->handle; + userfs_pack_iattr(&snd.iattr, iattr); + + if ((ret = userfs_doop(inode->i_sb, &pre, &rcv, + upp_notify_change_s, &snd, + void, NULL)) != 0) + { + printk("userfs_notify_change: transaction failed: %d\n", ret); + return ret; + } + + userfs_read_inode(inode); + + return -rcv.err_no; +} + +k_static void userfs_pack_inode(up_inode *ino, const struct inode *inode) +{ + ino->mode = inode->i_mode; + ino->nlink = inode->i_nlink; + ino->uid = inode->i_uid; + ino->gid = inode->i_gid; + ino->size = inode->i_size; + ino->atime = inode->i_atime; + ino->mtime = inode->i_mtime; + ino->ctime = inode->i_ctime; + ino->blksize = inode->i_blksize; + ino->blocks = inode->i_blocks; +} + +k_static int userfs_write_change(int flags, struct inode *inode) +{ + up_preamble pre; + upp_iwrite_s snd; + upp_repl rcv; + int ret; + + userfs_genpkt(inode->i_sb, &pre, userfs_up_iwrite); + + snd.handle = U_INOP(inode)->handle; + userfs_pack_inode(&snd.ino, inode); + + if ((ret = userfs_doop(inode->i_sb, &pre, &rcv, + upp_iwrite_s, &snd, void, NULL)) != 0) + { + printk("userfs_write_change: transaction failed: %d\n", ret); + return ret; + } + + return rcv.err_no; +} + +k_static void userfs_write_inode(struct inode *inode, int just_showed_up_in_2_4) +/* k_static void userfs_write_inode(struct inode *inode) */ +{ + int ret; + + /* + * We arn't allowed to fail, so if the IO below doesn't work, + * tough. + */ + inode->i_state &= ~I_DIRTY; + + if ((ret = userfs_write_change(0, inode)) != 0) + printk("userfs_write_inode: inode write failed: %d\n", ret); +} + +struct super_operations *userfs_probe_sops(struct super_block *sb) +{ + struct super_operations *sops; + + sops = (struct super_operations *)kmalloc(sizeof(*sops), GFP_KERNEL); + *sops = userfs_super_operations; + + if (!userfs_probe(sb, userfs_up_iread)) + sops->read_inode = NULL; + if (!userfs_probe(sb, userfs_up_iwrite)) + sops->write_inode = NULL; + if (!userfs_probe(sb, userfs_up_iput)) + sops->put_inode = NULL; /* userfs_free_inode; */ + if (!userfs_probe(sb, userfs_up_umount)) + sops->put_super = userfs_free_super; + if (!userfs_probe(sb, userfs_up_statfs)) + sops->statfs = userfs_statfs_stub; + + return sops; +} + +struct super_operations userfs_super_operations = +{ + userfs_read_inode, /* read_inode */ + NULL, /* read_inode2 */ + NULL, /* dirty_inode */ + userfs_write_inode, /* write_inode */ + userfs_put_inode, /* put_inode */ + NULL, /* delete inode */ + userfs_put_super, /* put_super */ + NULL, /* write_super */ + NULL, /* write_super_lockfs */ + NULL, /* unlockfs */ + userfs_statfs, /* statfs */ + NULL, /* remount_fs */ + NULL, /* clear inode */ + NULL, /* unmount begin */ +}; + Added: trunk/kernel/src/file.c ============================================================================== --- trunk/kernel/src/file.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/src/file.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,649 @@ +/* + * Deal with file operations + * + * Jeremy Fitzhardinge , 1993-1995 + */ + +#include "userfs.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int do_userfs_read(struct inode *inode, + up_credtok tok, off_t offset, + char *buf, int size, int userspace) +{ + unsigned int max_size; + up_preamble pre; + upp_repl repl; + upp_read_s snd; + upp_read_r rcv; + int rd = 0; + int sz; + int ret; + +#ifdef DEBUG + printk("do_userfs_read()\n"); +#endif + + if (inode == NULL) + { + printk("userfs_read: inode is NULL\n"); + return -EINVAL; + } + + rcv.data.nelem = 0; + max_size = MAX_KMALLOC - sizeof_upp_read_r(&rcv); + + snd.file = U_INOP(inode)->handle; + snd.ctok = tok; + + while(size > 0) + { + userfs_genpkt(inode->i_sb, &pre, userfs_up_read); + + snd.off = offset; + snd.size = MIN(max_size, size); + + if ((ret = userfs_doop(inode->i_sb, &pre, &repl, + upp_read_s, &snd, + upp_read_r, &rcv)) != 0) + { + printk("userfs_read: userfs_doop failed %d\n", + ret); + if (rd == 0) + rd = ret; + break; + } + + if (repl.err_no != 0) + { + if (rd == 0) + { + rd = -repl.err_no; + printk("userfs_read: repl.err.no!=0 : %d\n", rd); + } + + break; + } + + if (rcv.data.nelem == 0) + break; + + sz = MIN(size, rcv.data.nelem); + + if (rcv.data.nelem > max_size) + { + printk("userfs_read: more than %d bytes in data (!!!) (%ld)\n", + max_size, rcv.data.nelem); + sz = MIN(sz, max_size); + } + + if (userspace) + copy_to_user(buf, rcv.data.elems, sz); + else + /* this looks bad... */ + memcpy(buf, rcv.data.elems, sz); + + offset += sz; + size -= sz; + rd += sz; + buf += sz; + + FREE(rcv.data.elems); + } + return rd; +} + +k_static ssize_t userfs_read(struct file *file, + char *buf, size_t size, loff_t *offset) +{ + /* + * If we have a unified VM/buffer cache, then we just use + * the generic read function. This will end up calling our + * userfs_readpage function to perform the actual IO if necessary. + */ + return generic_file_read(file, buf, size, offset); +} + +k_static ssize_t userfs_write(struct file *file, + const char *buf, size_t size, loff_t *ofs) +{ + up_preamble pre; + upp_repl repl; + upp_write_s snd; + upp_write_r rcv; + int wr = 0; + int sz; + int ret; + unsigned char *mbuf = NULL; + int bufsz = 0; + unsigned int max_size; + struct inode *inode = file->f_dentry->d_inode; + + if (inode == NULL) + { + printk("userfs_write: inode is NULL\n"); + return -EINVAL; + } + + snd.data.nelem = 0; + max_size = MAX_KMALLOC - sizeof_upp_write_s(&snd); + + snd.file = U_INOP(inode)->handle; + if(U_FILEP(file)) + snd.ctok = U_FILEP(file)->cred_tok; + else + memset(&snd.ctok, 0, sizeof snd.ctok); + + if(!ofs) + { + printk("userfs_write: offset pointer was NULL.\n"); + return -EINVAL; + } + + sz = MIN(max_size, size); + + mbuf = (unsigned char *)kmalloc(sz, GFP_KERNEL); + bufsz = sz; + + while(size > 0) + { + sz = MIN(max_size, size); + + copy_from_user(mbuf, buf, sz); + + userfs_genpkt(inode->i_sb, &pre, userfs_up_write); + + if (file->f_flags & O_APPEND) + snd.off = inode->i_size; + else + snd.off = *ofs; + + snd.data.elems = mbuf; + snd.data.nelem = sz; + + if ((ret = userfs_doop(inode->i_sb, &pre, &repl, + upp_write_s, &snd, + upp_write_r, &rcv)) != 0) + { + printk("userfs_write: userfs_doop failed %d\n", + ret); + if (wr == 0) + wr = ret; + break; + } + + if (repl.err_no != 0) + { + printk("userfs_write: error %lX occured\n",repl.err_no); + if (wr == 0) + wr = -repl.err_no; + break; + } + + sz = rcv.wrote; + + if (sz == 0) + { + printk("userfs_write: write op returned 0\n"); + break; + } + + /* update_vm_cache(inode, snd.off, buf, sz); */ + + /* update the size */ + if(file->f_flags&O_APPEND) + { + inode->i_size += sz; + mark_inode_dirty(inode); + } + else + { + (*ofs) += sz; + if(inode->i_size < (*ofs)) + { + inode->i_size = *ofs; + mark_inode_dirty(inode); + } + } + size -= sz; + wr += sz; + buf += sz; + } + + inode->i_version = ++event; + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + + if (mbuf != NULL) + { + kfree(mbuf); + mbuf = NULL; + bufsz = 0; + } + return wr; +} + +#ifdef USE_MULTIREADDIR + +/* i suspect this is broken and unnecessary for the 2.2.x kernel ! */ + +/* Free all read-ahead dir entries */ +void userfs_free_dirra(struct inode *ino) +{ + struct userfs_dir_ra *ra; + int i; + +#ifndef DEBUG + printk("userfs_free_dirra()\n"); +#endif + + if (ino == NULL) + return; + + if (U_INOP(ino)->dir_ra == NULL) + return; + + ra = U_INOP(ino)->dir_ra; + U_INOP(ino)->dir_ra = NULL; + + for(i = 0; i < ra->nent; i++) + { + if (ra->ents[i].name != NULL) + kfree(ra->ents[i].name); /*, ra->ents[i].nlen); */ + } + + kfree(ra->ents); /* , sizeof(*ra->ents)*ra->nent); */ + kfree(ra); /* , sizeof(*ra)); */ +} + +/* + * Look up dir entry given offset for inode + * Returns pointer to entry on success, NULL on failure + */ +k_static struct userfs_dent *lookup_ra_dent(struct inode *dir, off_t off) +{ + struct userfs_dir_ra *ra; + int i; + +#ifdef DEBUG + printk("lookup_ra_dent()\n"); +#endif + + if (dir == NULL || U_INOP(dir)->dir_ra == NULL) + return NULL; + + ra = U_INOP(dir)->dir_ra; + + for(i = 0; i < ra->nent; i++) + if (ra->ents[i].roff == off) + return &ra->ents[i]; + return NULL; +} + +k_static int userfs_multireaddir(struct file *file, + void *dirent, filldir_t filldir) +{ + up_preamble pre; + upp_repl repl; + upp_multireaddir_s snd; + upp_multireaddir_r rcv; + struct userfs_dent *dent; + struct userfs_dir_ra *ra; + long ret = 0, err; + int i; + off_t off; + struct inode *dir = file->f_dentry->d_inode; + +#ifdef DEBUG + printk("userfs_multireaddir()\n"); +#endif + + if (!dir || !S_ISDIR(dir->i_mode)) + return -ENOTDIR; + + /* Try for read-ahead entries first */ + while((dent = lookup_ra_dent(dir, file->f_pos)) != NULL) + { + int len; + + len = MIN(NAME_MAX, dent->nlen); + if ((*filldir)(dirent, dent->name, len, + file->f_pos, dent->inum) != 0) + return ret; + ret += dent->offset; + file->f_pos += dent->offset; + } + + /* Flush the read-ahead and get something new */ + userfs_free_dirra(dir); + + userfs_genpkt(dir->i_sb, &pre, userfs_up_multireaddir); + + snd.off = file->f_pos; + snd.dir = U_INOP(dir)->handle; + if(U_FILEP(file)) + snd.ctok = U_FILEP(file)->cred_tok; + else + memset(&snd.ctok, 0, sizeof snd.ctok); + + rcv.nelem = 0; + rcv.elems = NULL; + + userfs_lock_inode(dir); + + if ((err = userfs_doop(dir->i_sb, &pre, &repl, upp_multireaddir_s, + &snd, upp_multireaddir_r, &rcv)) != 0) + { + printk("userfs_multireaddir: userfs_doop failed %ld\n", err); + ret = err; + goto out; + } + + if (repl.err_no != 0) + { + ret = -repl.err_no; + goto out; + } + + if (rcv.nelem == 0) + goto out; + + ra = kmalloc(sizeof(*ra), GFP_KERNEL); + ra->nent = rcv.nelem; + ra->ents = kmalloc(sizeof(struct userfs_dent)*rcv.nelem, GFP_KERNEL); + + off = file->f_pos; + for(i = 0; i < rcv.nelem; i++) + { + ra->ents[i].roff = off; + off += ra->ents[i].offset = rcv.elems[i].off; + ra->ents[i].name = rcv.elems[i].name.elems; + ra->ents[i].nlen = rcv.elems[i].name.nelem; + ra->ents[i].inum = rcv.elems[i].file.handle; + } + U_INOP(dir)->dir_ra = ra; + + if (rcv.elems != NULL) + FREE(rcv.elems); + + while((dent = lookup_ra_dent(dir, file->f_pos)) != NULL) + { + int len; + + len = MIN(NAME_MAX, dent->nlen); + if ((*filldir)(dirent, dent->name, len, + file->f_pos, dent->inum , DT_UNKNOWN ) != 0) + break; + ret += dent->offset; + file->f_pos += dent->offset; + } + +out: + userfs_unlock_inode(dir); + return ret; +} +#endif + +k_static int userfs_readdir(struct file *file, + void *dirent, filldir_t filldir) +{ + up_preamble pre; + upp_repl repl; + upp_readdir_s snd; + upp_readdir_r rcv; + long ret; + struct inode *dir = NULL; + + if(!file) + { + printk("file pointer was null\n"); + return 0; + } + + if(!file->f_dentry) + { + printk("d_entry pointer was null\n"); + return 0; + } + + dir = file->f_dentry->d_inode; + +#ifdef DEBUG + printk("userfs_readdir()\n"); +#endif + + if (!dir || !S_ISDIR(dir->i_mode)) + return -ENOTDIR; + + if(!dir->i_sb) + { + printk("superblock ptr was null\n"); + return 0; + } + userfs_genpkt(dir->i_sb, &pre, userfs_up_readdir); + + snd.off = file->f_pos; + snd.dir = U_INOP(dir)->handle; + + if(U_FILEP(file)) + snd.ctok = U_FILEP(file)->cred_tok; + else { + memset(&snd.ctok, 0, sizeof snd.ctok); + } + + rcv.name.nelem = 0; + + userfs_lock_inode(dir); + + ret = userfs_doop(dir->i_sb, &pre, &repl, + upp_readdir_s, &snd, + upp_readdir_r, &rcv); + + userfs_unlock_inode(dir); + + if (ret != 0) + { + printk("userfs_readdir: userfs_doop failed %ld\n", ret); + return ret; + } + + if (repl.err_no != 0) + { + ret = -repl.err_no; + goto out; + } + + if (rcv.off != 0) + { + ret = MIN(NAME_MAX, rcv.name.nelem); + + if(filldir) + (*filldir)(dirent, rcv.name.elems, ret, + file->f_pos, rcv.file.handle, DT_UNKNOWN); + else + printk("filldir was null\n"); + file->f_pos += rcv.off; + } + + ret = rcv.off; + +out: + if (rcv.name.nelem != 0) + FREE(rcv.name.elems); + + return ret; +} + +k_static int userfs_open(struct inode *ino, struct file *file) +{ + upp_open_s snd; + upp_open_r rcv; + up_preamble pre; + upp_repl repl; + int ret = 0; + +#ifdef DEBUG + printk("userfs_open()\n"); +#endif + + if(!ino) + { + printk("Null inode.\n"); + return -EINVAL; + } + + userfs_genpkt(ino->i_sb, &pre, userfs_up_open); + + userfs_setcred(&snd.cred); + + if(!ino) + printk("userfs_open() ino null!\n"); + + snd.file = U_INOP(ino)->handle; + + if ((ret = userfs_doop(ino->i_sb, &pre, &repl, + upp_open_s, &snd, upp_open_r, &rcv)) != 0) + { + printk("userfs_open: userfs_doop failed %d\n", ret); + goto out; + } + + if ((ret = -repl.err_no) == 0) + { + /* gotta malloc this one */ + U_FILEP(file) = kmalloc(sizeof(struct userfs_file_info), GFP_KERNEL); + U_FILEP(file)->cred_tok = rcv.ctok; + } + + out: + return ret; +} + +k_static int userfs_stub_open(struct inode *ino, struct file *file) +{ + printk("userfs_STUB_open\n"); + U_FILEP(file)=NULL; + return 0; +} + +k_static int free_file(struct inode *ino, struct file *file) +{ + if (U_FILEP(file) != NULL) + { + kfree(U_FILEP(file)); /*, sizeof(*U_FILEP(file))); */ + return 0; + } + return -EBADF; +} + +k_static int userfs_close(struct inode *ino, struct file *file) +{ + upp_close_s snd; + up_preamble pre; + upp_repl repl; + int ret = 0; + +#ifdef DEBUG + printk("userfs_close()\n"); +#endif + + userfs_genpkt(ino->i_sb, &pre, userfs_up_close); + + snd.file = U_INOP(ino)->handle; + if(U_FILEP(file)) + snd.ctok = U_FILEP(file)->cred_tok; + else + memset(&snd.ctok,0,sizeof snd.ctok); + + if ((ret = userfs_doop(ino->i_sb, &pre, &repl, + upp_close_s, &snd, void, NULL)) != 0) + { + printk("userfs_close: userfs_doop failed %d\n", ret); + return -EBUSY; + } + + free_file(ino, file); + + return ret; +} + +/* disable things that process won't cope with */ +struct file_operations *userfs_probe_fops(struct super_block *sb) +{ + struct file_operations *fops; + +#ifdef DEBUG + printk("userfs_probe_fops()\n"); +#endif + + fops = (struct file_operations *)kmalloc(sizeof(*fops), GFP_KERNEL); + + *fops = userfs_file_operations; + + if (!userfs_probe(sb, userfs_up_read)) + fops->read = NULL; + if (!userfs_probe(sb, userfs_up_write)) + fops->write = NULL; +#ifdef USE_MULTIREADDIR + if (!userfs_probe(sb, userfs_up_multireaddir)) + { + if (userfs_probe(sb, userfs_up_readdir)) + fops->readdir = userfs_readdir; + else + fops->readdir = NULL; + } +#else + if (!userfs_probe(sb, userfs_up_readdir)) + fops->readdir = NULL; +#endif + if (!userfs_probe(sb, userfs_up_open)) + fops->open = userfs_stub_open; + if (!userfs_probe(sb, userfs_up_close)) + fops->release = free_file; + + return fops; +} + +k_static int userfs_mmap(struct file *file, struct vm_area_struct *vma) +{ +#ifdef DEBUG + printk("userfs_mmap()\n"); +#endif + + /* Check uptodate here */ + return generic_file_mmap(file, vma); +} + +struct file_operations userfs_file_operations = +{ + NULL, /* struct module owner */ + NULL, /* userfs_lseek */ + userfs_read, + userfs_write, + userfs_readdir, + NULL, /* userfs_poll */ + NULL, /* userfs_ioctl */ + userfs_mmap, + userfs_open, /* open */ + NULL, /* flush */ + userfs_close, /* release */ + NULL, /* can't fsync */ + NULL, /* can't fasync */ + NULL, /* lock */ + NULL, /* readv */ + NULL, /* writev */ +}; Added: trunk/kernel/src/userfs_types.h ============================================================================== --- trunk/kernel/src/userfs_types.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/src/userfs_types.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,2 @@ +/* Get the kernel ones */ +#include Added: trunk/kernel/src/userfs_types.ty ============================================================================== --- trunk/kernel/src/userfs_types.ty 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/src/userfs_types.ty 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,2 @@ +/* Just include main userfs_types.ty */ +#include Added: trunk/kernel/src/module.c ============================================================================== --- trunk/kernel/src/module.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/src/module.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,73 @@ +/* + * Handling for loadable module + */ + +#include +#include +#include +#include +#include +#include +#include +#include "userfs.h" + +DECLARE_FSTYPE(ufst,"userfs",userfs_read_super,0); +/* +static struct file_system_type ufst = +{ + "userfs2", + 0, + userfs_read_super, + NULL +}; +*/ + +int init_module(void) +{ + int err; + struct super_block super_test; + struct inode inode_test; + + /* + * This is a sanity check. The code is going to assume + * that the userfs superblock info will fit into the + * standard superblock's misc data union. If it doesn't + * you will have to change some stuff in userfs to + * allocate extra memory and store a pointer there instead. + * Alternative you could recompile your kernel with enough + * space for the userfs_sb structure in struct super. + */ + if ( ( sizeof super_test.u < sizeof(struct userfs_sb_info)) || + ( sizeof inode_test.u < sizeof(struct userfs_inode_info)) ) + { + printk("%s:%d A bad assumption was made\n",__FILE__,__LINE__); + printk("Userfs will not be installed.\n"); + return -1; + } + + err = register_filesystem(&ufst); + + if (err) + { + printk("userfs: failed to register filesystem\n"); + return err; + } + + return 0; +} + +void cleanup_module(void) +{ + int err; + if (MOD_IN_USE) + printk("userfs: filesystem in use, removal delayed\n"); + + + if ( (err = unregister_filesystem(&ufst)) ) + { + printk("userfs: failed to unregister filesystem\n"); + return; + } +} + + Added: trunk/kernel/src/userfs_types.c ============================================================================== --- trunk/kernel/src/userfs_types.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/src/userfs_types.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,5 @@ +/* + * Just include the generated userfs_types.c + */ +#include "userfs.h" +#include Added: trunk/kernel/src/uio.c ============================================================================== --- trunk/kernel/src/uio.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/src/uio.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,727 @@ +/* + * IO to user process + * + * Jeremy Fitzhardinge , May 1993 + */ + +#include "userfs.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DB(x) x + +#include + + +/* Close channels, make everything fail later */ +void userfs_close_chan(struct super_block *sb) +{ + struct file *file; + + /* this is not really possible, but test it anyhow */ + if (U_SBP(sb) == NULL) + return; + + /* Wake up all sleepers before killing connection */ + userfs_kiss(sb, UP_WALL, UP_FINISH); + + if (U_SBP(sb)->s_toproc) + { + file = U_SBP(sb)->s_toproc; + if(file) + { +#ifdef DEBUG + printk("freeing toproc handle %p\n",file); +#endif + file->f_op->release(file->f_dentry->d_inode, file); + U_SBP(sb)->s_toproc = NULL; + } +#ifdef DEBUG + else + { + printk("toproc handle was null\n"); + } +#endif + } + + if (U_SBP(sb)->s_fromproc) + { + file = U_SBP(sb)->s_fromproc; + + if(file) + { +#ifdef DEBUG + printk("freeing fromproc handle %p\n",file); +#endif + file->f_op->release(file->f_dentry->d_inode, file); + U_SBP(sb)->s_fromproc = NULL; + } +#ifdef DEBUG + else + { + printk("fromproc handle was null\n"); + } +#endif + } +} + +/* + * Write to a file descriptor, like the sys_write + * + * The data buffer passed in is in kernel space. + * The tricky part is that f_op->write needs a buffer in + * current's user space, so we remap "fs" to the kernel data space, + * so that kernel space appears as user space. + * + * This will keep writing until everything is done, unless there's + * EOF or an error. + */ +k_static int userfs_send(struct file *file, char *data, unsigned int count) +{ + int ret; + int wrote = 0; + mm_segment_t fs; + sigset_t blocked; + + if (!file) + return -EBADF; + + if (!(file->f_mode & 2)) + return -EBADF; + if (!file->f_op || !file->f_op->write) + return -EINVAL; + if (!count) + return 0; + + if (count == 0) + return 0; + + /* inode = file->f_dentry->d_inode; */ + + fs = get_fs(); + set_fs(get_ds()); + + /* Filesystems are supposed to be uninterruptible */ + spin_lock(current->sigmask_lock); + blocked = current->blocked; + /* current->blocked = ~0L; */ + sigaddset(¤t->blocked,SIGKILL); + spin_unlock(current->sigmask_lock); + + while(count > 0) + { + assert(file != NULL); + assert(file->f_op != NULL); + assert(file->f_op->write != NULL); + + /* FIXME: need to initialise ofs */ + + ret = file->f_op->write(file,(char *)data,count,&file->f_pos); + + if (ret <= 0) + goto bad; + + count -= ret; + data += ret; + wrote += ret; + } + + ret = wrote; + bad: + spin_lock(current->sigmask_lock); + current->blocked = blocked; + spin_unlock(current->sigmask_lock); + + set_fs(fs); + if (ret == 0) + printk("userfs_send: f_op->write wrote 0 bytes, %d total\n", + wrote); + + return ret; +} + +/* + * As above, except for reading into kernel space. + * + * Note that this is unlike a normal read() syscall, since it will + * keep reading until count bytes are read, unless the read returns + * error or EOF. + */ +k_static int userfs_recv(struct file *file, char *data, unsigned int count) +{ + int ret, read = 0; + mm_segment_t fs; + sigset_t blocked; + + if (!file) + return -EBADF; + + if (!(file->f_mode & 1)) + return -EBADF; + if (!file->f_op || !file->f_op->read) + return -EBADF; + if (!count) + return 0; + + fs = get_fs(); + set_fs(get_ds()); + + /* Filesystems are supposed to be uninterruptible */ + spin_lock(current->sigmask_lock); + blocked = current->blocked; +/* sigaddset(¤t->blocked,SIGKILL); + sigaddset(¤t->blocked,SIGALRM); */ + sigfillset(¤t->blocked); + spin_unlock(current->sigmask_lock); + + while(count > 0) + { + assert(file != NULL); + assert(file->f_op != NULL); + assert(file->f_op->read != NULL); + + /* FIXME: what was this for? */ + /* current->blocked = (unsigned long)-1; */ + + ret = file->f_op->read(file,(char *)data,count,&file->f_pos); + + if (ret < 0) + { + printk("userfs_recv barfed: %s : %d\n", (char *)file->f_dentry->d_name.name, ret); + goto bad; + } + + if (ret == 0) + break; + + data += ret; + count -= ret; + read += ret; + } + + ret = read; +bad: + spin_lock(current->sigmask_lock); + current->blocked = blocked; + spin_unlock(current->sigmask_lock); + + set_fs(fs); + return ret; +} + +/* + * Generate a normal request packet for sending, including managing + * seqence numbers, etc + */ +void userfs_genpkt(struct super_block *sb, up_preamble *pre, up_ops op) +{ + pre->op = op; + pre->version = UP_VERSION; + pre->isreq = UP_REQ; + pre->seq = U_SBP(sb)->s_seq++; + pre->size = 0; +} + +/* + * Set lock on the userfs part of super block + */ + +k_static void userfs_lock(struct super_block *sb) +{ + spin_lock(&(U_SBP(sb)->s_lock)); +} + +/* + * Release lock on userfs part of super block + */ +k_static void userfs_unlock(struct super_block *sb) +{ + spin_unlock(&(U_SBP(sb)->s_lock)); +} + +/* + * Add entry to list of waiting processes + */ +k_static void addwlist(struct userfs_sb_info *sbi, struct pwlist *ent) +{ +printk("addwlist\n"); + assert(ent != NULL); + if (ent == NULL) + return; + + init_waitqueue_head(&ent->bed); + + ent->next = sbi->s_wlist; + if (ent->next) + ent->next->prev = ent; + + ent->prev = NULL; + sbi->s_wlist = ent; + + sbi->s_nwproc++; + + /* Assert postconditions */ + assert(sbi->s_wlist == ent); + assert(ent->prev == NULL); + assert(ent->next == NULL || (ent->next->prev == ent)); + assert(sbi->s_nwproc != 0); + assert((ent->next == NULL && sbi->s_nwproc == 1) || (ent->next != NULL && sbi->s_nwproc > 1)); +} + +/* + * Remove from list of waiting processes + */ +k_static void remwlist(struct userfs_sb_info *sbi, struct pwlist *ent) +{ +printk("remwlist\n"); + assert(ent != NULL); + if (ent == NULL) + return; + + if (ent->next) + { + assert(ent->next != ent); + ent->next->prev = ent->prev; + } + + if (ent->prev) + { + assert(ent->prev != ent); + ent->prev->next = ent->next; + } + else + { + assert(sbi->s_wlist == ent); + sbi->s_wlist = ent->next; + } + + ent->next = ent->prev = NULL; + + sbi->s_nwproc--; + + /* Assert some postconditions */ + assert(sbi->s_nwproc >= 0); + assert((sbi->s_wlist == NULL && sbi->s_nwproc == 0) || (sbi->s_wlist != NULL && sbi->s_nwproc >= 1)); + assert(sbi->s_wlist == NULL || (sbi->s_wlist->prev == NULL)); +} + +#ifdef DEBUG +k_static void dumplist(struct userfs_sb_info *sbi) +{ + struct pwlist *lp; + int i; +printk("dumplist\n"); + + for(lp = sbi->s_wlist, i = 0; lp != NULL; lp = lp->next, i++) + printk("%d: seq %d pid=%d why=%d more=%p repl.seq=%ld\n", + i, lp->seq, lp->pid, lp->why, lp->more, lp->repl.seq); + + assert(i == sbi->s_nwproc); +} +#endif + +/* + * Find waiting entry, given sequence number + */ +k_static struct pwlist *findwent(struct userfs_sb_info *sbi, int seq) +{ + struct pwlist *lp; +printk("findwent\n"); + + for(lp = sbi->s_wlist; lp != NULL; lp = lp->next) + if (lp->seq == seq) + return lp; + +#ifdef DEBUG + printk("findwent: seq=%d not found, %d things on list\n", + seq, sbi->s_nwproc); + dumplist(sbi); +#endif + return NULL; +} + +/* + * Kiss one process awake. Sets up the reason, the reply header + * and the reply body in the list entry and wakes it up. + */ +k_static struct pwlist *kissone(struct super_block *sb, int seq, int why, + upp_repl *repl, char *more) +{ + struct pwlist *lp; + struct userfs_sb_info *sbi = U_SBP(sb); + + if (seq == UP_WFIRST) + lp = sbi->s_wlist; + else + lp = findwent(sbi, seq); + + if (lp == NULL) + { + DB(printk("kissone: nothing done for seq=%d\n", + seq)); + return lp; + } + + lp->why = why; + + remwlist(sbi, lp); + + if (repl != NULL) + { + lp->more = more; + lp->repl = *repl; + } + else + { + assert(why != UP_REPL); + lp->repl.size = 0; + lp->repl.seq = -1; + lp->more = NULL; + } + + DB(printk("kissone: pid %d: kissing seq=%d, why=%d\n", + current->pid, seq, why)); + + assert(lp->pid == -1); + + lp->pid = current->pid; + wake_up(&lp->bed); + + return lp; +} + +/* + * Wake up one or all sleeping processes + * If seq == UP_WFIRST, then the first process is woken. Typically + * this would be why==UP_BATON, meaning that the process thus woken + * should take resposibility for reading the pipe + * If seq == UP_WALL then all processes are woken. It is not + * meaningful to have why anything but UP_FINISH. + * This shouldn't be called if a specific process needs awakening + */ +struct pwlist *userfs_kiss(struct super_block *sb, int seq, int why) +{ + struct userfs_sb_info *sbi; + struct pwlist *lp, *nxt; + + sbi = U_SBP(sb); + + if (seq == UP_WFIRST) + { + return kissone(sb, seq, why, NULL, NULL); + } + + assert(why == UP_FINISH); + assert(seq == UP_WALL); + + for(lp = sbi->s_wlist; lp != NULL; lp = nxt) + { + nxt = lp->next; + + kissone(sb, UP_WFIRST, why, NULL, NULL); + } + + assert(sbi->s_wlist == NULL); + assert(sbi->s_nwproc == 0); + + return NULL; +} + +/* + * Suck stuff from the process until we get what we want, + * then hand responsibilty over. + * + * This will either return when this process's reply comes, or + * on error. + */ +k_static int suckin(struct super_block *sb, struct pwlist *ent) +{ + upp_repl repl; + int replsz = sizeof_upp_repl(&repl); + char *more; + size_t more_sz; + struct userfs_sb_info *sbi = U_SBP(sb); + struct file *from = sbi->s_fromproc; + int ret; + unsigned char *p0, *p; + + p0 = (unsigned char *)get_free_page(GFP_KERNEL); + + ret = -1; /* general failure assumed */ + + assert(sbi->s_canread == 1); + + for(;;) + { + more = NULL; + more_sz = 0; + + if ((ret = userfs_recv(from, (char *)p0, replsz)) != replsz) + { + printk("suckin: %d: header recv failed: replsz=%d rcv=%d\n", + current->pid, replsz, ret); + if (ret==-ERESTARTSYS) + { + printk("suckin(header): needs to restart, trying to back-out\n"); + break; + } + userfs_close_chan(sb); + break; + } + + p = decode_upp_repl(&repl, p0); + + DB(printk("suckin: pid %d, seq %d got packet seq %ld, sz=%ld\n", + current->pid, ent->seq, repl.seq, repl.size)); + + assert(repl.size <= MAX_KMALLOC); + assert(repl.isreq == UP_REPL); + + if (repl.err_no == 0 && repl.size != 0) + { + more = (char *)kmalloc(repl.size, GFP_KERNEL); + more_sz = repl.size; + + if ((ret = userfs_recv(from, more, more_sz)) != repl.size) + { + printk("suckin: body recv failed: %d\n", ret); + if (ret==-ERESTARTSYS) + { + printk("suckin(body): needs to restart, trying to back-out\n"); + break; + } + userfs_close_chan(sb); + break; + } + } + + assert((repl.size == 0 && more == NULL) || (repl.size > 0 && more != NULL)); + + if (repl.seq == ent->seq) + { + /* For us! */ + + if (sbi->s_nwproc != 0) + userfs_kiss(sb, UP_WFIRST, UP_BATON); + else + sbi->s_canread = 0; + + ent->more = more; + ent->why = UP_REPL; + ent->repl = repl; + ret = 0; + more = NULL; + + DB(printk("suckin: sucker found its own (seq=%d), more=%p\n", + ent->seq, ent->more)); + break; + } + else + { + DB(printk("suckin: %d kissing seq %ld\n", + ent->seq, repl.seq)); + kissone(sb, repl.seq, UP_REPL, &repl, more); + } + } + + if (more != NULL) + kfree(more); /* , more_sz); */ + + free_page((unsigned long)p0); + + return ret; +} + +/* + * Wait for the reply to return, mostly sleeping. + * + * There are two cases: + * 1. We wait on the pipe for incoming packets. + * If a packet arrives that's not for us, then + * we wake up the process that is responsible + * for it. + * If its for us, then we accept it and pass + * responsibility on to another process to cope + * with the incoming. If there are no other + * waiting processes, then there should be + * no outstanding replies. + * 2. We wait on the list for something to happen. + * There are 3 reasons we can get woken: + * - Our reply arrvies. + * - We become resposible for reading + * - We unmount, and the reply is dropped + * If we get a reply or umount then remove ourselves + * from the list + * We return 0 on success, 1 if we were woken with UP_FINISHED + */ +k_static int userfs_sleep(struct super_block *sb, int seq, upp_repl *repl, + char **data) +{ + struct pwlist ent; + struct userfs_sb_info *sbi; + int ret = 0; + + sbi = U_SBP(sb); + + ent.seq = seq; + ent.more = NULL; + ent.why = 0; + ent.pid = -1; + ent.repl.size = 0; + ent.repl.seq = -1; + + if (sbi->s_canread == 0) + { + DB(printk("userfs_sleep: reading, pid=%d seq=%d\n", + current->pid, seq)); + + sbi->s_canread = 1; + + ret = suckin(sb, &ent); + + /* for restart, reset our state */ + if (ret==-ERESTARTSYS) + sbi->s_canread = 0; + } + else + { + addwlist(sbi, &ent); + + DB(printk("userfs_sleep: sleeping on list, pid=%d seq=%d\n", + current->pid, ent.seq)); + + ent.repl.seq = -1; + + sleep_on(&ent.bed); + DB(printk("userfs_sleep: pid %d, seq %d woken by pid %d\n", + current->pid, ent.seq, ent.pid)); + + assert(ent.pid != -1); + assert(ent.pid != current->pid); + + switch(ent.why) + { + case UP_BATON: /* We were woken to be reader */ + assert(sbi->s_canread == 1); + DB(printk("userfs_sleep: pid %d, seq %d taking on reader job\n", + current->pid, ent.seq)); + + ret = suckin(sb, &ent); + break; + + case UP_REPL: /* Our prince arrived */ + DB(printk("userfs_sleep: pid %d woken with %ld bytes in %p\n", + current->pid, ent.repl.size, ent.more)); + break; + + case UP_FINISH: /* We were sleeping and the connection failed */ + printk("userfs_sleep: got UP_FINISH from %d\n", + ent.pid); + ret = -EPROTO; + break; + + default: /* Bad reason for waking */ + printk("userfs_sleep: woke with bad why=%d from pid %d\n", + ent.why, ent.pid); + ret = -EPROTO; + break; + } + } + + if (ret != 0) + printk("userfs_sleep: failed with %d\n", ret); + else + { + *data = ent.more; + *repl = ent.repl; + } + + return ret; +} + +/* + * Deal with a normal send/reply transaction. + * + * This writes out the request in two parts. This locks the super + * block to prevent other operations from going out at the same + * time. After that we sleep until the reply comes in. + * Decode it and return. + */ +int __userfs_doop(struct super_block *sb, + up_preamble *pre, upp_repl *repl, + encode_func se, void *send, + decode_func rd, void *recv, + sizeof_func sso, sizeof_func rso) +{ + int ret; + unsigned char *p, *p0; + char *more = NULL; + struct file *to = U_SBP(sb)->s_toproc; + + p = p0 = (unsigned char *)get_free_page(GFP_KERNEL); + + assert(pre->version == UP_VERSION); + assert(pre->size <= MAX_KMALLOC); + assert(pre->isreq == UP_REQ || pre->isreq == UP_ENQ); + + pre->size = (*sso)(send); + assert(pre->size <= MAX_KMALLOC); + + /* Atomically send the packet */ + userfs_lock(sb); + p = encode_up_preamble(pre, p0); + if ((ret = userfs_send(to, (char *)p0, p-p0)) <= 0) + { + printk("userfs_doop: header send failed: %d\n", ret); + userfs_close_chan(sb); + free_page((long)p0); + userfs_unlock(sb); + return ret; + } + + if (pre->size > 0) + { + p = (*se)(send, p0); + if ((ret = userfs_send(to, (char *)p0, p-p0)) <= 0) + { + printk("userfs_doop: body send failed: %d\n", ret); + userfs_close_chan(sb); + free_page((long)p0); + userfs_unlock(sb); + return ret; + } + assert(p - p0 == pre->size); + } + + /* Sleep until a prince comes */ + if ((ret = userfs_sleep(sb, pre->seq, repl, &more)) == 0) + { + if (more != NULL) + { + (*rd)(recv, (unsigned char *)more); + assert(repl->size == (*rso)(recv)); + DB(printk("userfs_doop: more=%p\n", more)); + kfree(more); /*, repl->size); */ + } + } + else if (ret==-ERESTARTSYS) + printk("userfs_doop: userfs_sleep interrupted by signal in %d\n", current->pid); + else + printk("userfs_doop: userfs_sleep failed with %d\n", ret); + + userfs_unlock(sb); + + free_page((long)p0); + + return ret; +} Added: trunk/kernel/src/Makefile ============================================================================== --- trunk/kernel/src/Makefile 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/src/Makefile 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,46 @@ +# +# Makefile for the Linux userfs-filesystem routines. +# +# Edit DEFINES below depending on your kernel version +# + +TOP=../.. +include $(TOP)/rules + +CC=$(KERNCC) + +#define __SMP__ if you use smp... otherwise bad things will happen +#DEFINES= -DMODULE -DMODVERSIONS -DDEBUG +DEFINES= -DMODULE -DDEBUG +CFLAGS=-nostdinc -I/usr/lib/gcc-lib/i386-linux/2.95.4/include -I/usr/src/linux/include -I.. -O2 -fomit-frame-pointer $(DEFINES) -D__KERNEL__ -Wall +XCFLAGS= +INCL=../linux + +all:: userfs.o + +typedir: userfs_types.ty types + rm -f types/* + $(GENCODE) -sedl types userfs_types.ty + rm -f types/encode*_r.c types/decode*_s.c + cd types; for i in *.c ; do echo $$i: ; $(CC) -I.. $(CFLAGS) -c $$i; done + touch typedir + +OBJS= inode.o file.o super.o uio.o userfs_types.o module.o + +types: dummy + mkdir types + +userfs.o: $(OBJS) + $(LD) -r -o $@ $(OBJS) + +types.a: typedir + rm -f types.a + $(AR) r types.a types/*.o + ranlib types.a + +clean:: + rm -f core *.o *.a *.s *~ + rm -f types/* typedir types.a + +depend dep:: $(INCL)/userfs_types.h + $(CPP) $(CFLAGS) -M *.c > .depend Added: trunk/kernel/src/userfs.h ============================================================================== --- trunk/kernel/src/userfs.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/src/userfs.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,167 @@ +/* + * local defs of useful things + */ + +#ifndef __FS_USERFS_USERFS_H_SEEN__ +#define __FS_USERFS_USERFS_H_SEEN__ + +/* Versioning */ +#include +#define KVERS(maj,min,pat) ((maj)<<16|(min)<<8|(pat)) + +#if !defined(LINUX_VERSION_CODE) || (LINUX_VERSION_CODE < KVERS(2,2,0)) +#error "This version of Userfs is only supported on 2.2.6" +#endif /* LINUX_VERSION_CODE */ + +/* Module support */ +#ifndef MODULE +#error "This version of Userfs must be compiled as a module." +#endif /* MODULE */ + +/* #include */ +/* #include */ + +#ifdef MODVERSIONS +#include +#endif /* MODVERSIONS */ + +#if __cplusplus +#define __FUNCTION__ "__FUNCTION__:"__FILE__":(function/line unknown)" +#endif + +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +extern struct file_operations userfs_file_operations; +extern struct inode_operations userfs_inode_operations; +extern struct super_operations userfs_super_operations; + +#include + +struct super_block; +struct inode; + +extern void userfs_close_chan(struct super_block *); +extern void userfs_setcred(up_cred *); + +extern struct super_operations *userfs_probe_sops(struct super_block *); +extern struct inode_operations *userfs_probe_iops(struct super_block *); +extern struct file_operations *userfs_probe_fops(struct super_block *); + +extern int userfs_probe(struct super_block *, up_ops); +extern void userfs_set_inode(struct inode *, const up_inode *); +extern void userfs_read_inode(struct inode *); + +extern int do_userfs_read(struct inode *, up_credtok, off_t, char *, int, int); + +/* Access macros for union members */ + +/* +** Get a ptr to the userfs sb info struct from a ptr to a sb struct +** +** This assumes that union in the superblock is large enough to +** fit the userfs_fs_info structure. This is reasonable, because the +** union includes the proprietary information of many other fs's. +*/ +#define U_SBP(sb) ((struct userfs_sb_info *)&((sb)->u.generic_sbp)) + +/* +** Get a ptr to the userfs inode info struct from a ptr to an inode +** +** Comment similar to that for the superblock. +*/ +#define U_INOP(ino) ((struct userfs_inode_info *)&((ino)->u.generic_ip)) + +/* +** Get a ptr to the userfs file info struct from a ptr to a file. +** +** Aye ah. This one is different. You must malloc it first, because +** there isn't enough space in the struct to store all our info :-( +*/ +#define U_FILEP(file) ((struct userfs_file_info *)((file)->private_data)) + +/* +** old defined from when we used to malloc these things +** +** #define U_SB(sb) (*(struct userfs_sb_info *)(sb)->u.generic_sbp) +** #define U_INO(ino) (*(struct userfs_inode_info *)(ino)->u.generic_ip) +** #define U_SBP(sb) ((struct userfs_sb_info *)(sb)->u.generic_sbp) +** #define U_INOP(ino) ((struct userfs_inode_info *)(ino)->u.generic_ip) +** #define U_FILEP(file) ((struct userfs_file_info *)(file)->private_data) +** #define U_FILE(file) (*(struct userfs_file_info *)(file)->private_data) +*/ + +/* +** old defines from when we were in the kernel +** +** #define U_SB(sb) ((sb)->u.userfs_sb) +** #define U_INO(ino) ((ino)->u.userfs_i) +** #define U_FILE(file) ((file)->u.userfs_f) +*/ + +/* A kiss to end a sleep */ +extern struct pwlist *userfs_kiss(struct super_block *, int seq, int why); + +/* reasons why */ +#define UP_FINISH 1 /* Finish up - your prince will never come */ +#define UP_RECV 2 /* Your prince has arrived */ +#define UP_BATON 3 /* You take over */ + +/* for matching entries */ +#define UP_WFIRST (-1) /* wake first */ +#define UP_WALL (-2) /* wake all entries */ + +/* Element on list of sleeping processes */ +struct pwlist +{ + wait_queue_head_t bed; /* where we sleep */ + int why; /* filled on wake - why we woke */ + int seq; /* reply seqence */ + upp_repl repl; /* reply header */ + char *more; /* extra data */ + int pid; /* prince id */ + + struct pwlist *next; /* there are other beauties */ + struct pwlist *prev; +}; + +/* + * kmalloc is much less restricted than it used to be, but I'm still not + * allocating more than 4k, because there's little need. + */ +#define MAX_KMALLOC USERFS_MAX_XFER +#include + +/* Directory readahead things */ +void userfs_free_dirra(struct inode *ino); + +struct userfs_dir_ra +{ + int nent; /* Number of entries */ + struct userfs_dent *ents; /* Entries */ +}; + +struct userfs_dent +{ + off_t offset; /* Dir offset */ + off_t roff; /* Returned offset */ + ino_t inum; /* Inode number */ + char *name; /* Name, not \0 terminated */ + unsigned nlen; /* Name length */ +}; + +extern void userfs_lock_inode(struct inode *); +extern void userfs_unlock_inode(struct inode *); + +/* + * If we are debugging, bare all. If we generate an exception, + * we can lookup /proc/ksyms to see round about where things stuffed up. + */ +#ifdef DEBUG +#define k_static +#else +#define k_static static +#endif + +#endif /* __FS_USERFS_USERFS_H_SEEN__ */ + Added: trunk/kernel/types.h ============================================================================== --- trunk/kernel/types.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/types.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,130 @@ +#ifndef _LINUX_TYPES_H +#define _LINUX_TYPES_H + +#ifdef __KERNEL__ +#include +#endif + +#include +#include + +#ifndef __KERNEL_STRICT_NAMES + +typedef __kernel_fd_set fd_set; +typedef __kernel_dev_t dev_t; +typedef __kernel_ino_t ino_t; +typedef __kernel_mode_t mode_t; +typedef __kernel_nlink_t nlink_t; +typedef __kernel_off_t off_t; +typedef __kernel_pid_t pid_t; +typedef __kernel_daddr_t daddr_t; +typedef __kernel_key_t key_t; +typedef __kernel_suseconds_t suseconds_t; + +#ifdef __KERNEL__ +typedef __kernel_uid32_t uid_t; +typedef __kernel_gid32_t gid_t; +typedef __kernel_uid16_t uid16_t; +typedef __kernel_gid16_t gid16_t; + +#ifdef CONFIG_UID16 +/* This is defined by include/asm-{arch}/posix_types.h */ +typedef __kernel_old_uid_t old_uid_t; +typedef __kernel_old_gid_t old_gid_t; +#endif /* CONFIG_UID16 */ + +/* libc5 includes this file to define uid_t, thus uid_t can never change + * when it is included by non-kernel code + */ +#else +typedef __kernel_uid_t uid_t; +typedef __kernel_gid_t gid_t; +#endif /* __KERNEL__ */ + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +typedef __kernel_loff_t loff_t; +#endif + +/* + * The following typedefs are also protected by individual ifdefs for + * historical reasons: + */ +#ifndef _SIZE_T +#define _SIZE_T +typedef __kernel_size_t size_t; +#endif + +#ifndef _SSIZE_T +#define _SSIZE_T +typedef __kernel_ssize_t ssize_t; +#endif + +#ifndef _PTRDIFF_T +#define _PTRDIFF_T +typedef __kernel_ptrdiff_t ptrdiff_t; +#endif + +#ifndef _TIME_T +#define _TIME_T +typedef __kernel_time_t time_t; +#endif + +#ifndef _CLOCK_T +#define _CLOCK_T +typedef __kernel_clock_t clock_t; +#endif + +#ifndef _CADDR_T +#define _CADDR_T +typedef __kernel_caddr_t caddr_t; +#endif + +/* bsd */ +typedef unsigned char u_char; +typedef unsigned short u_short; +typedef unsigned int u_int; +typedef unsigned long u_long; + +/* sysv */ +typedef unsigned char unchar; +typedef unsigned short ushort; +typedef unsigned int uint; +typedef unsigned long ulong; + +#ifndef __BIT_TYPES_DEFINED__ +#define __BIT_TYPES_DEFINED__ + +typedef __u8 u_int8_t; +typedef __s8 int8_t; +typedef __u16 u_int16_t; +typedef __s16 int16_t; +typedef __u32 u_int32_t; +typedef __s32 int32_t; + +#endif /* !(__BIT_TYPES_DEFINED__) */ + +typedef __u8 uint8_t; +typedef __u16 uint16_t; +typedef __u32 uint32_t; + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +typedef __u64 uint64_t; +typedef __u64 u_int64_t; +typedef __s64 int64_t; +#endif + +#endif /* __KERNEL_STRICT_NAMES */ + +/* + * Below are truly Linux-specific types that should never collide with + * any application/library that wants linux/types.h. + */ + +struct ustat { + __kernel_daddr_t f_tfree; + __kernel_ino_t f_tinode; + char f_fname[6]; + char f_fpack[6]; +}; + +#endif /* _LINUX_TYPES_H */ Added: trunk/kernel/Makefile ============================================================================== --- trunk/kernel/Makefile 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/kernel/Makefile 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,7 @@ +# Userfs kernel top Makefile +TOP=.. +SUBDIRS=linux src +all:: subdirs + +include ../rules.sub +include ../rules Added: trunk/rules.sub ============================================================================== --- trunk/rules.sub 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/rules.sub 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,8 @@ +subdirs:: + set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done + +#dep depend:: +# set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i dep; done + +#clean:: +# set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i clean; done Added: trunk/genser/symtab.c ============================================================================== --- trunk/genser/symtab.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/genser/symtab.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,384 @@ +/* Symbol table handling */ + +#include "com.h" +#include "symtab.h" + +/* Global symbol/type table */ +Var *global; + +/* Table for dealing with structures */ +Var *structures; + +Var *lookup(Var *table, const char *sym) +{ + for(; table != NULL; table = table->next) + if (strcmp(sym, table->name) == 0) + return table; + + return NULL; +} + +Var *mkvar(Type *type, char *name) +{ + Var *var = (Var *)malloc(sizeof(*var)); + + var->name = name; + var->next = NULL; + var->prev = NULL; + var->type = type; + + return var; +} + +Var *add(Var *table, Var *var) +{ + assert(var != NULL); + + var->next = var->prev = NULL; + + if (table != NULL) + { + Var *tp = table; + + while(tp->next != NULL) + tp = tp->next; + + tp->next = var; + var->prev = tp; + } + else + table = var; + + return table; +} + +Var *addl(Var *table, Var *l) +{ + Var *n; + + assert(l != NULL); + + for(; l != NULL; l = n) + { + n = l->next; + table = add(table, l); + } + + return table; +} + +Var *preadd(Var *table, Var *var) +{ + var->next = table; + if (table) + table->prev = var; + + return var; +} + +int type_sizeof(const Type *ty) +{ + int sz = 0; + + switch(ty->tclass) + { + case Scalar: + switch(ty->i.scalar_i.size) + { + case NoType: sz = 0; break; + case Char: sz = 1; break; + case Short: sz = 2; break; + case Long: sz = 4; break; + case LongLong: sz = 8; break; + case Float: sz = 4; break; + case Double: sz = 8; break; + } + break; + + case Pointer: + sz = 4; /* XXX */ + break; + + case Void: + sz = 0; + break; + + case CArray: + sz = ty->i.carray_i.size * type_sizeof(ty->i.carray_i.type); + break; + + default: + sz = 0; /* XXX */ + break; + } + + return sz; +} + +Type *mktype(void) +{ + Type *tp = (Type *)malloc(sizeof(Type)); + + tp->tclass = NoType; + tp->anon = 1; + tp->nocode = 0; + tp->nohdr = 0; + tp->demand = 0; + tp->norep = 0; + tp->coded = 0; + tp->name = NULL; + + return tp; +} + +Var *mktypedef(Type *type, char *name) +{ + Type *td = mktype(); + Var *tv = mkvar(td, name); + + td->tclass = Typedef; + td->i.typedef_i.t = type; + td->i.typedef_i.n = name; + type->anon = 0; + + if (type->name == NULL) + type->name = td; + + td->anon = 0; + td->norep = type->norep; + + return tv; +} + +Type *mkstruct(Var *vars) +{ + Type *st = mktype(); + + st->tclass = Struct; + st->i.struct_i = vars; + + return st; +} + +Type *mkpointer(Type *type) +{ + Type *pt = mktype(); + + pt->tclass = Pointer; + pt->i.pointer_i = type; + + return pt; +} + +Type *mkvoid(void) +{ + Type *v = mktype(); + + v->tclass = Void; + return v; +} + +Type *mkarray(Type *type) +{ + Type *at = mktype(); + + at->tclass = Array; + at->i.array_i = type; + + return at; +} + +Type *mkcarray(Type *type, unsigned int size) +{ + Type *at = mktype(); + + at->tclass = CArray; + at->i.carray_i.type = type; + at->i.carray_i.size = size; + + return at; +} + +Type *mkscalar(enum sc_size sz, int sgn) +{ + Type *st = mktype(); + + st->tclass = Scalar; + st->i.scalar_i.size = sz; + st->i.scalar_i.Unsigned = sgn; + + return st; +} + +Type *realtype(Type *t) +{ + while(t && t->tclass == Typedef) + t = t->i.typedef_i.t; + + return t; +} + +Type *Ulonglong_type; +Type *Ulong_type; +Type *Ushort_type; +Type *Uchar_type; +Type *longlong_type; +Type *long_type; +Type *short_type; +Type *char_type; +Type *void_type; +Type *float_type; +Type *double_type; + +/* + * Carefully set up symbol table types. Most of the fiddling here + * is to cover the slight differences between our type system and + * C's + */ +void init_symtab(void) +{ + Var *v; + Type *t; + + global = NULL; + structures = NULL; + + t = char_type = mkscalar(Char, 0); + t->nocode = t->nohdr = 1; + t = Uchar_type = mkscalar(Char, 1); + t->nocode = 1; + + t = short_type = mkscalar(Short, 0); + t->nocode = t->nohdr = 1; + t = Ushort_type = mkscalar(Short, 1); + t->nocode = 1; + + t = long_type = mkscalar(Long, 0); + t->nocode = t->nohdr = 1; + t = Ulong_type = mkscalar(Long, 1); + t->nocode = 1; + + t = longlong_type = mkscalar(LongLong, 0); + t->nocode = t->nohdr = 1; + t = Ulonglong_type = mkscalar(LongLong, 1); + t->nocode = 1; + + t = float_type = mkscalar(Float, 0); + t->nocode = t->nohdr = 1; + t = double_type = mkscalar(Double, 1); + t->nocode = 1; + + t = void_type = mkvoid(); + t->nohdr = t->nocode = t->norep = 1; + + global = add(global, v = mktypedef(char_type, "char")); + v->type->nocode = v->type->nohdr = 1; + global = add(global, v = mktypedef(short_type, "short")); + v->type->nocode = v->type->nohdr = 1; + global = add(global, v = mktypedef(long_type, "long")); + v->type->nocode = v->type->nohdr = 1; + global = add(global, v = mktypedef(longlong_type, "longlong")); + v->type->nocode = v->type->nohdr = 1; + + global = add(global, v = mktypedef(float_type, "float")); + v->type->nocode = v->type->nohdr = 1; + global = add(global, v = mktypedef(double_type, "double")); + v->type->nocode = v->type->nohdr = 1; + + global = add(global, v = mktypedef(void_type, "void")); + v->type->nohdr = v->type->nocode = v->type->norep = 1; + + global = add(global, v = mktypedef(Uchar_type, "Uchar")); + v->type->nocode = v->type->nohdr = 1; + global = add(global, v = mktypedef(Ushort_type, "Ushort")); + v->type->nocode = v->type->nohdr = 1; + global = add(global, v = mktypedef(Ulong_type, "Ulong")); + v->type->nocode = v->type->nohdr = 1; + global = add(global, v = mktypedef(Ulonglong_type, "Ulonglong")); + v->type->nocode = v->type->nohdr = 1; + global = add(global, v=mktypedef(Ulong_type, "Uint")); + v->type->demand = v->type->nohdr = v->type->indir = 1; + + global = add(global, v=mktypedef(long_type, "int")); + v->type->demand = v->type->nohdr = v->type->indir = 1; +} + +extern char *prefix; + +static Var *name_type(Type *type, Var *var) +{ + Var *vp; + static int typecnt = 1; + + if (type->tclass != Typedef && type->anon == 1) + { + char buf[20]; + Var *nv; + + sprintf(buf, "_%s_%03d", prefix, typecnt++); + + nv = mktypedef(type, strdup(buf)); + type->anon = 1; + + var = preadd(var, nv); + } + + switch(type->tclass) + { + case Array: + var = name_type(type->i.array_i, var); + break; + + case CArray: + var = name_type(type->i.carray_i.type, var); + break; + + case Pointer: + var = name_type(type->i.pointer_i, var); + break; + + case Struct: + for(vp = type->i.struct_i; vp != NULL; vp = vp->next) + var = name_type(vp->type, var); + break; + + case Typedef: + var = name_type(type->i.typedef_i.t, var); + break; + + default: + break; + } + + return var; +} + +Var *name_types(Var *table) +{ + Var *vp, *sc; + Var *tab; + + for(tab = table; tab != NULL; tab = tab->next) + { + if (tab->type->nocode) + continue; + vp = name_type(tab->type, NULL); + + if (vp == NULL) + continue; + + for(sc = vp; sc->next != NULL; sc = sc->next) + ; + + vp->prev = tab->prev; + if (tab->prev) + tab->prev->next = vp; + else + table = vp; + + sc->next = tab; + tab->prev = sc; + } + + return table; +} Added: trunk/genser/misc.h ============================================================================== --- trunk/genser/misc.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/genser/misc.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,13 @@ +#ifndef _MISC_H_SEEN_ +#define _MISC_H_SEEN_ + +struct cmdarg +{ + char *str; + struct cmdarg *n; +}; + +struct cmdarg *add_cmdarg(struct cmdarg *, const char *str); +char *cat_args(struct cmdarg *); + +#endif /* _MISC_H_SEEN_ */ Added: trunk/genser/coder.h ============================================================================== --- trunk/genser/coder.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/genser/coder.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,283 @@ +/* Base type primitives */ + +#ifndef __CODER_H_SEEN__ +#define __CODER_H_SEEN__ + +#ifndef __GNUC__ +#define __inline__ /* */ +#endif + +#ifndef __cplusplus +#ifndef ALLOC +extern void *malloc(unsigned long); +extern void free(void *); +#define ALLOC(s) malloc(s) +#define FREE(s) free(s) +#endif /* ALLOC */ +#endif __cplusplus + +/* Types we use */ +typedef unsigned char Uchar; +typedef unsigned short Ushort; +typedef unsigned long Ulong; +typedef unsigned long Uint; +typedef unsigned long long Ulonglong; +typedef long long longlong; + +/** char **/ +__inline__ static unsigned char *encode_char(const char *ch, unsigned char *buf) +{ + *buf = *ch; + return buf+1; +} + +__inline__ static unsigned char *decode_char(char *ch, unsigned char *buf) +{ + *ch = *buf; + return buf+1; +} + +__inline__ static unsigned int sizeof_char(const char *c) +{ + (void)c; + return 1; +} + +/** unsigned char **/ +__inline__ static unsigned char *encode_Uchar(const Uchar *ch, unsigned char *buf) +{ + *buf = *ch; + return buf+1; +} + +__inline__ static unsigned char *decode_Uchar(Uchar *ch, unsigned char *buf) +{ + *ch = *buf; + return buf+1; +} + +__inline__ static unsigned int sizeof_Uchar(const Uchar *c) +{ + (void)c; + return 1; +} + +/** short **/ +__inline__ static unsigned char *encode_short(const short *sh, unsigned char *buf) +{ + register short sv = *sh; + + buf[0] = (sv >> 8)& 0xff; + buf[1] = sv & 0xff; + return buf+2; +} + +__inline__ static unsigned char *decode_short(short *sh, unsigned char *buf) +{ + *sh = (buf[0] << 8) | buf[1]; + return buf+2; +} + +__inline__ static unsigned int sizeof_short(const short *c) +{ + (void)c; + return 2; +} + +/** unsigned short **/ +__inline__ static unsigned char *encode_Ushort(const Ushort *sh, unsigned char *buf) +{ + register Ushort sv = *sh; + + buf[0] = (sv >> 8)& 0xff; + buf[1] = sv & 0xff; + return buf+2; +} + +__inline__ static unsigned char *decode_Ushort(Ushort *sh, unsigned char *buf) +{ + *sh = (buf[0] << 8) | buf[1]; + return buf+2; +} + +__inline__ static unsigned int sizeof_Ushort(const Ushort *c) +{ + (void)c; + return 2; +} + +/** long **/ +__inline__ static unsigned char *encode_long(const long *l, unsigned char *buf) +{ + register long lv = *l; + + buf[0] = (lv >> 24) & 0xff; + buf[1] = (lv >> 16) & 0xff; + buf[2] = (lv >> 8) & 0xff; + buf[3] = lv & 0xff; + return buf+4; +} + +__inline__ static unsigned char *decode_long(long *l, unsigned char *buf) +{ + *l = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + return buf+4; +} + +__inline__ static unsigned int sizeof_long(const long *c) +{ + (void)c; + return 4; +} + +/** unsigned long **/ +__inline__ static unsigned char *encode_Ulong(const Ulong *l, unsigned char *buf) +{ + register Ulong lv = *l; + + buf[0] = (lv >> 24) & 0xff; + buf[1] = (lv >> 16) & 0xff; + buf[2] = (lv >> 8) & 0xff; + buf[3] = lv & 0xff; + return buf+4; +} + +__inline__ static unsigned char *decode_Ulong(Ulong *l, unsigned char *buf) +{ + *l = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + return buf+4; +} + +__inline__ static unsigned int sizeof_Ulong(const Ulong *c) +{ + (void)c; + return 4; +} + +/** long long */ +__inline__ static unsigned char *encode_longlong(const long long *l, + unsigned char *buf) +{ + register long long lv = *l; + + buf[0] = (lv >> 56) & 0xff; + buf[1] = (lv >> 48) & 0xff; + buf[2] = (lv >> 40) & 0xff; + buf[3] = (lv >> 32) & 0xff; + buf[4] = (lv >> 24) & 0xff; + buf[5] = (lv >> 16) & 0xff; + buf[6] = (lv >> 8) & 0xff; + buf[7] = lv & 0xff; + + return buf+8; +} + +__inline__ static unsigned char *decode_longlong(long long *l, + unsigned char *buf) +{ +#define BUF(x) ((long long)(buf[x])) + *l = (BUF(0) << 56)|(BUF(1) << 48)|(BUF(2) << 40)|(BUF(3) << 32)| + (BUF(4) << 24)|(BUF(5) << 16)|(BUF(6) << 8)|BUF(7); +#undef BUF + return buf+8; +} + +__inline__ static unsigned int sizeof_longlong(const long long *c) +{ + (void)c; + return 8; +} + +/** unsigned long long */ +__inline__ static unsigned char *encode_Ulonglong(const unsigned long long *l, + unsigned char *buf) +{ + register unsigned long long lv = *l; + + buf[0] = (lv >> 56) & 0xff; + buf[1] = (lv >> 48) & 0xff; + buf[2] = (lv >> 40) & 0xff; + buf[3] = (lv >> 32) & 0xff; + buf[4] = (lv >> 24) & 0xff; + buf[5] = (lv >> 16) & 0xff; + buf[6] = (lv >> 8) & 0xff; + buf[7] = lv & 0xff; + + return buf+8; +} + +__inline__ static unsigned char *decode_Ulonglong(unsigned long long *l, + unsigned char *buf) +{ +#define BUF(x) ((unsigned long long)(buf[x])) + *l = (BUF(0) << 56)|(BUF(1) << 48)|(BUF(2) << 40)|(BUF(3) << 32)| + (BUF(4) << 24)|(BUF(5) << 16)|(BUF(6) << 8)|BUF(7); +#undef BUF + return buf+8; +} + +__inline__ static unsigned int sizeof_Ulonglong(const unsigned long long *c) +{ + (void)c; + return 8; +} + +/** void **/ +__inline__ static unsigned char *encode_void(const void *v, unsigned char *buf) +{ + (void)v; + return buf; +} + +__inline__ static unsigned char *decode_void(void *v, unsigned char *buf) +{ + (void)v; + return buf; +} + +__inline__ static unsigned int sizeof_void(const void *c) +{ + (void)c; + return 0; +} + +/* Assuming this host has IEEE 754 floats, this is all OK */ +/** float **/ +__inline__ static unsigned char *encode_float(const float *f, unsigned char *buf) +{ + *(float *)buf = *f; + return buf + sizeof(float); +} + +__inline__ static unsigned char *decode_float(float *f, unsigned char *buf) +{ + *f = *(float *)buf; + return buf + sizeof(float); +} + +__inline__ static unsigned int sizeof_float(const float *c) +{ + (void)c; + return sizeof(float); +} + +/** double **/ +__inline__ static unsigned char *encode_double(const double *d, unsigned char *buf) +{ + *(double *)buf = *d; + return buf + sizeof(double); +} + +__inline__ static unsigned char *decode_double(double *d, unsigned char *buf) +{ + *d = *(double *)buf; + return buf + sizeof(double); +} + +__inline__ static unsigned int sizeof_double(const double *c) +{ + (void)c; + return sizeof(double); +} + +#endif /* __CODER_H_SEEN__ */ Added: trunk/genser/parser.y ============================================================================== --- trunk/genser/parser.y 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/genser/parser.y 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,338 @@ +/* -*- fundamental -*- */ + +%{ +#include "com.h" +#include "symtab.h" + +#define YYERROR_VERBOSE + +static int nohdr = 0; + +static Type *set_type(Type *, Type *); +void yyerror(const char *, ...); +int yylex(void); +%} + +%union +{ + Var *var; + Type *type; + char *name; + int num; +} + +%token STRUCT TYPEDEF SIGNED UNSIGNED NOTHDR GENERATE VOID +%token STATIC CONST EXTERN ELLIPSIS VOLATILE SIZEOF +%token IDENT +%token TYPE +%token NUM +%token STRING + +%left '-' '+' +%left '*' '/' + +%type type struct qual_type unsigned signed +%type type_name varlist typedef c_ident c_id_list type_list +%type op_ident +%type const sizeof + +%% + +sfile : /* */ + | sfile actions + ; + +actions : nothdr + | header_thing + | generate + ; + +nothdr : NOTHDR '{' { nohdr++; } header_things { nohdr--; } '}' + ; + +type_list: STRING { $$ = mkvar(NULL, $1); } + | type_list ',' STRING { $$ = add($1, mkvar(NULL, $3)); } + ; + +/* Cause code to be generated for types */ +generate: GENERATE type_list ';' + { + Var *v = $2; + for(; v != NULL; v = v->next) + { + Var *tv = lookup(global, v->name); + if (tv) + tv->type->demand = 0; + else + yyerror("Type %s unknown", v->name); + } + } + ; + +/* things we're likely to find in a header file */ +header_thing: typedefs + | prototype + | vars + ; + +header_things: header_thing + | header_things header_thing + ; + +/* List of typedef statements */ +typedefs: typedef { if ($1 != NULL) global = addl(global, $1); } + | typedefs typedef + { + if ($2 != NULL) + global = addl(global, $2); + } + ; + +/* A single typedef */ +typedef : TYPEDEF type c_id_list ';' + { + Var *v, *l = NULL; + for(v = $3; v != NULL; v = v->next) + { + Var *td; + v->type = set_type(v->type, $2); + td = mktypedef(v->type, v->name); + td->type->nohdr = nohdr; + td->type->demand = nohdr; + l = add(l, td); + } + $$ = l; + } + | struct ';' { $$ = NULL; } + + + | TYPEDEF type '(' c_ident ')' '(' comma_proto_list ')' ';' + { + $$ = NULL; + } + ; + +/* A list of type-ident pairs */ +varlist: /* */ { $$ = NULL; } + | varlist type_name { $$ = $2 == NULL ? NULL : addl($1, $2); } + ; + +/* A type with a list of names */ +type_name: type c_id_list ';' + { + Var *v, *n, *l = NULL; + for(v = $2; v != NULL; v = n) { + n = v->next; + v->type = set_type(v->type, $1); + l = add(l, v); + } + $$ = l; + } + ; + +const : NUM { $$ = $1; } + | sizeof { $$ = $1; } + | const '+' const { $$ = $1 + $3; } + | const '-' const { $$ = $1 - $3; } + | const '*' const { $$ = $1 * $3; } + | const '/' const { $$ = $1 / $3; } + | '(' const ')' { $$ = $2; } + ; + +sizeof : SIZEOF '(' type ')' { $$ = type_sizeof($3); } + ; + +/* + * A comma-separated list of C idents + * The hacks in here are for things like "int foo, bar[10];" and + * "char goop, **poot;" + */ +c_ident : IDENT { $$ = mkvar(NULL, $1); } + | '*' c_ident { $$ = mkvar(mkpointer($2->type), $2->name); } + | c_ident '[' const ']' { $$ = mkvar(mkcarray($1->type, $3), $1->name); } + | c_ident '[' ']' { $$ = mkvar(mkarray($1->type), $1->name); } + ; + +c_id_list: c_ident { $$ = $1; } + | c_id_list ',' c_ident { $$ = add($1, $3); } + ; + +/* Optional ident for C struct syntax */ +op_ident: /* */ { $$ = NULL; } + | IDENT { $$ = $1; } + ; + +/* Cope with C structure syntax */ +struct : STRUCT op_ident '{' varlist '}' + { + $$ = mkstruct($4); + if ($2 != NULL) + { + Var *v = mkvar($$, $2); + structures = add(structures, v); + } + } + | STRUCT IDENT + { + Var *v = lookup(structures, $2); + + if (v != NULL) + $$ = v->type; + else + { + $$ = mkstruct(NULL); + $$->norep = 1; + } + } + ; + +/* Cruftyness to handle "long int" and "long double" */ +qual_type: TYPE TYPE + { + Type *t1 = realtype($1); + Type *t2 = realtype($2); + $$ = NULL; + + if (t1 != long_type && t1 != short_type) + { + yyerror("Can only qualify with \"long\" or \"short\""); + YYERROR; + } + else if (t2->tclass != Scalar) + { + yyerror("Can only qualify scalar types"); + YYERROR; + } + else + { + switch(t2->i.scalar_i.size) + { + case Float: + if (t1 == long_type) + { + $$ = double_type; + break; + } + case Long: + if (t1 == short_type) + { + $$ = short_type; + break; + } + if (t1 == long_type) + { + $$ = longlong_type; + break; + } + + default: $$ = $2; + } + } + } + ; + +/* Cope with "unsigned int" */ +unsigned: UNSIGNED TYPE { $$ = $2; } + | UNSIGNED qual_type { $$ = $2; } + | UNSIGNED { $$ = Ulong_type; } + ; + +signed : SIGNED TYPE { $$ = $2; } + | SIGNED qual_type { $$ = $2; } + | SIGNED { $$ = long_type; } + ; + +/* Main rule for all types */ +type : TYPE { $$ = $1; } + | qual_type + | signed { $$ = $1; } + | unsigned + { + Type *t, *rt; + + rt = realtype($1); + if (rt->tclass != Scalar) + { + yyerror("only scalars can be unsigned"); + YYERROR; + t = $1; + } + else + { + switch(rt->i.scalar_i.size) + { + case Char: t = Uchar_type; break; + case Short: t = Ushort_type; break; + case Long: t = Ulong_type; break; + case LongLong: t = Ulonglong_type; break; + default: + yyerror("only integral types can be unsigned"); + YYERROR; + break; + } + } + $$ = t; + } + | struct { $$ = $1; } + | VOID { $$ = NULL; } + ; + +/* Parse prototypes, without semantic action */ + +/* Storage class for functions. We're an accepting lot */ +sclass : /* */ + | sclass EXTERN + | sclass CONST + | sclass VOLATILE + | sclass STATIC + ; + +prototype: sclass type IDENT '(' comma_proto_list ')' ';' + ; + +/* Variables */ +vars : sclass type_name /* ';' -- type_name expects it */ + +/* Optional constant */ +opconst: /* */ + | CONST + ; + +/* A prototype argument */ +proto : opconst type + | opconst type IDENT + | ELLIPSIS + ; + +/* A list of parameters */ +comma_proto_list: /* */ + | proto + | comma_proto_list ',' proto + ; +%% + +static Type *set_type(Type *tt, Type *to) +{ + if (tt == NULL) + return to; + + switch(tt->tclass) + { + case Array: + tt->i.array_i = set_type(tt->i.array_i, to); + break; + + case CArray: + tt->i.carray_i.type = set_type(tt->i.carray_i.type, to); + break; + + case Pointer: + tt->i.pointer_i = set_type(tt->i.pointer_i, to); + break; + + default: + abort(); + } + + return tt; +} Added: trunk/genser/com.h ============================================================================== --- trunk/genser/com.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/genser/com.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,12 @@ +/* Common headers and defns */ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +#define EXTERNC extern "C" +#endif Added: trunk/genser/symtab.h ============================================================================== --- trunk/genser/symtab.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/genser/symtab.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,111 @@ +/* + * Symbol table structures + */ + +typedef struct var_t Var; +typedef struct type_t Type; + +enum typeclass +{ + Struct, + Typedef, + Scalar, + Array, + CArray, + Pointer, + Void +}; + +enum sc_size +{ + NoType = -1, + Char, + Short, + Long, + LongLong, + Float, + Double +}; + +struct type_t +{ + enum typeclass tclass; + union + { + Var *struct_i; + struct + { + Type *t; + char *n; + } typedef_i; + struct + { + enum sc_size size; + int Unsigned; + } scalar_i; + Type *array_i; + Type *pointer_i; + struct + { + Type *type; + unsigned size; + } carray_i; + } i; + Type *name; /* Pointer to nameing typedef */ + unsigned anon:1; /* Had no defined name */ + unsigned nocode:1; /* No code to be generated */ + unsigned nohdr:1; /* No header generated */ + unsigned demand:1; /* Generate code as needed */ + unsigned norep:1; /* No serial representation */ + unsigned indir:1; /* Use a level of indirection */ + unsigned coded:3; /* En/Decode func generated */ +}; + +struct var_t +{ + char *name; + Type *type; + Var *next; + Var *prev; +}; + +extern Var *global; /* Global symbol table */ +extern Var *structures; /* Global structure table */ + +void init_symtab(void); + +int type_sizeof(const Type *); + +Var *lookup(Var *, const char *); +Var *add(Var *, Var *); +Var *addl(Var *, Var *); +Var *preadd(Var *, Var *); + +Type *mktype(void); +Type *mkstruct(Var *); +Type *mkpointer(Type *); +Type *mkarray(Type *); +Type *mkcarray(Type *, unsigned int); +Type *mkscalar(enum sc_size, int); +Type *mkvoid(void); + +Var *mkvar(Type *, char *); +Var *mktypedef(Type *, char *); +Var *mkincl(const char *); + +Var *name_types(Var *); + +Type *realtype(Type *); + +/* Standard types */ +extern Type *Ulonglong_type; +extern Type *Ulong_type; +extern Type *Ushort_type; +extern Type *Uchar_type; +extern Type *longlong_type; +extern Type *long_type; +extern Type *short_type; +extern Type *char_type; +extern Type *void_type; +extern Type *float_type; +extern Type *double_type; Added: trunk/genser/gencode.c ============================================================================== --- trunk/genser/gencode.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/genser/gencode.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,591 @@ +#include +#include "com.h" +#include "symtab.h" +#include "format.h" +#include "misc.h" +#include + +extern int yyparse(); + +char *prefix = ""; + +int copythrough = 0; + +static int do_oneperfile = 0; +static int do_cplusplus = 0; +static const char *filedir = NULL; +static const char *srcext = ".c"; + +static void file_preamble(void) +{ + format("/* -*- %s -*-\n * DO NOT EDIT BY HAND!\n *\n", + do_cplusplus ? "C++" : "C"); + format(" * This was automatically generated by gencode.\n */\n"); + if (do_cplusplus) + { + format("#ifdef __cplusplus\n"); + format("#if __GNUC__ == 2\n"); + format("#pragma implementation \"%s\"\n", prefix); + format("#endif /* __GNUC__ */\n"); + format("#endif /* __cplusplus */\n"); + } + format("#include \"%s.h\"\n", prefix); +} + +static void preamble(Type *type, const char *op, int co, const char *name) +{ + if (do_oneperfile) + { + char buf[256]; + + sprintf(buf, "%s_%s%s", op, name, srcext); + + if ((form_out = fopen(buf, "w")) == NULL) + { + fprintf(stderr, "Failed to create %s: %s\n", + buf, strerror(errno)); + exit(1); + } + file_preamble(); + } + + format("\n"); +#if 0 + if (!do_oneperfile && (type->anon || type->demand)) + format("__inline__ static "); +#endif + format("\nunsigned char *%s_%s(%s%s *sp, unsigned char *buf)\n{\n", + op, name, co ? "const " : "", name); +} + +static void postamble() +{ + format("return buf;\n}\n"); + + if (do_oneperfile) + fclose(form_out); +} + +#define NAMEOF(t) ((t)->name->i.typedef_i.n) + +void encode_type(Type *type, const char *typename) +{ + Var *var; + + assert(type != NULL); + + if (type->nocode || type->coded == 1) + return; + + type->coded = 1; + + switch(type->tclass) + { + Type *tt; + +#define PRE() preamble(type, "encode", 1, typename) +#define POST() postamble() + + case Typedef: + tt = realtype(type); + encode_type(tt, NAMEOF(tt)); + PRE(); + format("buf = encode_%s(sp, buf);\n", NAMEOF(tt)); + POST(); + break; + + case Scalar: + PRE(); + format("buf = encode_%s(sp, buf);\n", NAMEOF(type)); + POST(); + break; + + case Array: + if (type->norep) + { + PRE(); + format("/* No representation */\n"); + POST(); + break; + } + tt = realtype(type->i.array_i); + + encode_type(tt, NAMEOF(tt)); + PRE(); + format("{\nunsigned i;\n\n"); + format("buf = encode_Ulong(&sp->nelem, buf);\n"); + format("for(i = 0; i < sp->nelem; i++) {\n"); + format("buf = encode_%s(&sp->elems[i], buf);\n", + NAMEOF(tt)); + format("}\n}\n"); + POST(); + break; + + case CArray: + tt = realtype(type->i.carray_i.type); + encode_type(tt, NAMEOF(tt)); + PRE(); + format("{\nunsigned i;\n\n"); + format("for(i = 0; i < %d; i++) {\n", type->i.carray_i.size); + format("buf = encode_%s(&(*sp)[i], buf);\n", + NAMEOF(tt)); + format("}\n}\n"); + POST(); + break; + + case Struct: + for(var = type->i.struct_i; var != NULL; var = var->next) + { + tt = realtype(var->type); + encode_type(tt, NAMEOF(tt)); + } + + PRE(); + for(var = type->i.struct_i; var != NULL; var = var->next) + { + if (var->type->norep) + { + format("/* Unrepresentable type */\n"); + continue; + } + + tt = realtype(var->type); + + format("buf = encode_%s(&sp->%s, buf);\n", + NAMEOF(tt), var->name); + } + POST(); + break; + + case Pointer: + tt = realtype(type->i.pointer_i); + encode_type(tt, NAMEOF(tt)); + PRE(); + format("buf = encode_%s(*sp, buf);\n", + NAMEOF(tt)); + POST(); + break; + + default: + printf("#error \"undealt-with type %d\"\n", type->tclass); + break; +#undef PRE +#undef POST + } +} + +void decode_type(Type *type, const char *typename) +{ + Var *var; + + assert(type != NULL); + + if (type->nocode || type->coded == 2) + return; + + type->coded = 2; + + switch(type->tclass) + { + Type *tt; + +#define PRE() preamble(type, "decode", 0, typename) +#define POST() postamble() + + case Typedef: + tt = realtype(type); + decode_type(tt, NAMEOF(tt)); + PRE(); + format("buf = decode_%s(sp, buf);\n", + NAMEOF(tt)); + POST(); + break; + + case Scalar: + PRE(); + format("buf = decode_%s(sp, buf);\n", NAMEOF(type)); + POST(); + break; + + case Array: + if (type->norep) + { + PRE(); + format("/* No representation */\n"); + POST(); + break; + } + + tt = realtype(type->i.array_i); + decode_type(tt, NAMEOF(tt)); + PRE(); + format("{\nunsigned i;\n"); + format("buf = decode_Ulong(&sp->nelem, buf);\n"); + format("if (sp->nelem == 0)\n"); + format("{\nsp->elems = 0;\nreturn buf;\n}\n"); + if (do_cplusplus) + { + format("#ifdef __cplusplus\n"); + format("sp->alloc(sp->nelem);\n"); + format("#else\n"); + } + format("sp->elems = (%s *)ALLOC(sizeof(%s) * sp->nelem);\n", + NAMEOF(tt), NAMEOF(tt)); + if (do_cplusplus) + format("#endif /* __cplusplus */\n"); + format("if (sp->elems == 0) {\nreturn buf;\n}\n"); + + format("for(i = 0; i < sp->nelem; i++) {\n"); + format("buf = decode_%s(&sp->elems[i], buf);\n", + NAMEOF(tt)); + format("}\n}\n"); + POST(); + break; + + case CArray: + tt = realtype(type->i.carray_i.type); + decode_type(tt, NAMEOF(tt)); + PRE(); + format("{\nunsigned i;\n\n"); + format("for(i = 0; i < %d; i++) {\n", type->i.carray_i.size); + format("buf = decode_%s(sp[i], buf);\n", + NAMEOF(tt)); + format("}\n}\n"); + POST(); + break; + + case Struct: + for(var = type->i.struct_i; var != NULL; var = var->next) + { + tt = realtype(var->type); + decode_type(tt, NAMEOF(tt)); + } + PRE(); + for(var = type->i.struct_i; var != NULL; var = var->next) + { + if (var->type->norep) + { + format("/* Unrepresentable type */\n"); + continue; + } + tt = realtype(var->type); + format("buf = decode_%s(&sp->%s, buf);\n", + NAMEOF(tt), var->name); + } + POST(); + break; + + case Pointer: + tt = realtype(type->i.pointer_i); + decode_type(tt, NAMEOF(tt)); + PRE(); + format("*sp = (%s *)ALLOC(sizeof(%s));\n", + NAMEOF(tt), NAMEOF(tt)); + format("if (*sp == NULL) {\nreturn buf;\n}\n"); + format("buf = decode_%s(*sp, buf);\n", + NAMEOF(tt)); + POST(); + break; + +#undef PRE +#undef POST + default: + printf("#error \"undealt-with type %d\"\n", type->tclass); + break; + } +} + +static void s_preamble(const Type *type, const char *name) +{ + if (do_oneperfile) + { + char buf[256]; + + sprintf(buf, "sizeof_%s%s", name, srcext); + + if ((form_out = fopen(buf, "w")) == NULL) + { + fprintf(stderr, "Failed to create %s: %s\n", + buf, strerror(errno)); + exit(1); + } + file_preamble(); + } +#if 0 + if (!do_oneperfile && (type->nocode || type->anon || type->demand)) + format("static __inline__ "); +#endif + format("unsigned int sizeof_%s(const %s *sp)\n{\n", name, name); + format("unsigned int sz=0;\n\n"); +} + +static void s_postamble(void) +{ + format("return sz;\n}\n"); + + if (do_oneperfile) + fclose(form_out); +} + +void sizeof_type(Type *type, const char *typename) +{ + Var *var; + + assert(type != NULL); + + if (type->nocode || type->coded == 3) + return; + + type->coded = 3; + + switch(type->tclass) + { + Type *tt; + +#define PRE() s_preamble(type, typename) +#define POST() s_postamble() + + case Typedef: + tt = realtype(type); + sizeof_type(tt, NAMEOF(tt)); + PRE(); + format("sz += sizeof_%s(sp);\n", + NAMEOF(tt)); + POST(); + break; + + case Scalar: + PRE(); + format("sz += sizeof(%s);\n", + NAMEOF(type)); + POST(); + break; + + case Array: + if (type->norep) + { + PRE(); + format("/* No representation */\n"); + POST(); + break; + } + tt = realtype(type->i.array_i); + + sizeof_type(tt, NAMEOF(tt)); + PRE(); + format("sz += sizeof_Ulong(&sp->nelem);\n"); + format("{\nunsigned i;\n"); + format("for(i = 0; i < sp->nelem; i++) {\n"); + format("sz += sizeof_%s(&sp->elems[i]);\n", NAMEOF(tt)); + format("}\n}\n"); + POST(); + break; + + case CArray: + tt = realtype(type->i.carray_i.type); + sizeof_type(tt, NAMEOF(tt)); + PRE(); + format("{\nunsigned i;\n"); + format("for(i = 0; i < %d; i++) {\n", + type->i.carray_i.size); + format("sz += sizeof_%s(sp[i]);\n}\n}\n", NAMEOF(tt)); + POST(); + break; + + case Struct: + for(var = type->i.struct_i; var != NULL; var = var->next) + { + tt = realtype(var->type); + sizeof_type(tt, NAMEOF(tt)); + } + + PRE(); + for(var = type->i.struct_i; var != NULL; var = var->next) + { + if (var->type->norep) + { + format("/* Unrepresentable type */\n"); + continue; + } + tt = realtype(var->type); + format("sz += sizeof_%s(&sp->%s);\n", + NAMEOF(tt), + var->name); + } + POST(); + break; + + case Pointer: + tt = realtype(type->i.pointer_i); + sizeof_type(tt, NAMEOF(tt)); + PRE(); + format("sz += sizeof_%s(*sp);\n", + NAMEOF(tt)); + POST(); + break; + + case Void: + PRE(); + POST(); + break; + + default: + printf("#error \"undealt-with type %d\"\n", type->tclass); + break; +#undef PRE + } +} + + +typedef void (*Genfunc)(Type *, const char *); + +static void gen_code(Var *table, Genfunc func) +{ + for(; table != NULL; table = table->next) + { + Type *type; + + type = table->type; + + assert(table->type->tclass == Typedef); + + if (type->demand) + continue; + + (*func)(type->i.typedef_i.t, type->i.typedef_i.n); + } +} + +extern FILE *yyin; +char *file; + +extern int yydebug; + +int +main(int argc, char *argv[]) +{ + char *cp; + int och, err = 0; + int do_encode = 0, do_decode = 0, do_sizeof = 0; + char buf[1024]; + struct cmdarg *cppargs = NULL; + + form_out = stdout; + cppargs = add_cmdarg(cppargs, CPP); + + while((och = getopt(argc, argv, "sedCD:I:U:l:E:Y")) != EOF) + { + switch(och) + { + case 'D': + case 'I': + case 'U': + sprintf(buf, "-%c%s", och, optarg); + cppargs = add_cmdarg(cppargs, buf); + break; + + case 'd': + do_decode = 1; + break; + + case 'e': + do_encode = 1; + break; + + case 's': + do_sizeof = 1; + break; + + case 'l': + filedir = optarg; + do_oneperfile = 1; + break; + + case 'E': + srcext = optarg; + break; + + case 'C': + do_cplusplus = 1; + srcext = ".cc"; + break; + + case 'Y': + yydebug = 1; + break; + + default: + err++; + break; + } + } + + if (err || optind >= argc) + { + fprintf(stderr, "Usage: %s [-des] [-l dir] [-E ext] [cpp-opts] types-file\n", + argv[0]); + fprintf(stderr, "\t-d\tGenerate decode functions\n"); + fprintf(stderr, "\t-e\tGenerate encode functions\n"); + fprintf(stderr, "\t-s\tGenerate sizeof functions\n"); + fprintf(stderr, "\t-l dir\tGenerate one function per file in directory `dir'\n"); + fprintf(stderr, "\t-E ext\tUse extention `ext' on files (-l only)\n"); + fprintf(stderr, "\tcpp-opts\tPass -I, -D and -U options to cpp\n"); + exit(1); + } + + if (!(do_encode || do_decode || do_sizeof)) + fprintf(stderr, "Warning: no functions will be generated\n"); + + file = strdup(argv[optind]); + + cppargs = add_cmdarg(cppargs, file); + + if ((yyin = popen(cat_args(cppargs), "r")) == NULL) + { + perror("file open failed"); + exit(1); + } + + if ((cp = strrchr(argv[optind], '/')) == NULL) + cp = argv[optind]; + else + cp++; + + prefix = strdup(cp); + cp = strrchr(prefix, '.'); + if (cp) + *cp = 0; + + init_symtab(); + + if (yyparse()) + { + fprintf(stderr, "Bad input file\n"); + exit(1); + + } + + global = name_types(global); + + if (!do_oneperfile) + file_preamble(); + else + { + if (chdir(filedir) == -1) + { + perror("Couldn't change to output directory"); + exit(1); + } + } + + if (do_encode) + gen_code(global, encode_type); + + if (do_decode) + gen_code(global, decode_type); + + if (do_sizeof) + gen_code(global, sizeof_type); + + exit(0); +} Added: trunk/genser/genhdr.c ============================================================================== --- trunk/genser/genhdr.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/genser/genhdr.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,270 @@ +#include "com.h" +#include "symtab.h" +#include "format.h" +#include "misc.h" +#include +#include + +extern int yyparse(); + +int copythrough = 1; + +static int do_cplusplus = 0; + +char *prefix; + +static inline Type *symb(Type *t) +{ + if (t->name != NULL) + return t->name; + assert(t->tclass == Typedef); + return t; +} + +void dumptype(Type *type, const char *name) +{ + char *str; + Var *var; + int ret = 1; + + assert(type != NULL); + + switch(type->tclass) + { + case Typedef: + format(type->i.typedef_i.n); + break; + + case Scalar: + if (type->i.scalar_i.Unsigned) + format("unsigned "); + switch(type->i.scalar_i.size) + { + case Char: str = "char"; break; + case Short: str = "short"; break; + case Long: str = "long"; break; + case LongLong: str = "long long"; break; + case Float: str = "float"; break; + case Double: str = "double"; break; + default: str = "???"; break; + } + + format(str); + break; + + case Array: + if (do_cplusplus) + { + static int scount = 1; + char n[128]; + + sprintf(n, "_%s_S%03d", prefix, scount++); + + format("struct %s {\n", n); + format("Ulong nelem;\n"); + dumptype(mkpointer(type->i.array_i), "elems"); + format(";\n"); + format("#ifdef __cplusplus\n"); + format("int alloced;\n"); + format("void %s::alloc(unsigned size)\t{elems = new ", n); + dumptype(symb(type->i.array_i),""); + format("[size]; alloced = 1; }\n"); + format("%s::%s()\t{ alloced = 0; }\n", n, n); + format("%s::~%s()\t{\n", n, n); + format("if (alloced) {\n"); + format("delete [] elems; alloced = 0;\n}\n}\n"); + format("#endif /* __cplusplus */\n}"); + } + else + { + format("struct\n{\n"); + format("Ulong nelem;\n"); + dumptype(mkpointer(type->i.array_i), "elems"); + format(";\n}"); + } + break; + + case CArray: + dumptype(symb(type->i.carray_i.type), name); + format("[%d]", type->i.carray_i.size); + ret = 0; + break; + + case Struct: + format("struct\n{\n"); + for(var = type->i.struct_i; var != NULL; var = var->next) + { + if (var->type->norep) + { + format("/* No representation */\n"); + continue; + } + dumptype(symb(var->type), var->name); + format(";\n"); + } + format("}"); + break; + + case Pointer: + dumptype(symb(type->i.pointer_i), NULL); + format("*"); + break; + + default: + printf("undealt-with type %d", type->tclass); + break; + } + if (name != NULL && ret) + format(" %s", name); +} + +void gen_hdr(Var *table) +{ + format("/* Encoded types */\n\n"); + for(; table != NULL; table = table->next) + { + Type *type = table->type; + + assert(type->tclass == Typedef); + + if (type->nohdr) + continue; + + format("typedef "); + dumptype(type->i.typedef_i.t, table->name); + format(";\n"); + } +} + +void gen_proto(Var *table) +{ + for(; table != NULL; table = table->next) + { + Type *type; + const char *name = table->name; + const char *st = table->type->nocode ? "static " : ""; + + assert(table->type->tclass == Typedef); + + type = table->type->i.typedef_i.t; + + format("%sunsigned char *encode_%s(const %s *, unsigned char *);\n", + st, name, name); + format("%sunsigned char *decode_%s(%s *, unsigned char *);\n", + st, name, name); + format("%sunsigned int sizeof_%s(const %s *);\n\n", + st, name, name); + + } +} + +extern FILE *yyin; +char *file; + +extern int yydebug; + +int +main(int argc, char *argv[]) +{ + char *upname, *cp; + int c, err = 0; + char buf[1024]; + struct cmdarg *cppargs = NULL; + + form_out = stdout; + cppargs = add_cmdarg(cppargs, CPP); + + while((c = getopt(argc, argv, "U:I:D:YC")) != EOF) + switch(c) + { + case 'D': + case 'I': + case 'U': + sprintf(buf, "-%c%s", c, optarg); + cppargs = add_cmdarg(cppargs, buf); + break; + + case 'Y': + yydebug = 1; + break; + + case 'C': + do_cplusplus = 1; + break; + + default: + err++; + break; + } + + if (err || optind >= argc) + { + fprintf(stderr, "Usage: %s [-C] [cpp-opts...] typedef-file\n", argv[0]); + fprintf(stderr, "\t-C\tGenerate C++ classes rather than C\n"); + fprintf(stderr, "\tcpp-opts\tPass -I, -D and -U options to cpp\n"); + exit(1); + } + + file = strdup(argv[optind]); + + cppargs = add_cmdarg(cppargs, file); + + if ((yyin = popen(cat_args(cppargs), "r")) == NULL) + { + perror("file open failed"); + exit(1); + } + + if ((cp = strrchr(file, '/')) == NULL) + cp = file; + else + cp++; + + prefix = strdup(cp); + cp = strrchr(prefix, '.'); + if (cp) + *cp = 0; + + init_symtab(); + + upname = cp = strdup(prefix); + + for(; *cp; cp++) + if (islower(*cp)) + *cp = toupper(*cp); + + format("/* -*- %s -*-\n * DO NOT EDIT BY HAND!\n *\n", + do_cplusplus ? "C++" : "C"); + format(" * This was automatically generated from \"%s\"", + argv[optind]); + format(" by genhdr.\n */\n"); + format("#ifndef __%s_H_SEEN__\n", upname); + format("#define __%s_H_SEEN__\n\n", upname); + + if (do_cplusplus) + { + format("#ifdef __cplusplus\n"); + format("#if __GNUC__ == 2\n"); + format("#pragma interface \"%s\"\n", prefix); + format("#endif /* __GNUC__ */\n"); + format("#endif /* __cplusplus */\n"); + } + if (yyparse()) + { + fprintf(stderr, "Bad input file\n"); + exit(1); + } + + format("#ifndef _NO_CODER_H_\n"); + format("/* Type encode/decode routines */\n"); + format("#include \"coder.h\"\t/* Standard routines */\n"); + format("#endif /* _NO_CODER_H_ */\n"); + global = name_types(global); + + gen_hdr(global); + gen_proto(global); + + format("#endif /* __%s_H_SEEN__ */\n", upname); + + exit(0); +} Added: trunk/genser/format.c ============================================================================== --- trunk/genser/format.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/genser/format.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,87 @@ +/* C output formatting */ +#include "com.h" +#include "format.h" +#include + +static int lvl; +static int lastnl = 0; +static int col; + +FILE *form_out; + +static void out_ch(char ch) +{ + if (ch == '\n') + { + fputc(ch, form_out); + col = 0; + lastnl = 1; + return; + } + + if (lastnl && ch != '#') + { + int cnt; + + col += lvl * 4; + for(cnt = 0; cnt < lvl; cnt++) + fputs(" ", form_out); + } + lastnl = 0; + + col++; + fputc(ch, form_out); + +#if 0 + if (col >= 65 && (ch == ';' || ch == ',')) + out_ch('\n'); +#endif +} + +static void out_str(const char *str) +{ + for(; *str; str++) + out_ch(*str); +} + +static void out_num(int n) +{ + char buf[20]; + + sprintf(buf, "%d", n); + out_str(buf); +} + +void format(const char *str, ...) +{ + va_list va; + + va_start(va, str); + + for(; *str; str++) + { + switch(*str) + { + case '(': + case '{': out_ch(*str); lvl++; break; + + case ')': + case '}': lvl--; out_ch(*str); break; + + case '%': + switch(*++str) + { + case 's': out_str(va_arg(va, char *)); break; + case 'd': out_num(va_arg(va, int)); break; + default: + out_ch('%'); + out_ch(*str); + break; + } + break; + + default: + out_ch(*str); + } + } +} Added: trunk/genser/lexer.l ============================================================================== --- trunk/genser/lexer.l 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/genser/lexer.l 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,99 @@ +/* -*- fundamental -*- */ +%{ +#include "com.h" +#include "symtab.h" +#include "y.tab.h" + +extern char *file; +extern int copythrough; +static int line = 1; +static char strbuf[1024]; +static char *strptr; +%} + +%x comment +%x string + +%% +struct return STRUCT; +typedef return TYPEDEF; +unsigned return UNSIGNED; +(__)?signed(__)? return SIGNED; +notypedef return NOTHDR; +generate return GENERATE; +sizeof return SIZEOF; + + /* Purely C keywords */ +static return STATIC; +void return VOID; +extern return EXTERN; +(__)?const return CONST; +(__)?volatile return VOLATILE; +"..." return ELLIPSIS; + +[_a-zA-Z][_a-zA-Z0-9]* { + Var *v = lookup(global, yytext); + if (v != NULL && v->type->tclass == Typedef) + { + Type *t = v->type; + if (t->indir == 1) + t = t->i.typedef_i.t; + + yylval.type = t; + return TYPE; + } + yylval.name = strdup(yytext); + return IDENT; + } +[0-9]+ { yylval.num = atoi(yytext); return NUM; } +[+-/{}[\]*;,()] return *yytext; +"/*" BEGIN(comment); +^#\ [0-9]+\ \"[a-zA-Z_.0-9/]+\".*$ { + char *cp; + + line = strtol(&yytext[2], &cp, 10); + free(file); + file = cp+2; + for(cp = file; *cp && *cp != '"'; cp++) + ; + *cp = 0; + file = strdup(file); + } +\" strptr = strbuf; BEGIN(string); +^#.*$ ; +[ \t] ; +\n line++; +^"%".* if (copythrough) { fputs(&yytext[1], stdout); fputc('\n', stdout); } +. fprintf(stderr, "Uncaught char '%c'\n", *yytext); + +[^*\n]+ /* eat up anything up to '*' */ +"*"+[^*/\n]* /* eat up rows of '*' not followed by '/' */ +\n line++; +"*"+"/" BEGIN(INITIAL); + +\\. *strptr++ = yytext[1]; +\" *strptr=0; yylval.name = strdup(strbuf); BEGIN(INITIAL); return STRING; +[^\\\"]+ {char *cp = yytext; while(*cp) *strptr++ = *cp++; } + +%% + +#include +#include + +void +yyerror(const char *msg, ...) +{ + va_list va; + + fprintf(stderr, "%s:%d:", file, line, msg); + + va_start(va, msg); + vfprintf(stderr, msg, va); + va_end(va); + fputc('\n', stderr); +} + +int yywrap(void) +{ + return 1; +} Added: trunk/genser/misc.c ============================================================================== --- trunk/genser/misc.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/genser/misc.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,45 @@ +/* + * Misc functions, for command execution and so on + */ +#include +#include +#include "misc.h" + +struct cmdarg *add_cmdarg(struct cmdarg *l, const char *str) +{ + struct cmdarg *lp, *new; + + new = malloc(sizeof(*new)); + new->n = NULL; + new->str = strdup(str); + + if (l == NULL) + return new; + + for(lp = l; lp->n != NULL; lp = lp->n) + ; + lp->n = new; + + return l; +} + +char *cat_args(struct cmdarg *l) +{ + int len; + struct cmdarg *lp; + char *str, *cp; + + for(len = 0, lp = l; lp != NULL; len += strlen(l->str)+1, lp = lp->n) + ; + + str = malloc(len); + + for(cp = str, lp = l; lp != NULL; lp = lp->n, *cp++ = ' ') + { + strcpy(cp, lp->str); + cp += strlen(lp->str); + } + + cp[-1] = 0; + return str; +} Added: trunk/genser/README ============================================================================== --- trunk/genser/README 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/genser/README 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,113 @@ +genser - generate serialising code + +This is a pair of programs which generate code to serialise and +deserialise data structures, given a description of them. I wrote +them for the protocol used by userfs, but they are quite general. One +program generates code for encoding, decoding and finding the size of +the encoded representation, and the other generates prototypes for +them, and emits the types in ansi C. + +GENHDR + +Usage: genhdr [-C] input.ty + +This emits all the datatypes and function prototypes in ansi C to +standard output. If -C is specified then array structures are +generated with destructors which free memory allocated by decoding. + +GENCODE + +Usage: gencode [-sedC] [-l dir] [-s suff] input.ty [> output.c] + +Gencode generates C code for the encode/decode/sizeof functions +(generated with the -e, -d, and -s options respectively). -l dir will +generate one function per file into directory "dir" for the generation +of archive libraries so that programs don't have to link everything +in. -s sets the suffix of the output files (.c by default). -C +generates code to work with the destuctors generated with genhdr -C, +and sets the suffix to .cc when used with -l. + +INPUT FILE FORMAT + +The input file is essentially C type definitions, with a few +exceptions. By default, code is generated for any type named with +typedef, and any anonymous type used in a typedef. + +Arrays are defined as follows: + + typedef int foo[]; + +This defines a type "foo", which is an unbounded array of ints (signed +32 bit words). This generates a structure of the form: + + struct { + int *elems; + long nelem; + }; + +which is a pointer to the base of the array, and the number of +elements. + +This, and the complete exclusion of functions from the type system, +are the main differences from pure C syntax. A number of parsing +hacks have been put in place so that C syntax can be parsed without +semantic content for genser. + +Structures may be named with the "struct foo {...};" syntax, but they +are ignored until they are used in a named type. + +Often you want to include a system include file for a couple of types, +but it defines dozens. Typedefs can be marked as "generate on demand" +(when used in other types) by enclosing them in a notypedef block: + +notypedef { +#include +} + +This will only generate code and definitions for the types in + if another type uses them. + +The input file is run through cpp ("/lib/cpp -Ulinux -C"). + +It is possible to quote parts of the input file directly into the +output file, by putting '%' at the beginning of the line. These lines +are completely uninterpreted and are copied through with the '%' +stripped off. The order in the output of these lines is maintained, +but the order in relation to genser output corresponding to input +surrounding the quoted lines is not specified, but generally they will +be before any generated output. Quoted lines are not copies through +by gencode, only genhdr, so they are only in the header lines. + +%/* Copy into output file */ +%#include + +When decoding arrays of variable size and pointers to objects, the +decode routine calls a function or macro void *ALLOC(size_t size) to +allocate memory. It expects this function will always return a valid +pointer to free memory. By default, it is defined as malloc(), but it +can be redefined in the quoted section to something appropriate to +local conditions. The memory allocated in the decode function must be +manually freed when you've finished. If one generates C++ code (-C +option to gen(code|hdr)) then destructors which call FREE() are +generated for arrays. They will only attempt to free memory if it was +allocated by a decode function. + +coder.h is a file that must always be included. It contains the +definitions of the encode/decode/sizeof functions for the base types +used by genser. It is normally included as "coder.h", but if one +defines _NO_CODER_H_ in the output file (with a quoted define), it +will not be automatically included. One can then include it in a more +appropriate way, or replace it altogether. + +There are no known actual *bugs*, but there are a few limitations and +desireable features. Most importantly, C++ support could be much +better. Each type could be a class with encode/decode/sizeof methods, +and memory can be allocated with new and delete if required. Also it +should have a better grasp of C so it will always be able to parse +Linux header files. + +Also, this readme file could be turned into a real man page or texinfo +page. + +Bug reports and comments to + Jeremy Fitzhardinge Added: trunk/genser/Makefile ============================================================================== --- trunk/genser/Makefile 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/genser/Makefile 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,51 @@ +# +# Makefile for genser +# +LEX=flex -s +YACC=bison -yvt +TOP=.. +include $(TOP)/rules + +CFLAGS = $(CPP) +CPP='-DCPP="/lib/cpp -Ulinux -C"' +LDFLAGS=-s +LIBS= #-lfl + +ALLSRC=gencode.c genhdr.c $(SRC) +ALLOBJ=$(ALLSRC:%.c=%.o) + +SRC=symtab.c lex.yy.c y.tab.c format.c misc.c +HDR=symtab.h y.tab.h +OBJ=$(SRC:%.c=%.o) + +.SUFFIXES: .ty + +.ty.c: gencode + gencode -dse $< > $@ + +.ty.h: genhdr + genhdr $< > $@ + +all:: genhdr gencode + +genhdr: genhdr.o $(OBJ) + $(CC) $(LDFLAGS) -o $@ genhdr.o $(OBJ) $(LIBS) + +gencode: gencode.o $(OBJ) + $(CC) $(LDFLAGS) -o $@ gencode.o $(OBJ) $(LIBS) + +lex.yy.c: lexer.l y.tab.h + $(LEX) $< + +lex.yy.o: lex.yy.c y.tab.h + $(CC) $(XCFLAGS) $(CFLAGS) -w -c $< + +y.tab.c y.tab.h: parser.y + $(YACC) -d $< + +dep depend:: $(ALLSRC) $(HDR) + $(CC) -M $(ALLSRC) > .depend + +clean:: + rm -f *.o lex.yy.c y.output y.tab.[ch] *~ genhdr gencode core + Added: trunk/genser/format.h ============================================================================== --- trunk/genser/format.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/genser/format.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,5 @@ +/* Output formatting routines */ + +void format(const char *, ...) __attribute((format (printf, 1, 2))); + +extern FILE *form_out; Added: trunk/Changelog ============================================================================== --- trunk/Changelog 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/Changelog 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,25 @@ +-------------------------------------------------------------------------- +userfs-0.9.7-pre3 + The listed example filesystems now compile well: + + arcfs + cvsfs + egfs + homer + tarfs + +-------------------------------------------------------------------------- +20 June 1999 Jan Jirmasek + + Merged the Mike's patch for 2.2.x kernels and my glibc patches + into the latest version of userfs-0.9.6. + Getting ready to compile genser part, kernel part, utils, c++ lib. + + +5 May 1999 Michael McCormack + + Userfs now compiles with the Linux 2.2.7 kernel + Added a couple of extra file systems. + Modified genser to parse and discard function typedefs. + Removed some compile warnings. + Added: trunk/rules ============================================================================== --- trunk/rules 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/rules 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,64 @@ +# Global rules and definitions +# This is included near the top of every Makefile (after TOP is set) + +CC=gcc +KERNCC=gcc # Do not define this as $(CC) +CPP=$(CC) +CXX=g++ + +# Debugging/optimisation +DEBUG=-O2 -m486 + +# profiling flags +PROF= + +# Warnings +WARN=-Wall -Wno-unused + +#Extra ld flags +XLDFLAGS= + +# Extra C and C++ flags +# Individual makefiles can change CFLAGS and CXXFLAGS, but +# global additions can be made here +XCFLAGS=$(PROF) $(DEBUG) $(WARN) +XCXXFLAGS=$(PROF) $(DEBUG) $(WARN) #-fno-for-scope + +.cc.o: + $(CXX) -c $(CXXFLAGS) $(XCXXFLAGS) $< + +.c.o: + $(CC) -c $(CFLAGS) $(XCFLAGS) $< + +.cc.s: + $(CXX) -S $(CXXFLAGS) $(XCXXFLAGS) $< + +.c.s: + $(CC) -S $(CFLAGS) $(XCFLAGS) $< + +all:: + +# Specific targets +DEPLIBUSERFS=$(TOP)/lib/libuserfs.a +LIBUSERFS=-L$(TOP)/lib -luserfs + +DEPLIBLWP=$(TOP)/lwp/liblwp.a +LIBLWP=-L$(TOP)/lwp -llwp + +GENDIR=$(TOP)/genser +GENHDR=$(GENDIR)/genhdr +GENCODE=$(GENDIR)/gencode + +$(GENHDR) $(GENCODE) $(DEPLIBUSERFS) $(DEPLIBLWP): dummy + $(MAKE) -C $(@D) $(@F) + + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif + +dummy: + Added: trunk/README.gnome-vfs ============================================================================== --- trunk/README.gnome-vfs 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/README.gnome-vfs 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,53 @@ +The additional work done here on top of userfs-0.9.7-pre3 is designed to allow +access to gnome-vfs URIs from non-Gnome projects. For the purposes of getting +gnome-vfs as a filesystem, here are the files we care about: + + kernel/src/userfs.o - build this (hopefully) by doing a make in kernel/ + filesystems/gvfs - cd here and do a "make gvfs" + utils/muserfs - do a "make muserfs" from utils/ + +You could do a make from the toplevel, but be prepared to get a boatload of +errors about the c++ class library. The "filesystems" were first written against +libg++ and I began to bring them forward before realizing that I could just +write the user-side module in C (by changing the arcfs module slightly). +Forget the c++ stuff for now. + +Once you have a working userfs.o, just "insmod userfs.o" as root. If it +bitches, you'll have to figure out what changed in the kernel from 2.4.3. + +If that worked, cd over to filesystems/gvfs, and try: + $ ../../utils/muserfs ./gvfs /mnt/0 ftp://user:pass@host/path +for an existing path /mnt/0 that you have full privileges on. + +If all goes well, you may now poke around on your ftp server. + +REQUIREMENTS: + * kernel 2.4.3 is known to work, 2.4.0-test2 is known NOT to work + * gnome-vfs requires the NIC patch (the no-gconf stuff) + * my /usr/include/linux and /usr/include/asm happened to be the 2.4.3 + include/linux and include/asm directories, so either change the makefile + or change your setup to match when building the kernel module + +NOTES: + * open up two terminals, start reading a big file in one, then start reading + the same file in the second. BARF! most likely a bug in kernel/src/uio.c + related to my /* commenting out the superblock locking.. */ or maybe not. + * it currently even works with webdav over a proxy, but the proxy string + is screwy. I think it needs to be HTTP_PROXY=host:port as opposed to + the usual HTTP_PROXY=http://host:port. ?? anyhoo, it has been tested + successfully against http://www.mydocsonline.com + * read, write, open, close, readdir, lookup, create are all implemented. + haven't done remove, move, and symlink ops yet, but they shouldn't be + hard. + * read specifically works around any gnome-vfs pseudo-seek stuff. this is + solely because the NIC project has no hard drive so I cannot afford to + use temp space. thusly, if you are going to do non-sequential reads, + your performance will _suck_, but hey, it works. + * writes can currently only be sequential. + * though it's weird, you can even mount a file (as opposed to a directory). + a phony parent directory will be created for it. though this is strange, + you may need this if, for example, you can access a file via ftp but have + no permissions to the directory which contains it. + +Have fun! +-kurt Added: trunk/utils/um.c ============================================================================== --- trunk/utils/um.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/utils/um.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,27 @@ +/* + * Force an unmount, ignoring everything + * + * This is useful for getting rid of runaway filesystems + * when muserfs gets confused and leaves the mtab in an + * inconsistent state. + */ + +#include +#include +#include +#include + +int +main(int argc, char *argv[]) +{ + if (argc == 2) + { + if (umount(argv[1]) == -1) + perror("umount"); + else + exit(0); + } + else + fprintf(stderr, "Usage: %s mount-point\n", argv[0]); + exit(1); +} Added: trunk/utils/muserfs.c ============================================================================== --- trunk/utils/muserfs.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/utils/muserfs.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,622 @@ +/* + * Simple mount interface for userfs. This does permissions checking + * and allows non-suid processes to be mounted. + * + * It checks the proposed mount dir, does the mount and starts up + * the filesystem program attached to the kernel with pipes to + * deal with the filesystem operations. The filesystem process + * runs as the invoking user. + * + * Muserfs expects the child to only ever exit properly when it + * gets an EOF from the kernel. Muserfs takes signals and umounts + * the filesystem when it gets normal termination signals. + * muserfs will also attempt to unmount the filesystem if the child + * exists unexpectedly. If this happens, muserfs will exit regardless + * of whether it was successful. + * + * The /etc/mtab file is also updated correctly, so that umount should + * be able to unmount the filesystem. + * + * The input and output fds are inhereted by the filesystem process + * and are passed on the command-line with the -i fd (kernel to process) + * and -o fd (process to kernel) options. + * + * Usage: muserfs [-a] program mount-point [args...] + * + * This program is distributed under the terms of the + * Free Software Foundation General Public Licence. + * Copyright Jeremy Fitzhardinge 1993 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define FILESYSTEM_NAME "userfs" + +#ifdef __GLIBC__ + +#undef WNOHANG /* due sys/wait.h -x- linux/fs.h conflict */ +#undef WUNTRACED + +#undef BLOCK_SIZE /* due sys/mount.h -x- linux/fs.h conflict */ +#undef MS_RDONLY +#undef MS_NOSUID +#undef MS_NODEV +#undef MS_NOEXEC +#undef MS_SYNCHRONOUS +#undef MS_REMOUNT +#undef MS_MANDLOCK +#undef S_WRITE +#undef S_APPEND +#undef S_IMMUTABLE +#undef MS_NOATIME +#undef MS_NODIRATIME +#undef MS_RMT_MASK +#undef MS_MGC_VAL +#undef BLKROSET +#undef BLKROGET +#undef BLKRRPART +#undef BLKGETSIZE +#undef BLKFLSBUF +#undef BLKRASET +#undef BLKRAGET + +#endif + +#include +#include +#include +#include +#include +#include + +#include "io.h" + +char *progname = NULL; + +const char *mount_point = NULL; + +int doumount(const char *); +int mounted = 0; + +void sighandler(int sig) +{ +fprintf(stderr, "%s: in sighandler\n", progname); + switch (sig) + { + case SIGINT: + case SIGTERM: + case SIGHUP: + case SIGQUIT: + case SIGCHLD: + fprintf(stderr, "%s: signal in (INT,TERM,HUP,QUIT,CHLD)\n", progname); + if (!mounted) + break; + + if (!doumount(mount_point)) + fprintf(stderr, "%s: failed to unmount \"%s\"\n", + progname, mount_point); + + default: + return; + } +} + +static void sysfatal(const char *str, ...) +{ + va_list va; + int er = errno; + + va_start(va, str); + fprintf(stderr, "%s: ", progname); + vfprintf(stderr, str, va); + fprintf(stderr, ": %s\n", strerror(er)); + va_end(va); + exit(1); +} + +static void syserror(const char *str, ...) +{ + va_list va; + int er = errno; + + va_start(va, str); + fprintf(stderr, "%s: ", progname); + vfprintf(stderr, str, va); + fprintf(stderr, ": %s\n", strerror(er)); + va_end(va); +} + +void *xmalloc(size_t s) +{ + void *m = malloc(s); + + if (m == NULL) + sysfatal("memory allocation failure"); + + return m; +} + +char *fullpath(const char *p) +{ + char path[MAXPATHLEN]; + int dl; + char *np; + + if (realpath(p, path) == NULL) + return strdup(p); + else + return strdup(path); +} + +char *makeopts(char **av, int narg, const char *name, int pid) +{ + int i, j, nblen; + char *op, *cp; + char nbuf[100]; + + sprintf(nbuf, "username=%s,user,pid=%d,exec,nodev,nosuid,", name, pid); + nblen = j = strlen(nbuf); + + for(i = 0; i < narg; i++) + j += strlen(av[i]) + 1; + + op = xmalloc(j + 1); + + strcpy(op, nbuf); + cp = &op[nblen]; + + for(i = 0; i < narg; i++) + { + strcpy(cp, av[i]); + cp += strlen(av[i]); + *cp++ = ','; + } + + cp[-1] = 0; + + return op; +} + +int doumount(const char *mpoint) +{ + int kid; + int wstat; + int i; + static volatile int interlock; + static const char *umounts[] = + { + "/sbin/umount", + "/etc/umount", + "/usr/sbin/umount", + "/bin/umount", + }; + + if (++interlock != 1) + return 0; + if (mpoint == NULL) + return 0; + + switch(kid = fork()) + { + case -1: + perror("umount fork failed"); + return 1; + case 0: + setuid(geteuid()); + for(i = 0; i < sizeof(umounts)/sizeof(*umount); i++) + execl(umounts[i], "umount", mpoint, NULL); + sysfatal("exec of \"umount %s\" failed", mpoint); + exit(1); + } + + if (wait4(kid, &wstat, 0, NULL) == -1) + sysfatal("Wait for umount failed"); + + interlock--; + + if (WEXITSTATUS(wstat) != 0) + return 0; + mounted = 0; + return 1; +} + +static int prot_seq = 0; + +void genhdr(up_preamble *pre, up_ops op) +{ + pre->version = UP_VERSION; + pre->op = op; + pre->isreq = UP_REQ; + pre->seq = prot_seq++; + pre->size = 0; +} + +typedef unsigned char *(*encode_func)(const void *, unsigned char *); +typedef unsigned char *(*decode_func)(void *, unsigned char *); +typedef unsigned int (*sizeof_func)(const void *); + +#define GEN_ENC(var) (encode_func)(var) +#define GEN_DEC(var) (decode_func)(var) +#define GEN_SIZ(var) (sizeof_func)(var) + +void userfs_genpkt(struct super_block *, up_preamble *, up_ops); + +/* Encode and send request, receive and decode reply */ +#define doop(from, to, pre, repl, st, ss, rt, rs)\ + _userfs_doop(from, to, pre, repl, \ + GEN_ENC(encode_##st), (void *)ss, \ + GEN_DEC(decode_##rt), (void *)rs, \ + GEN_SIZ(sizeof_##st), GEN_SIZ(sizeof_##rt)) + +int _userfs_doop(int from, int to, + up_preamble *pre, upp_repl *repl, + encode_func se, void *send, + decode_func rd, void *recv, + sizeof_func sso, sizeof_func rso) +{ + int ret; + unsigned char *p, *p0; + int replsz = sizeof_upp_repl(repl); + + pre->size = (*sso)(send); + + p = p0 = xmalloc(USERFS_MAX_XFER); + + p = encode_up_preamble(pre, p0); + if ((ret = fullwrite(to, p0, p-p0)) != p-p0) + { + free(p0); + return -1; + } + + if (pre->size > 0) + { + p = (*se)(send, p0); + if ((ret = fullwrite(to, p0, p-p0)) != p-p0) + { + free(p0); + return -1; + } + } + + if (fullread(from, p0, replsz) != replsz) + { + free(p0); + return -1; + } + + decode_upp_repl(repl, p0); + + if (repl->size != 0) + { + if (fullread(from, p0, repl->size) != repl->size) + { + free(p0); + return -1; + } + (*rd)(recv, p0); + } + free(p0); + + return 0; +} + +/* + * Get mount flags from the filesystem + */ +int getflags(int in, int out) +{ + return 0; +} + +/* + * Check filesystem process is there and functioning by asking if + * it supports the upp_mount operation. If it doesn't or fails to + * respond then the mount is aborted. + */ +int checkfs(int in, int out) +{ + up_preamble pre; + upp_repl repl; + int sz; + + genhdr(&pre, userfs_up_mount); + pre.isreq = UP_ENQ; + + if (doop(in, out, &pre, &repl, void, NULL, void, NULL) != 0) + return 0; + + if (repl.version != UP_VERSION || repl.op != userfs_up_mount || + repl.seq != 0 || repl.isreq != UP_REPL || + repl.size != 0 || repl.err_no != 0) + return 0; + + return 1; +} + +int domount(int infd, int outfd, const char *mpoint, char *prog, + char **args, int nargs, int kid, int flags) +{ + struct userfs_mount mnt; + struct mntent ment; + FILE *mtab; + struct passwd *pwd; + char *mdev; + int fd,r; + + if ((pwd = getpwuid(getuid())) == NULL) + sysfatal("can't get password file entry for uid %d", + getuid()); + + mnt.tokern = infd; + mnt.fromkern = outfd; + mnt.version = USERFS_VERSION; + mnt.magic = USERFS_SUPER_MAGIC; + mnt.seq = prot_seq; + + r = mount(NULL, mpoint, FILESYSTEM_NAME, + MS_MGC_VAL|MS_NODEV|MS_NOSUID|flags, &mnt); + + if (r == -1) + { + syserror("mount of %s on %s failed", + prog, mpoint); + if(0>close(infd)) + fprintf(stderr,"close infd returned err\n"); + if(0>close(outfd)) + fprintf(stderr,"close outfd returned err\n"); + return 1; + } + + close(infd); + close(outfd); + + mdev = xmalloc(strlen(prog) + 7); + sprintf(mdev, "%s-%d", prog, kid); + + ment.mnt_fsname = mdev; + ment.mnt_dir = fullpath(mpoint); + ment.mnt_type = FILESYSTEM_NAME; + ment.mnt_opts = makeopts(args, nargs, pwd->pw_name, kid); + ment.mnt_freq = 0; + ment.mnt_passno= 0; + + mount_point = ment.mnt_dir; + + if ((fd = open(MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1) + { + syserror("Can't get "MOUNTED"~ lock file"); + return 1; + } + close(fd); + + if ((mtab = setmntent(MOUNTED, "a+")) == NULL) + { + syserror("Can't open " MOUNTED); + return 1; + } + + if (addmntent(mtab, &ment) == 1) + { + syserror("Can't write mount entry"); + return 1; + } + if (fchmod(fileno(mtab), 0644) == -1) + { + syserror("Can't set perms on "MOUNTED); + return 1; + } + endmntent(mtab); + + if (unlink(MOUNTED"~") == -1) + { + syserror("Can't remove "MOUNTED"~"); + return 1; + } + free(mdev); + mounted = 1; + return 0; +} + +int mountok(struct stat *st) +{ + if (!S_ISDIR(st->st_mode)) + { + errno = ENOTDIR; + return -1; + } + + if (getuid() != 0 && + (getuid() != st->st_uid || + (st->st_mode & S_IRWXU) != S_IRWXU) + ) + { + errno = EPERM; + return -1; + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + struct stat st; + int kid, i, ch; + int p1[2], p2[2]; + char **args; + char b1[10], b2[10]; + int async = 0; + int ret = 0; + int euid, egid, gid; + + progname = argv[0]; + euid = geteuid(); + egid = getegid(); + gid = getgid(); +#if 0 + if (euid != 0 || egid != gid) + { + fprintf(stderr, "%s: must be installed suid root: euid=%d egid=%d gid=%d\n", + progname, + euid, egid, gid); + exit(1); + } +#endif + + for(i = 0; (ch = getopt(argc, argv, "a")) != EOF;) + switch(ch) + { + case 'a': + async = 1; + break; + default: + i++; + } + + argc -= optind; + argv = &argv[optind]; + + if (i != 0 || argc < 2) + { + fprintf(stderr, + "Usage: %s [-a] program mount-point [args...]\n", + progname); + exit(1); + } + + if (async && getuid() != 0) + { + fprintf(stderr, "%s: async (-a) ignored: you can't unmount if you arn't root\n", + progname); + async = 0; + } + + if (stat(argv[1], &st) < 0) + sysfatal("Stat of %s failed", argv[1]); + + if (mountok(&st) < 0) + sysfatal("can't mount on %s", argv[1]); + + if (pipe(p1) < 0 || pipe(p2) < 0) + sysfatal("can't create pipe"); + + for(i = 1; i < NSIG; i++) + { + struct sigaction sa; + sigset_t ss; + + sigemptyset(&ss); + + sa.sa_handler = sighandler; + sa.sa_flags = SA_NOMASK|SA_RESTART; + sa.sa_mask = ss; + + if (i != SIGKILL && i != SIGSTOP) + sigaction(i, &sa, NULL); + } + signal(SIGCHLD, SIG_DFL); + + switch(kid = fork()) + { + case -1: /* fail */ + sysfatal("fork failed"); + + case 0: /* child */ + break; + + default: /* parent */ + close(p1[1]); + close(p2[0]); + + mounted = 0; + + if (checkfs(p1[0], p2[1])) + { + int flags = getflags(p1[0], p2[1]); + + ret = domount(p1[0], p2[1], argv[1], argv[0], + &argv[2], argc-2, kid, flags); + } + else + fprintf(stderr, + "%s: filesystem failed to respond correctly.\n", + progname); + + while (!async) + { + int wstat; + + if (wait4(kid, &wstat, 0, NULL) < 0) + fprintf(stderr, "%s: wait for pid %d failed: %s\n", + progname, kid, strerror(errno)); + else + if (!WIFEXITED(wstat)) + continue; + + if (mounted && !doumount(mount_point) != 0) + fprintf(stderr, "%s: Failed to umount filesystem\n", + progname); + break; + } + exit(ret); + } + + /* child */ + close(p1[0]); + close(p2[1]); + + if (setreuid(-1, getuid()) < 0) + sysfatal("Can't drop suid permissions"); + + { + static int isigs[] = { SIGKILL, SIGTERM, SIGINT }; + for(i = 0; i < sizeof(isigs)/sizeof(*isigs); i++) + { + struct sigaction sa; + sigset_t ss; + + sigemptyset(&ss); + + sa.sa_handler = SIG_IGN; + sa.sa_flags = SA_NOMASK|SA_RESTART; + sa.sa_mask = ss; + + sigaction(isigs[i], &sa, NULL); + } + } + args = (char **)xmalloc(sizeof(char *)* (argc + 3)); + + sprintf(b1, "-i%d", p2[0]); + sprintf(b2, "-o%d", p1[1]); + + args[0] = argv[0]; + args[1] = b1; + args[2] = b2; + args[3] = "-m"; + args[4] = fullpath(argv[1]); + + for(i = 0; i <= argc-3; i++) + args[i+5] = argv[i+2]; + args[i+5] = NULL; + + execvp(args[0], args); + + sysfatal("exec of %s failed", args[0]); + exit(1); +} Added: trunk/utils/opnames.h ============================================================================== --- trunk/utils/opnames.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/utils/opnames.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,27 @@ + +const char *opnames[] = +{ + "up_create", + "up_lookup", + "up_close", + "up_read", + "up_write", + "up_truncate", + "up_fsync", + "up_readdir", + "up_link", + "up_unlink", + "up_symlink", + "up_readlink", + "up_followlink", + "up_mount", + "up_umount", + "up_iread", + "up_iwrite", + "up_statfs", + "up_iput", + "up_open", + "up_permission", + "up_rename", +}; + Added: trunk/utils/io.c ============================================================================== --- trunk/utils/io.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/utils/io.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,81 @@ +/* + * Simple IO functions + * + * These are just like read() and write(), except they will try + * to process all the requested data, unless there's an error or + * EOF. They also cope with EINTR. + * + * Copyright (C) 1995 Jeremy Fitzhardinge + * + * 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. + */ + +#include +#include +#include +#include + +#include "io.h" + +size_t +fullread(int from, unsigned char *buf, size_t sz) +{ + size_t rd = 0; + size_t ret; + + while(sz > 0) + { + ret = read(from, buf, sz); + + if (ret == (size_t)-1) + { + if (errno == EINTR) + continue; + + return -1; + } + + if (ret == 0) + break; + + sz -= ret; + buf += ret; + rd += ret; + } + + return rd; +} + +size_t +fullwrite(int tofd, const unsigned char *buf, size_t sz) +{ + size_t wr = 0; + size_t ret; + + while(sz > 0) + { + ret = write(tofd, buf, sz); + + if (ret == (size_t)-1) + { + if (errno == EINTR) + continue; + return -1; + } + + if (ret == 0) + { + fprintf(stderr, "fullwrite wrote 0 bytes\n"); + break; + } + + sz -= ret; + buf += ret; + wr += ret; + } + + return wr; +} Added: trunk/utils/userfs_types.c ============================================================================== --- trunk/utils/userfs_types.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/utils/userfs_types.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1 @@ +#include Added: trunk/utils/io.h ============================================================================== --- trunk/utils/io.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/utils/io.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,23 @@ +/* -*- C -*- */ + +#ifndef _LIB_IO_H_ +#define _LIB_IO_H_ + +/* + * Simple IO functions + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +size_t fullread(int fd, unsigned char *, size_t); +size_t fullwrite(int fd, const unsigned char *, size_t); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIB_IO_H_ */ Added: trunk/utils/Makefile ============================================================================== --- trunk/utils/Makefile 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/utils/Makefile 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,33 @@ +# Client toplevel makefile + +TOP=.. +FLAGS=-I$(TOP)/kernel -I$(TOP)/lib -I$(TOP)/genser #-DDEBUG -S +CXXFLAGS = $(FLAGS) +CFLAGS = $(FLAGS) -g + +#include $(TOP)/rules + +LDFLAGS = $(PROF) + +MUSERFSOBJ = muserfs.o userfs_types.o io.o + +PROGS=muserfs um + +all: $(PROGS) + +install: muserfs + install -m 4755 -o root -g root -sc muserfs /usr/local/bin + +muserfs: $(MUSERFSOBJ) #$(DEPLIBUSERFS) + $(CC) $(LDFLAGS) -o $@ $(MUSERFSOBJ) $(LIBUSERFS) + +muserfs.cat: muserfs.1 + groff -Tascii -man $< > $@ || rm -f $@ + +clean: + rm -f *.o *~ core $(PROGS) + +dep depend: + $(CXX) $(CXXFLAGS) -M *.c > .depend + +include $(TOP)/rules.sub Added: trunk/br/br.c ============================================================================== --- trunk/br/br.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/br/br.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,9 @@ +#include + +_syscall0(void,unbreak) +_syscall0(void,doabreak) + +int main() +{ + unbreak(); +} Added: trunk/README.mm ============================================================================== --- trunk/README.mm 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/README.mm 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,910 @@ +.\" mm, I guess +.ds d "\&\s-1\f(CW +.ds p "\&\s+1\fP +.de CC +.DS I +.ft CW +.S -1 +.nr == \w'~~~~~~~~'u +.ta \\n(==u +\\n(==u +\\n(==u +\\n(==u +\\n(==u +\\n(==u +\\n(==u +\\n(==u +\\n(==u +\\n(==u +.. +.de EE +.ft P +.S +1 +.DE \\$1 +.. +.nr Hb 10 +.nr Hs 10 +.TL +\fB Userfs\fP \- Filesystems Implemented as User Processes +.AU "Jeremy Fitzhardinge +.AF "Softway Pty. Ltd." +.MT 4 +.H 1 "Introduction" +Userfs is a mechanism by which normal user processes can +be a Linux filesystem. +There are many uses for this, including: +.BL +.LI "Prototype filesystems" +.P +Prototype new block allocation algorithms in a user process and +debug with gdb +before going into the compile-crash-reboot cycle of kernel +development. +.LI "Infrequent use filesystems" +.P +You want to mount "FooBaz 0X" filesystems under Linux, but +you don't want it that often, and you don't need it to be +maximum speed. Rather than trying to get the kernel itself +to understand, or write specialised tools, write a filesystem +program. +.LI "Add capabilities to existing filesystems" +.P +Want compression, encryption, ACLs? Have a process to mirror +an existing file tree, but with your own extentions and semantics. +.LI "Completely virtual filesystems and new interfaces" +.P +Add a filesystem-type interface to an existing mechanism, or +a filesystem interface as a new way of representing data. +Sick of FTP? How about +.CC +$ mkdir /ftp/tsx-11.mit.edu +$ cd /ftp/tsx-11.mit.edu/pub/linux +$ cp README $HOME +.EE +Or mail? +.CC +$ cd /mail +$ ls +001.sbg@socs.uts.edu.au +002.Leroy +003.tlukka@vinkku.hut.fi +004.Davor_Jadrijevic +$ cat */From +From: sbg@socs.uts.edu.au +From: leroy@socs.uts.edu.au (Leroy) +From: tlukka@vinkku.hut.fi +From: davor%emard.uucp@ds5000.irb.hr (Davor Jadrijevic) +$ cat */Subject +Subject: More things +Subject: (none) +Subject: That userfs thing +Subject: mailfs again +$ +.EE +.LE +You get the idea. +.H 1 "Installation" +.H 2 "Kernel" +First of all, if you have installed userfs before, +remove traces of previous versions of userfs: make sure +there are no userfs header files in +.I "linux/include/linux" +and no userfs patches to any of the kernel source. +.P +Otherwise, the kernel module should just compile with the rest of +the build process. Userfs is currently supported for 2.0.x +(tested up to 2.0.0), and for 1.3.x. +It should work out the kernel version you're compiling for and configure itself +appropriately. +There are no kernel patches and +compiling userfs into the kernel is not supported. +.P +To install the module you need the +.B modutils +package, which should be available from your local +Linux ftp archive. It should be clear from its +documentation what you need to do with +.I "userfs.o" +to get it into the kernel. If you get some warnings about multiply +defined symbols, ignore them: only undefined symbols are a problem. +You can compile the kernel and module with either ELF or a.out compilers; +I used ELF. +.P +The kernel module supports modverions, so it generally won't be necessary +to recompile it for every kernel version; +.I insmod +will let you know if you need to recompile the userfs module (with luck - otherwise +Linux will helpfully let you know with obscure behaviour or kernel panics...). +.H 2 "Non-kernel Code" +.P +Building the rest of the code should be a matter of typing "make" at +the top userfs directory. This will generate dependencies and build +the utilities needed (genser), the library, the clients using the +library and the kernel module. There will be some warnings; ignore them. +.P +I used gcc 2.7.0; you probably need to use the latest compiler and +libraries (libg++ 2.7.0.1) for the C++ (though I've avoided templates +and exceptions; g++ has enough problems with simple things). +.H 2 "Mailing list" +The old USERFS channel on the Linux Activists list server is now +defunct. +There is a new list: +\f(CWlinux-userfs@vger.rutgers.edu\fP. +To subscribe, send mail to \f(CWmajordomo@vger.rutgers.edu\fP +with the contents +.CC +subscribe linux-userfs [your email address] +.EE +.H 2 "Bugs, comments, etc" +When you find a bug, tell me. Please send me the code you're using, +the kernel version, whatever changes you've made to userfs kernel +code, and instructions or a script to reproduce the bug. Don't just +tell me "it broke." +.P +If you've made changes to the kernel code, please send it to me rather +than sending it out to the world. Please send me comments, ideas for +new kernel features, or things that you think would make good +filesystems but you can't do right now. Also feel free to ask +questions about either the implementation of my code, how to write +your own userfs clients, or even just to tell me you got it working. +.P +Send mail to either me (Jeremy Fitzhardinge ) or to +the mailing list (see above). +.H 1 "Using clients" +Clients are generally mounted with the +.B muserfs +command. It's quite simple \- it's a program which makes sure the +mount point is legal for the user to mount on, and mounts the given +process with the user's permissions. Note that any user can mount a +process, so more checking is done on the mount point than for a normal +mount. Unless the user is root, the mount point must be owned by the +user and writable. +.B muserfs +has a man page, which is even up to date. +.P +There are a few useful or semi-useful clients: +.B homer ", " ftpfs ", " mailfs " and " arcfs. +.BL +.LI Homer +is written in C++, and uses the C++ library in the lib directory to do +most of its work. All it does is set up a single directory under its +mount point which contains symbolic links named after each user name +in the password file, which points to the associated home directory. +Mounted on /u it makes a passible replacement for ~ expansion in a +shell (but it works for any program). +.LI Ftpfs +is an experimental filesystem which allows readonly access to FTP +sites, maintaining a long-term disk cache. Its intended primarily for +anonymous FTP, but can also be used for authenticated FTP sessions. +.LI Mailfs +is by Davor Jadrijevic. It is for reading mail. Currently its +read-only and does not track mailbox changes, and is no longer being +actively developed. Pester Davor (or fix it yourself). +.LI Arcfs +was written by David Gymer. It allows you to mount +a compressed tar file as a read-only filesystem, and inspect +it with normal tools. It's pretty neat, but not recommended for +heavy "production" use, or for very large files. +.H 1 "Theory of operation" +The kernel module registers a new filesystem type with the +kernel ("userfs"). The filesystem itself is very simple; all it does +it takes the normal kernel filesystem requests, wraps them up into +well-defined packets and squirts them down a file descriptor +(presumeably connected to a process) and waits for the reply on +another file descriptor. +.P +If the filesystem process is on the same machine, then the file +descriptors are probably ordinary pipes. However, userfs just reads +and writes on the file descriptors, so they could be anything; files, +sockets, devices \- userfs doesn't care. +.P +The following is not a comprehensive tutorial on writing filesystems, +or a detailed "how it works" or specification of the existing code. +It is intended to give some idea of what I was thinking, and basic +concepts to bear in mind while poking about in my kernel or user code. +.H 2 "Priorities" +I had a number of goals which I wanted satisfied by this thing (from +most to least important): +.BL +.LI Flexibility +.P +I want the process to have as much power as a kernel-resident +filesystem as possible. I wanted to keep the interfaces as generic +and flexible. This has been mostly achieved. +.LI Robustness +.P +Since I see prototyping and development a major use for userfs, it +seems important to make sure that the kernel code can't (at worst) +crash or lock up if the user code fails. As it stands, it should be +impossible for a user process to crash the kernel, but it is possible +for a bad user process to lock up processes trying to use the +filesystem. +.P +It is also possible for a process to go strange while it is being +mounted, leaving a half-mounted filesystem. The mountpoint becomes a +nulled out inode, but the kernel refuses to unmount it (because it +isn't mounted), and refuses to mount on it (because it's busy). +This happens much less often than it used to, because muserfs does a +simple check to see if the filesystem process is at all viable. +.LI "Availability to users and Security" +.P +I'd like any user to be able to write a filesystem process. +Traditionally, filesystems are things that embody the security of +Unix, and are therefore very much superuser-only things. However, +there are only a couple of really sensitive features that shouldn't be +able to be controlled by any user: suid executables and device nodes. +Since a trusted superuser process is still required to call the mount +system call, and that process can set the no-suid and no-device flags, +the filesystem code can't use these as security holes. I can't think +of anything else that needs special care from a security point of +view. However, since the filesystem is completely under the control +of the process, one can make no assumptions about its contents. For +example "." and ".." may not do expected things, symlinks may point to +places other than what readlink returns. This makes navigating such +filesystems a new and interesting experience. +.LI "Efficiency" +.P +Efficiency is my lowest priority, but it is still important. +Unfortunately the other requirements (as usual) make things less +efficient. The most significant inefficiency is the context switches +between the kernel and the process. I think the most benefits can be +gained by reducing the number of these. There are several approaches +to this: +.BL +.LI +If the process wants a default behaviour for an operation, then +it can be done in the kernel. The best example of this is +permission checking - if the process wants normal unix permission +checking then it doesn't need to do it itself. Otherwise it can take +all the permission requests from the kernel, and implement other +permission policies. This is currently implemented. When the +filesystem is first mounted, the kernel asks the process what requests +it will accept. From that point the kernel will do sensible default +actions for requests that the process doesn't want to handle rather +than sending them down the connection. +.LI +Group requests commonly issued together into one. This is hard, since +the main kernel tells the filesystem code very little about what it is +doing, so it is hard to know what to do next. However, there are a +couple of single kernel requests that are implemented in the protocol +as two or more transactions. This could be fixed in future. +.LI +Data can be cached in the kernel. This is the most tricky, since +kernel caching or read-ahead limits the amount of control the process +can have over the data once read. I think this could be optionally +implemented, depending on whether the process says it is OK to do +caching, and if so what kinds. +.P +Currently directory readahead is implemented with the +.B upp_multireaddir +operation. This allows the filesystem process to return as many +directory entries as it likes, which are then saved in a readahead +buffer. If there's a future request which can be satisfied by this +buffer it is, rather than sending another message to the filesystem. +In 1.3.x kernels, userfs can transfer the whole lot to the process +reading the directory in one syscall (assuming the process has enough +space allocated for it). +This is a win if there +are lots of linear directory searches (such as shell globbing, ls or +pwd). +.LI +A larger than 4k maximum packet size can be used, now that the kernel +memory allocator allows larger than 4k memory allocations. However, +since pipes are the most common connection beween filesystems and +kernels, and pipes can hold at most 4k of data, there would still be a +context switch between filesystem code and kernel every 4k, so there +wouldn't be much gain. +.LE +.P +A number of people have suggested adding shared memory between the +kernel and the filesystem process. This would be quite limiting and +least likely option to improve things. At the moment, the filesystem +makes no assumptions about the nature of the file descriptors for +talking to the process. To implement shared memory between the kernel +and the process would require some way of finding the process on the +other end of the file descriptors (if any), and playing around with +memory maps. This still wouldn't cut down on the number of context +switches at all (it may even increase the number of switches because +of syncronisation). +.LE +.H 2 "Protocol" +The protocol used is machine independent, using network +byte order and defined type sizes. The code to do the +packetisation and depacketisation is generated automatically +by a program, given the description of each packet. +This is not fully portable, but it avoids byte order and +structure alignment problems. +.P +A packet to or from the kernel has two parts. The first is a header +that contains a sequence number, an operation type, a packet type, +size of the following data, and a protocol version number. The packet +type can either be a request, a reply or an enquiry. Requests and +enquiries are always from the kernel to the process, and the process +only ever sends replies to the kernel. A reply's header has one extra +field - an error field, containing an error number. Replies always +have the same sequence number as their corresponding request or +enquiry. If there was an error performing the operation the error +field is set to the error number and there is no additional data +returned. If there is no error the error field is set to 0. +.P +Following a request or reply packet is the optional operation-specific +data. This is passed through the protocol for interpretation by the +operation routines at each end. +.P +The kernel may have multiple outstanding requests. In other words, +the kernel may send a new request before receiving a reply to a +previous one. This allows the filesystem to block one process for a +slow operation while other processes can use the filesystem for +shorter operations. This improves performance on, for example, an ftp +filesystem, where one process may be using a fast local link, and +another may be using a slow international one, and each has to wait +for its own requests to be satisfied. Of course this requires the +filesystem process to be written with some form of multi-threading. +If the filesystem just reads requests, acts on them and replies then it +can do so and ignore any kernel requests until it is ready to deal +with them. +.H 2 "Handles" +The base element of a filesystem is an +.I inode . +There is an exact one to one relationship between inodes and files +(where a +.I file +in this case can be any filesystem object, like a normal file, a +directory and so on). The kernel needs to be able to uniquely +identify inodes. Inodes are uniquely numbered within a +filesystem, but each mounted filesystem has its own numbering. +Therefore an inode is completely identified by an inode number and a +filesystem identifier (or +.I device , +though it doesn't mean much for a filesystem which has no +physical hardware associated with it). +.P +A device is what distinguishes mounted filesystems from one another, +and an inode is what distinguishes files within a filesystem from each +other. Inode numbers are generated by each filesystem, and are used +by the kernel to refer to specific files to the filesystem specific +code. User process filesystems are no exception: between the kernel +and the filesystem process, files are refered to by using +.I handles , +which are essentially 32 bit unsigned numbers. When a filesystem first +mentions a file to the kernel, it gives it a handle, which the kernel +uses for all later operations on the file. It the the handle which +identifies the file, rather than the name, so it is important to use +distinct handles for distinct files, and never change the handle of a +file once it has been given to the kernel. +.H 2 "Random operation specific advice and blurb" +This may eventually accurately describe the whole protocol, but for +now its a list of interesting points and things that have bitten me. +.P +Normally when writing a filesystem you should use the library +.I libuserfs +(see below), and use the advice in this section as a guide on what +kind of things should be put in your userfs operation functions, +or for idle curiosity. +.H 3 "Mounting" +The mount is initiated by a user process calling the mount system +call, with the "userfs" filesystem type. In the filesystem specific +data, the process passes two file descriptor numbers for the kernel to +read and write to. These can by any kind of file descriptor at all. +Most commonly they would be pipes or sockets, but there is no +restriction. All the kernel requires that the one it talks to the +process with is writable, and the one it gets replies from is +readable. +.P +The most important request is mounting. Most important, because it is +one of the two requests that the process has to implement (of course, +not implementing anything else would be completely useless). The request +itself is not that complex. All it does is return a handle of the inode +at the root of the filesystem. Most commonly, this will be a directory. +Userfs does not enforce this, but the kernel itself may. +.P +After the process returns the root handle, the kernel will probe the +process to see what operations it is willing to support. This is done +by sending a series of enquire packets to the process. The process +should reply with normal reply packets, with the errno field either +set to 0 if it is supported or ENOSYS if it isn't. No real operation +should be done, and no additional information should be sent in the +reply. If the process replies ENOSYS to an operation, it will never +recieve it again, and the kernel will use a sensible default for it +(typically what the kernel would normally do for an in-kernel +filesystem if it doesn't support the operation). Conversely, if the +filesystem process doesn't get an enquiry about a particular operation +from the kernel, it will never see that operation from the kernel. +The filesystem process should send 0 for the operations it explicitly +supports, and ENOSYS for everything else, so the protocol can be +extended without having to modify existing clients. + +.H 3 "Reading Inodes" +The most common thing for a filesystem to be asked to do is to read +inodes. For the process, this involves filling out a structure much +like the kernel's inode structure and the stat structure. It's +important is to make sure the nlinks field is non-zero. This +field is the number of names the inode has, that is, the number of +directory entries in the filesystem which refer to this inode. In +theory, this can never be 0 when the kernel asks for the inode, +because that means that the kernel asked for the inode without ever +seeing a name referring to it, implying that the filesystem never told +the kernel about the file. If it is 0 then the kernel will never +"put" the inode, and it will make the filesystem un-umountable. +.P +When the kernel wants an inode from the filesystem, it uses the +.B upp_iread +protocol request to fetch it. This happens if something in the kernel +asks for the inode, but it isn't already in the kernel inode table. +Therefore, once the kernel has asked the filesystem for an inode, it +will not ask for it again while anything in the kernel is using it. +.P +Once nothing in the kernel is using the inode, the kernel will +issue an +.B upp_iput +operation, which may be preceded by an +.B upp_iwrite +if the inode was modified in use. A filesystem need not implement +these operations if there is no need to do so. +.H 3 "Open and Close" +Reading and putting inodes are the basic operations: regardless of +what an inode is being used for it will be read and put. The +.B upp_open " and " upp_close +operations specifically correspond to the +.BR open (2) +and +.BR close (2) +system calls. Normally a filesystem doesn't need to perform any +special handling for these operations, and would not normally +implement them, except if it wants to know the identity of the process +doing the operations. When a program issues an open system call for a +file on the user filesystem, the kernel will send a +.I upp_open +operation for the file, which includes complete identifcation for the +process which issued the open. When the filesystem replies it returns +a +.I "credentials token." +From then on, that credentials token is sent to the filesystem in all +operations which correspond to a system call which takes a file +descriptor as an argument, such as +.B read , write , readdir , lseek +and so on. +.P +This may seem a bit complex: why not just send the uid of the process +with the operations? Well, the credentials of a process are quite +complex, since they include the real, saved and effective uids and +gids of the process, and all the auxillary groups. Sending this with +each request would be quite an overhead. The idea is that all the +info is sent on a open, and the filesystem process can associate it +with a token internally, and only use the token in correspondance with +the kernel. +.P +Also note that the credentials are associated with an open file +descriptor, not the process performing the operation. Mostly a +process will deal with file descriptors it has created itself, but its +quite possible that it can inherit file descriptors from another +process with a different set of credentials. In this case the +filesystem knows the original process's credentials, but not for the +process which is performing the operation. +.H 3 "Handle Management" +The handle of an inode is only way the kernel and the filesystem can +talk about a file. An inode may have more than one name, or no names +at all, so file names are not a good way of keeping track of a file. +Use inodes in your filesystem code to keep track of files, even if you +have a simple 1:1 name to file mapping. +.P +Handles must also be consistent. Of course you must always keep the +handles of files currently in use consistent, but you must also keep +them consistent between uses. If a process opens a file once, closes +it and then reopens it, then it will expect it to have the same inode +number if it is supposed to be the same file (which is how processes +using a user filesystem will see the file handles). +.P +Also, if you ever refer to a handle in communication with the kernel, +you must be prepared for the kernel to ask about it. For example, if +the kernel reads a directory with the +.B upp_readdir " or " upp_multireaddir +operations, each entry in the reply will have a name and a handle. +Each of those handles must be the handle of the file if the kernel +looks at the file more closely. If you make them all the same, for +example, then a program would be entitled to believe that all the +names in the directory refer to one actual file. +.H 3 "Dealing with muserfs" +Writing a client which can be handled by muserfs is very easy. The +important thing to remember is that the filesystem process can +basically ignore muserfs, and ignore issues like how to quit and so +on. +.P +A userfs filesystem process should only terminate under one condition: +it gets an EOF (a read of 0 bytes) from the kernel on the file +descriptor its reading operation requests from. Muserfs will execute +it so that most signals are ignored, so it can handle them itself. +When the muserfs process is sent a SIGINT or SIGTERM it unmounts the +filesystem mount point with the +.BR umount (8) +command (used so that /etc/mtab is updated properly). This causes the +kernel to send the filesystem process a +.B upp_umount +operation. The kernel will close its end of the file descriptors, and +the process is expected to do the same, even if only by exiting. +Therefore, when trying to unmount a userfs filesystem, do not kill the +filesystem process directly, and do not kill muserfs with SIGKILL. +Either way you should be able to unmount with +.B umount +as root. +.H 1 "Using libuserfs" +.I libuserfs +is a C++ library designed to make writing filesystem clients easier. +It is designed so all the work common to almost all filesystems is +encapsulated into a few generic classes, which can be used as base +classes for specific filesystem functions. +.H 2 "Basic Classes" +The most basic classes, +.B Comm ", " Filesystem " and " Inode +implement the basic communication with the kernel and stub methods for +each operation. +.P +The Comm class reads from the kernel and decodes the headers of the +operation packets, and passes the remainder to the Filesystem class. +The Filesystem performs the operation and returns an unencoded return +header and the encoded body of the reply, if any. All this is not +exposed to the code using the library. +.P +Filesystem takes each operation and dispatches it to the appropriate +place. The Filesystem class directly handles the operations which are +global to the whole filesystem, such as mounting or unmounting. +For operation which pertain to a particular Inode (such as reading, +or looking up a name in a directory), Filesystem looks +up the Inode in its table and dispatches the operation to it. +.P +The Inode class has all its methods implemented as stubs which fail +with the "not implemented" error code. It also has members for the +standard inode properties of mode, type, size, ownership, links, +timestamps and so on. +.P +These classes are completely useless on their own, so they must be +used as base classes for other classes with actually do something. +.I libuserfs +has more specific, but still generally useful classes. +.P +.B SimpleInode +implements a simple inode with some normally expected behaviour. +It has a constructor which initializes the inode properties to +sensible values, and methods which implement simple defaults for +the open, close and permissions check operations. +.P +.B DirInode, +derived from SimpleInode, implements all the operations needed for +a directory, including linking and unlinking inodes to/from names, +rename, and directory scanning and lookup. It takes very little +extra code to implemement simple directory behaviour. +.H 2 "Writing your own filesystem classes" +A complete filesystem has two parts: a collection of inodes, one for +each file, and the filesystem structure itself, which holds all the +inodes together. Each inode represents a file in the filesystem, +regardless of type. There is only one inode per file in the +filesystem, even if the file appears multiple times under different +names. +.H 3 "Arguments and return values of operation methods" +Each method with the name +.B do_something +in the Filesystem and Inode classes corresponds to an operation +in the userfs protocol. As a result, they all have similar +argument structures. All such methods have +.B "const up_preamble &pre" " and " "upp_repl &repl" +which are references to the operation reqest and reply packet +headers. Mostly there is no reason for operation methods to +use them, because their contents are dealt with in lower +levels of the library, but they are there if you want them. +.P +Each userfs protocol operation may have arguments, return values, +both or neither, and the method for that operation will have +corresponding arguments. For an operation named +.I x +the method argument with the operation arguments will have the +type \fBconst upp_\fIx\fP_s\fR, +and the return values argument will have the type +\fBupp_\fIx\fP_r\fR, +For example, the up_read operation will correspond to the Inode +method +.CC +int Inode::do_read(const up_preamble &pre, upp_repl &repl, + const upp_read_s &args, upp_read_r &ret); +.EE +.P +The contents of the structures, along with encoding and decoding +functions, are machine generated, and therefore have a consistent +set of rules. Mostly its quite simple, with normal base types +directly corresponding to C and C++ types. However, variable +sized types need to have both a pointer to the data and the +size of the data encoded into them. Memory for the data is allocated +with the C++ new and delete operators, with the +.B alloc +method of a variable sized object. The memory is automatically freed +by the method's caller. For example, if a return value of a method +contains an member called +.B name +representing a filename, it would be set with the following sequence +(assuming +.B ourname +is a normal 0 terminated string): +.CC +int namelen = strlen(ourname); +ret.name.alloc(namelen); // Allocate memory +ret.name.nelem = namelen; // Set name length +memcpy(&ret.name.elems, ourname, namelen); // Set name contents +// ... +.EE +(alternatively, you could just point +.I "ret.name.elems +directly at +.I ourname , +because it won't try and free the string if it was never allocated). +.P +Note that strings are never zero terminated; the length of the +returned string is exactly the number of characters in the string. +.P +If the operation the method is performing fails, it should return the +appropriate error code, or 0 if it succeeds. Don't return -1 unless +you mean to \- it has special meaning (see below, in "Deferring +Replies"). +.H 3 "Deriving from Filesystem" +Filesystem class must implement a number of methods to make the +filesystem viable: +.BL +.LI "\fIEnquire\fP" +is called when the kernel wants to find what operations your +filesystem supports. For all the operations that any inode will +implement, return 0 and return ENOSYS for the rest. +.LI "\fIdo_mount\fP" +takes no arguments and returns the handle for the inode for the +root directory (that is, the top directory of your filesystem). +The kernel immediately does a +.B do_iread +operation using this handle. +.LE +You can also implement +.I do_statfs +which allows the kernel to get space and inode usage statistics, +such as when "df" is executed, and +.I do_umount +so the filesystem is formally informed when it is unmounted (normally +it just gets an EOF from the kernel, and Comm::Run returns). +.H 3 "Deriving from Inode" +Most of the work of the filesystem is done in the inodes. +All inode classes must be derived from Inode, and generally +there will be a number of different Inode based classes. +.P +It is probably better to use SimpleInode as a base rather than +plain Inode, because it implements simple defaults for some +methods, which would otherwise fail. If Filesystem::Enquire +says that the filesystem supports a particular operation, then +any inode should be prepared to get that operation from the +kernel. +.P +Similarly, unless you are doing something special, deriving +directories from DirInode saves a lot of work. +.P +Only +.I do_iread +need be implemented, but obviously the filesystem will do nothing +interesting unless other operations are implemented. do_iread returns +the details of the inode. Note that the Filesystem class calls the +do_iread of the Inode when the operation comes from the kernel, so the +inode must exist by the time the kernel asks for it. The constructor +for Inode automatically registers the inode in the Filesystem's inode +table; conversely, the destructor removes it. +.P +Here are some other useful methods for an Inode; the descriptions +are brief and general, and don't necessarily refer to all the arguments +and return values, which means they can be ignored. +.BL +.LI "\fIdo_iwrite\fP" +is, obviously, the opposite of do_iread. It simply sets the various +Inode values. +.LI "\fIdo_iput\fP" +is called when the kernel is no longer using the inode. That is, +the inode is no longer open, the current or root directory of a +process, being executed from or being mapped from. If an inode +is iput and has no names (has no name to inode mapping in any +directory) it can be destroyed. +.LI "\fIdo_read\fP" +allows data to be read from the file. The arguments are the offset in +the file to start reading from, and the number of bytes desiried. The +method may return as many bytes up to that number as it likes, +including 0, which means EOF. +.LI "\fIdo_write\fP" +does the converse; a block of data and an offset is passed in, and +the method returns the number of bytes actually written. +.LI "\fIdo_lookup\fP" +translates a name into an inode reference. This is typically +implemented for directories; if the name exists in the directory +the method should return the handle of the inode, or fail with +ENOENT. +.LI "\fIdo_dirread\fP" +returns the next directory entry at the passed offset. It returns +the name and inode of the next file in the directory, and the +size of the entry returned. This is added by the kernel to the +current offset in the directory to form the offset of the next +directory entry for the next call. Since the directory entries +don't correspond to real file storage as in other, more conventional +filesystems, a directory entry can be regarded as having an +offset of 1. +.P +If the end of the directory has been reached, it should return a new +offset of 0. +.LI "\fIdo_multireaddir\fP" +is similar to do_readdir, but can return any number of directory +entries, which are cached in a readahead buffer in the kernel. If a +program asks for a directory entry for an inode which has a cached +directory entry then the entry will come from within the kernel rather +than asking the filesystem process. This operation can return only +one entry (and so is like do_readdir), or as many as will fit in a +return packet (up to 4k or so of entries). Returning no entries means +the end of the directory has been reached. Returning multiple entries +improves the performance of directory scans, most frequently done by +ls, pwd and shell globbing. +.P +Look at the implementation of DirInode::do_multireaddir for details +of how this should be dealt with. +.LI "\fIdo_create\fP" +does all file creation, whether it be a normal file, a directory, +a fifo file or a device node. The mode contains the type of the +file in same way as the stat structure member +.B st_mode. +.LI "\fIdo_unlink\fP" +is the opposite, and is used for unlinking (removing a name to inode +mapping) files and directories. If an inode is not in use and +has no links then it can be destroyed and its handle can be reused. +.LI "\fIdo_symlink\fP" +is used to create new symlink inodes. It returns the handle +of the new inode. +.LI "\fIdo_readlink\fP" +returns the pathname which a symbolic link is pointing to. +.LI "\fIdo_followlink\fP" +returns the pathname of the file a symbolic link is really referring +to. If Filesystem::Enquire says the filesystem does not support +this operation, the readlink operation is used instead. +.LI "\fIdo_open\fP" +is called when a file is actually opened. It is only necessary +to implement this if it is important to know whether a file is +being opened as opposed to being used in any other way. This +operation passes the filesystem the complete authentication +credentials of the process doing the open, so that the filesystem +can do extended security checking or change the behaviour of the +file depending on the user. +.P +This method can return a credential token, which is a magic number +used by the filesystem process to refer to the set of credentials +passed by the kernel. The kernel attaches this credentials token to +each each operation generated by system calls on the file descriptor +generated by the open (read(), write(), readdir() and close()). The +credentials token is part of the file descriptor, so is inhereited +unchanged if the descriptor is passed to another process, even if it +has different credentials. +.P +When a file is opened, a new file table entry for the inode is +created. That file table entry has a single file descriptor +referring to it. More file descriptors can be made to refer to +the file table entry with the +.BR dup (2) +system call, and can be removed with +.BR close (2). +.LI "\fIdo_close\fP" +is called when the last file descriptor for a file table entry +is closed. The only argument for this is the credentials token +for that file table entry, so that the filesystem can free all +references to it. +.LI "\fIdo_permission\fP" +is called when the filesystem says it wants to do permissions +checking. This is called a lot, and can cause many more operations +to pass between the kernel and filesystem process. If the filesystem +does not implement it the normal unix user/group/others checking +is performed. +.LI "\fIdo_rename\fP" +moves a file from one directory to a new one (though it may be the +same). +.H 3 "Deriving from DirInode" +DirInode implements a number of userfs operation methods for +directories, such as readdir, multireaddir and lookup. It +also automatically constructs directories with "." and ".." +entries pointing to the appropriate places. +.P +DirInode deals with strings a lot, and rather than using the +normal +.B "char *" +it uses the libg++ +.B String +class for all string arguments to its own methods (but not, +of course, for the userfs protocol operation methods). +.P +DirInode expects a pointer to the parent directory, +which is also a class derived from DirInode. If the directory +is at the top of the filesystem's tree, it should be a NULL +pointer. The protected member +.B parent +points the the parent inode, or +.B this +for the top one. It should never be NULL. +.P +DirInode keeps a list of files in the directory, but does not +allow that list to be directly visible. The only operations +for manipulating the directory contents for a derived class +are: +.BL +.LI "\fBint link(const String name, Inode *)\fP" +which links a new name into the directory, updating all the reference +and link counts; +.LI "\fBint unlink(const String name)\fP" +which does the opposite; +.LI "\fBDirEntry *lookup(const String name)\fP" +which returns a directory entry if it finds the file, or NULL +otherwise; and +.LI "\fBDirEntry *scan(DirEntry * &pos)\fP" +which returns the directory entry at +.I pos, +updating it in the process, or NULL if there are no more entries. +.LI "\fBDirEntry *scan(int &pos)\fP" +is the same, except it uses an integer offset, which is less +efficient. +.LE +.H 2 "Communications classes" +.P +There are a number of communications classes in the library, +which provide different ways of multiplexing replies. +.P +The most simple is the Comm class, which simply takes each request, +passes it to the filesystem and sends back the reply. There are more +complex comms classes though. +.H 3 "File Descriptor Dispatcher" +.P +The +.B CommBase +class (base of all comms classes) provides a dispatcher which allows +classes to register interest in activity on file descriptors. +This is used internally to get input from the kernel, but can be used +by a filesystem to monitor any file descriptor for any reason. +To do it, simply derive a dispatcher class from +.B DispatchFD +and call +.B "struct disp_fd CommBase::addDispatch(int fd, DispatchFD *, int what)" , +where what can be one or more of +.I DISP_R ", " DISP_W " or " DISP_E , +for interest in read ready, write ready or exceptions. +When an event occurs, the +.B "DispatchFD::dispatch(int fd, int what)" +method is called of the registered class. If it returns 0 then +it is removed from the dispatch list. If it returns -1 it indicates +an error; it is removed, and +.B "CommBase::Run()" +returns. Returning 1 is a normal return. +.P +.B "CommBase::Run()" +returns normally when there are no more entries on the dispatch list. +.H 3 "Deferring Replies" +.P +In normal operation, the filesystem processes one request at a time, +so each operation is replied to before the next is looked at. This is +a convention of the way the user code works, and not something the +kernel enforces. It just sends requsts as processes using the +filesystem need them, and they block until the reply for their +particular request is replied to. Therefore, it is possible for +multiple processes to use the filesystem at once. +.P +The +.B DeferComm " and " DeferFilesys +classes have a method called +.B DeferReply +(the DeferFilesys once just calls the DeferComm one to make it +accessable to things within the filesystem). DeferReply forks the +filesystem; on the child side it returns 0 and in the parent it +returns the pid of the child. If the operation method returns -1 then +the Filesystem just goes on to processing the next request from the +kernel. When the child is ready to reply, it can just return in the +normal way. The call to DeferReply sets up the DeferComm class in the +child process to reply though the parent rather than going straight to +the kernel, in order to make sure the replies from multiple processes +don't get jumbled up. When the reply has been sent back, the child +process just exits. +.P +Because the child is really a child process, you have to do all the +changes in filesystem state before calling DeferReply, or arrange for +some other mechanism for the parent and children to talk. +.H 3 "Multi-threaded filesystems" +.P +The +.B ThreadComm +class creates a new lightweight thread for each request, using the Rex +lwp library (in the lwp directory). This allows multiple requests to +be handled within the one process, so long as one thread does not +block the whole process in a system call. The file descriptor +dispatcher in CommBase is useful for preventing this: see +.B ftpfs +for a +complete example of a multithreaded filesystem. Added: trunk/TODO ============================================================================== --- trunk/TODO 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/TODO 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,8 @@ +TODO list +========= + +1. Any C++ hacker should try to compile the sample filesystems - ftpfs, intfs, + homer, etc. There has to be done some work around the String class sure. + +2. Remove useless warnings during compilation of the c++ lib. + Added: trunk/lib/Comm.cc ============================================================================== --- trunk/lib/Comm.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/lib/Comm.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,84 @@ +// -*- C++ -*- + +// Basic communications + +// (C) Copyright 1993, 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#pragma implementation + +#include +#include +#include +#include + +Comm::Comm(Filesystem &fs, unsigned int to, unsigned int from) + :CommBase(fs, to, from) +{ + req = new Comm_doreq(this, filesys); + addDispatch(from, req); +} + +Comm_doreq::Comm_doreq(const CommBase *comm, Filesystem &fs) + : DispToKern(comm), filesys(fs) +{ +} + +int +Comm_doreq::dispatch(int fd, int) +{ + up_preamble pre; + size_t presize = sizeof_up_preamble(&pre); + Uchar hbuf[256]; + Uchar buf[4096]; + int ret; + + ret = fullread(fd, hbuf, presize); + if (ret == 0) + return 0; + + if (ret != (int)presize) + { + fprintf(stderr, "Comm_doreq::dispatch failed to get whole header (%d wanted, %d got)\n", + presize, ret); + return -1; + } + + upp_repl repl; + size_t replsize = sizeof_upp_repl(&repl); + + assert(sizeof(hbuf) > replsize); + + decode_up_preamble(&pre, hbuf); + + if (pre.size != 0 && (ret = fullread(fd, buf, pre.size)) != (int)pre.size) + { + fprintf(stderr, "Comm_doreq::dispatch: failed to get whole body (%ld wanted, %d got)\n", + pre.size, ret); + return -1; + } + + ret = filesys.DoOp(pre, repl, buf); + + if (!ret) + return -1; + +#ifdef DEBUG + if (repl.errno != 0) + { + fprintf(stderr, "Request %d failing with %d %s\n", + pre.op, repl.errno, strerror(repl.errno)); + } +#endif + + encode_upp_repl(&repl, hbuf); + + if (fullwrite(tokern, hbuf, replsize) != replsize) + return -1; + + if (repl.size != 0 && fullwrite(tokern, buf, repl.size) != repl.size) + return -1; + + return 1; +} Added: trunk/lib/Comm.h ============================================================================== --- trunk/lib/Comm.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/lib/Comm.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,32 @@ +// -*- C++ -*- + +// Basic communications - simple 1 in 1 out + +// This program is distributed under the terms of the +// Free Software Foundation General Public Licence. +// Copyright Jeremy Fitzhardinge 1993 + +#ifndef __COMM_H_SEEN__ +#define __COMM_H_SEEN__ + +#pragma interface + +#include + +class Comm: public CommBase +{ +public: + Comm(Filesystem &, unsigned int to, unsigned int from); +}; + +class Comm_doreq: public DispToKern +{ +protected: + Filesystem &filesys; +public: + Comm_doreq(const CommBase *comm, Filesystem &filesys); + + int dispatch(int fd, int); +}; + +#endif /* __COMM_H_SEEN__ */ Added: trunk/lib/DirInode.cc ============================================================================== --- trunk/lib/DirInode.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/lib/DirInode.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,325 @@ +// -*- C++ -*- + +// Generic directory inode by Jeremy Fitzhardinge +// This program is distributed under the terms of the +// Free Software Foundation General Public Licence. +// See COPYING for details + +// A directory + +#include +#include +#include +#include +#include +#include +#include + +#pragma implementation + +#include "Filesystem.h" +#include "SimpleInode.h" +#include "DirInode.h" +#include "string" +#include "dbg.h" + +DirInode::DirInode(Filesystem &fs, Handle h, Inode *p, int mm) + :SimpleInode(fs, h), max_multird(mm) +{ + LOG("DirInode::DirInode"); + + mode = S_IFDIR; + + parent = p == NULL ? this : p; + + size = 0; + + entries = end = NULL; + link(".", this); + link("..", parent); +} + +DirInode::~DirInode() +{ + DirEntry *next; + + for(; entries; entries = next) + { + next = entries->next; + delete entries; + } + + entries = end = NULL; +} + +int +DirInode::link(const string &name, Inode *ino) +{ + if (lookup(name) != NULL) + return EEXIST; + + DirEntry *de = new DirEntry(name, ino); + + de->prev = end; + de->next = NULL; + if (de->prev) + de->prev->next = de; + else + entries = de; + end = de; + + ino->incref(); + + size++; + + return 0; +} + +int +DirInode::unlink(const string &name) +{ + DirEntry *de = lookup(name); + + if (de == NULL) + return ENOENT; + + de->geti()->decref(); + + if (de->next) + de->next->prev = de->prev; + else + end = de->prev; + + if (de->prev) + de->prev->next = de->next; + else + entries = de->next; + + delete de; + + size--; + + return 0; +} + +DirEntry * +DirInode::lookup(const string &name) const +{ + for(DirEntry *de = entries; de != NULL; de = de->next) + if (de->name == name) + return de; + + return NULL; +} + +DirEntry * +DirInode::scan(DirEntry * &de) const +{ + if (de == NULL) + de = entries; + + if (de == NULL) + return NULL; + + DirEntry *ret = de; + de = de->next; + + return ret; +} + +DirEntry * +DirInode::scan(int &ind) const +{ + if (ind >= size) + return NULL; + + int i; + DirEntry *de; + + for(de = entries, i = 0; de != NULL && i < ind; de = de->next, i++) + ; + + if (de == NULL) + return de; + + ind++; + return de; +} + +// Implementations of userfs operations +int +DirInode::do_unlink(const up_preamble &, upp_repl &, + const upp_unlink_s &arg) +{ + update(); + + return unlink(string((char *)arg.name.elems, (int)arg.name.nelem)); +} + +int +DirInode::do_link(const up_preamble &, upp_repl &, + const upp_link_s &args) +{ + update(); + + Inode *ino = findino(args.ofile.handle); + + if (!ino) + return EINVAL; + + return link(string((char *)args.name.elems, (int)args.name.nelem), ino); +} + +int +DirInode::do_rename(const up_preamble &, upp_repl &, + const upp_rename_s &arg) +{ + Inode *ndir = findino(arg.ndir.handle); + + if (ndir == NULL || !S_ISDIR(ndir->mode)) + return ENOTDIR; + + update(); + + string oname((char *)arg.oname.elems, (int)arg.oname.nelem); + + DirEntry *fde = lookup(oname); + + if (!fde) + return ENOENT; + + Inode *file = fde->geti(); + + if (file == NULL) + return EINVAL; + + int ret = ndir->link((char *)arg.nname.elems, arg.nname.nelem, file); + if (ret) + return ret; + ret = unlink(oname); + + ndir->mtime = mtime = time(0); + + return ret; +} + +int +DirInode::do_lookup(const up_preamble &pre, upp_repl &rep, + const upp_lookup_s &arg, upp_lookup_r &res) +{ + update(); + + DirEntry *de = lookup(string((char *)arg.name.elems, (int)arg.name.nelem)); + + atime = time(0); + + if (de != NULL) + { + res.handle.handle = de->geti()->gethandle(); + return 0; + } + return ENOENT; +} + +int +DirInode::do_readdir(const up_preamble &pre, upp_repl &repl, + const upp_readdir_s &arg, upp_readdir_r &res) +{ + LOG("readdir"); + + update(); + + res.off=1; + + int ind = arg.off; + + DirEntry *de = scan(ind); + + if(de == NULL) + { + res.off=0; + res.name.nelem=0; + return 0; + } + + atime = time(0); + + res.name.nelem = strlen((de->name).c_str()); + res.name.elems = (__s8 *) (de->name).c_str(); + res.file.handle = de->ino->gethandle(); + + DB(printf("Readdir:'%s',%d,%d\n",res.name.elems,res.name.nelem,res.file.handle)); + return 0; +} + +int +DirInode::do_read(const up_preamble &, upp_repl &, + const upp_read_s &, upp_read_r &) +{ + return EISDIR; +} + +int +DirInode::do_write(const up_preamble &, upp_repl &, + const upp_write_s &, upp_write_r &) +{ + return EISDIR; +} + +int +DirInode::do_multireaddir(const up_preamble &pre, upp_repl &repl, + const upp_multireaddir_s &arg, + upp_multireaddir_r &res) +{ + update(); + + LOG("multireaddir"); + + int ind = arg.off; + DirEntry *de = scan(ind); + + if (de == NULL) + { + res.nelem = 0; + return 0; + } + + atime = time(0); + + res.nelem = 0; + res.alloc(max_multird); + upp_readdir_r *ents = res.elems; + + int i; + for(i = 0; + de != NULL && i < max_multird && + sizeof_upp_multireaddir_r(&res) < USERFS_MAX_XFER; + i++, scan(de)) + { + int len = de->name.length(); + ents[i].off = 1; + ents[i].name.nelem = len; + ents[i].name.alloc(len); + memcpy(ents[i].name.elems, (de->name).c_str(), len); + ents[i].file.handle = de->ino->gethandle(); + DB(printf("Multireaddir:%d '%s',nlen=%d,ino=%d,off=%d\n", + i, (const char *)de->name, + len, ents[i].file.handle, off)); + res.nelem = i+1; + } + res.nelem = i; + + while(sizeof_upp_multireaddir_r(&res) >= USERFS_MAX_XFER) + res.nelem--; + + return 0; +} + +DirEntry::DirEntry(const string name, Inode *i) + : name(name), ino(i) +{ +} + +DirEntry::~DirEntry() +{ +} Added: trunk/lib/Filesystem.p ============================================================================== --- trunk/lib/Filesystem.p 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/lib/Filesystem.p 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,9584 @@ + + + + + + + + +#pragma implementation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern "C" { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern int errno; + + +extern int *__errno_location (void) throw () __attribute__ ((__const__)); + + + + + + + + + + + + + + + + + + + + + + + + + + +} + + + + + + + + + + + + + + + + + + + + +#pragma interface "userfs_types" + + + + + + + + + + + + +typedef unsigned short __kernel_dev_t; +typedef unsigned long __kernel_ino_t; +typedef unsigned short __kernel_mode_t; +typedef unsigned short __kernel_nlink_t; +typedef long __kernel_off_t; +typedef int __kernel_pid_t; +typedef unsigned short __kernel_ipc_pid_t; +typedef unsigned short __kernel_uid_t; +typedef unsigned short __kernel_gid_t; +typedef unsigned int __kernel_size_t; +typedef int __kernel_ssize_t; +typedef int __kernel_ptrdiff_t; +typedef long __kernel_time_t; +typedef long __kernel_suseconds_t; +typedef long __kernel_clock_t; +typedef int __kernel_daddr_t; +typedef char * __kernel_caddr_t; +typedef unsigned short __kernel_uid16_t; +typedef unsigned short __kernel_gid16_t; +typedef unsigned int __kernel_uid32_t; +typedef unsigned int __kernel_gid32_t; + +typedef unsigned short __kernel_old_uid_t; +typedef unsigned short __kernel_old_gid_t; + + +typedef long long __kernel_loff_t; + + +typedef struct { + + int __val[2]; + +} __kernel_fsid_t; + + + + + + + + +typedef unsigned short umode_t; + + + + + + +typedef __signed__ char __s8; +typedef unsigned char __u8; + +typedef __signed__ short __s16; +typedef unsigned short __u16; + +typedef __signed__ int __s32; +typedef unsigned int __u32; + + +typedef __signed__ long long __s64; +typedef unsigned long long __u64; + + + + + + + + + +typedef __kernel_suseconds_t suseconds_t; +typedef __u8 uint8_t; +typedef __u16 uint16_t; +typedef __u32 uint32_t; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern "C" { + + +extern void __assert_fail (__const char *__assertion, __const char *__file, + unsigned int __line, __const char *__function) + throw () __attribute__ ((__noreturn__)); + + +extern void __assert_perror_fail (int __errnum, __const char *__file, + unsigned int __line, + __const char *__function) + throw () __attribute__ ((__noreturn__)); + + + + +extern void __assert (const char *__assertion, const char *__file, int __line) + throw () __attribute__ ((__noreturn__)); + + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef unsigned int size_t; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern "C" { + + + + + + + +typedef struct + { + int quot; + int rem; + } div_t; + + + +typedef struct + { + long int quot; + long int rem; + } ldiv_t; + + + + + + + + + + + + + + + + + + +extern size_t __ctype_get_mb_cur_max (void) throw () ; + + + +extern double atof (__const char *__nptr) throw () ; + +extern int atoi (__const char *__nptr) throw () ; + +extern long int atol (__const char *__nptr) throw () ; + + + +__extension__ extern long long int atoll (__const char *__nptr) + throw () ; + + + +extern double strtod (__const char *__restrict __nptr, + char **__restrict __endptr) throw () ; + + + + +extern long int strtol (__const char *__restrict __nptr, + char **__restrict __endptr, int __base) throw () ; + +extern unsigned long int strtoul (__const char *__restrict __nptr, + char **__restrict __endptr, int __base) + throw () ; + + + +__extension__ +extern long long int strtoq (__const char *__restrict __nptr, + char **__restrict __endptr, int __base) throw () ; + +__extension__ +extern unsigned long long int strtouq (__const char *__restrict __nptr, + char **__restrict __endptr, int __base) + throw () ; + + + + + + +__extension__ +extern long long int strtoll (__const char *__restrict __nptr, + char **__restrict __endptr, int __base) throw () ; + +__extension__ +extern unsigned long long int strtoull (__const char *__restrict __nptr, + char **__restrict __endptr, int __base) + throw () ; + + + + + + + + + +extern double __strtod_internal (__const char *__restrict __nptr, + char **__restrict __endptr, int __group) + throw () ; +extern float __strtof_internal (__const char *__restrict __nptr, + char **__restrict __endptr, int __group) + throw () ; +extern long double __strtold_internal (__const char *__restrict __nptr, + char **__restrict __endptr, + int __group) throw () ; + +extern long int __strtol_internal (__const char *__restrict __nptr, + char **__restrict __endptr, + int __base, int __group) throw () ; + + + +extern unsigned long int __strtoul_internal (__const char *__restrict __nptr, + char **__restrict __endptr, + int __base, int __group) throw () ; + + + + +__extension__ +extern long long int __strtoll_internal (__const char *__restrict __nptr, + char **__restrict __endptr, + int __base, int __group) throw () ; + + + +__extension__ +extern unsigned long long int __strtoull_internal (__const char * + __restrict __nptr, + char **__restrict __endptr, + int __base, int __group) + throw () ; + + + + + + + +extern __inline double +strtod (__const char *__restrict __nptr, char **__restrict __endptr) throw () +{ + return __strtod_internal (__nptr, __endptr, 0); +} +extern __inline long int +strtol (__const char *__restrict __nptr, char **__restrict __endptr, + int __base) throw () +{ + return __strtol_internal (__nptr, __endptr, __base, 0); +} +extern __inline unsigned long int +strtoul (__const char *__restrict __nptr, char **__restrict __endptr, + int __base) throw () +{ + return __strtoul_internal (__nptr, __endptr, __base, 0); +} + + + + +__extension__ extern __inline long long int +strtoq (__const char *__restrict __nptr, char **__restrict __endptr, + int __base) throw () +{ + return __strtoll_internal (__nptr, __endptr, __base, 0); +} +__extension__ extern __inline unsigned long long int +strtouq (__const char *__restrict __nptr, char **__restrict __endptr, + int __base) throw () +{ + return __strtoull_internal (__nptr, __endptr, __base, 0); +} + + + +__extension__ extern __inline long long int +strtoll (__const char *__restrict __nptr, char **__restrict __endptr, + int __base) throw () +{ + return __strtoll_internal (__nptr, __endptr, __base, 0); +} +__extension__ extern __inline unsigned long long int +strtoull (__const char * __restrict __nptr, char **__restrict __endptr, + int __base) throw () +{ + return __strtoull_internal (__nptr, __endptr, __base, 0); +} + + +extern __inline double +atof (__const char *__nptr) throw () +{ + return strtod (__nptr, (char **) __null ); +} +extern __inline int +atoi (__const char *__nptr) throw () +{ + return (int) strtol (__nptr, (char **) __null , 10); +} +extern __inline long int +atol (__const char *__nptr) throw () +{ + return strtol (__nptr, (char **) __null , 10); +} + + +__extension__ extern __inline long long int +atoll (__const char *__nptr) throw () +{ + return strtoll (__nptr, (char **) __null , 10); +} + + + + + + + + +extern char *l64a (long int __n) throw () ; + + +extern long int a64l (__const char *__s) throw () ; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern "C" { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef unsigned char __u_char; +typedef unsigned short __u_short; +typedef unsigned int __u_int; +typedef unsigned long __u_long; + +__extension__ typedef unsigned long long int __u_quad_t; +__extension__ typedef long long int __quad_t; + +typedef signed char __int8_t; +typedef unsigned char __uint8_t; +typedef signed short int __int16_t; +typedef unsigned short int __uint16_t; +typedef signed int __int32_t; +typedef unsigned int __uint32_t; + +__extension__ typedef signed long long int __int64_t; +__extension__ typedef unsigned long long int __uint64_t; + +typedef __quad_t *__qaddr_t; + +typedef __u_quad_t __dev_t; +typedef __u_int __uid_t; +typedef __u_int __gid_t; +typedef __u_long __ino_t; +typedef __u_int __mode_t; +typedef __u_int __nlink_t; +typedef long int __off_t; +typedef __quad_t __loff_t; +typedef int __pid_t; +typedef int __ssize_t; +typedef __u_long __rlim_t; +typedef __u_quad_t __rlim64_t; +typedef __u_int __id_t; + +typedef struct + { + int __val[2]; + } __fsid_t; + + +typedef int __daddr_t; +typedef char *__caddr_t; +typedef long int __time_t; +typedef unsigned int __useconds_t; +typedef long int __suseconds_t; +typedef long int __swblk_t; + +typedef long int __clock_t; + + +typedef int __clockid_t; + + +typedef int __timer_t; + + + + + + +typedef int __key_t; + + +typedef unsigned short int __ipc_pid_t; + + + +typedef long int __blksize_t; + + + + +typedef long int __blkcnt_t; +typedef __quad_t __blkcnt64_t; + + +typedef __u_long __fsblkcnt_t; +typedef __u_quad_t __fsblkcnt64_t; + + +typedef __u_long __fsfilcnt_t; +typedef __u_quad_t __fsfilcnt64_t; + + +typedef __u_quad_t __ino64_t; + + +typedef __loff_t __off64_t; + + +typedef long int __t_scalar_t; +typedef unsigned long int __t_uscalar_t; + + +typedef int __intptr_t; + + +typedef unsigned int __socklen_t; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +struct __sched_param + { + int __sched_priority; + }; + + + + +typedef int _lt_spinlock_t; + + +struct _pthread_fastlock +{ + long int __status; + _lt_spinlock_t __spinlock; + +}; + + + +typedef struct _pthread_descr_struct *_pthread_descr; + + + + + +typedef struct __pthread_attr_s +{ + int __detachstate; + int __schedpolicy; + struct __sched_param __schedparam; + int __inheritsched; + int __scope; + size_t __guardsize; + int __stackaddr_set; + void *__stackaddr; + size_t __stacksize; +} pthread_attr_t; + + + +typedef struct +{ + struct _pthread_fastlock __c_lock; + _pthread_descr __c_waiting; +} pthread_cond_t; + + + +typedef struct +{ + int __dummy; +} pthread_condattr_t; + + +typedef unsigned int pthread_key_t; + + + + + +typedef struct +{ + int __m_reserved; + int __m_count; + _pthread_descr __m_owner; + int __m_kind; + struct _pthread_fastlock __m_lock; +} pthread_mutex_t; + + + +typedef struct +{ + int __mutexkind; +} pthread_mutexattr_t; + + + +typedef int pthread_once_t; + + + + + + + + +typedef unsigned long int pthread_t; + + + + + + + + + +typedef __u_char u_char; +typedef __u_short u_short; +typedef __u_int u_int; +typedef __u_long u_long; +typedef __quad_t quad_t; +typedef __u_quad_t u_quad_t; +typedef __fsid_t fsid_t; + + +typedef __loff_t loff_t; + + + +typedef __ino_t ino_t; + + + + + + +typedef __dev_t dev_t; + + + + +typedef __gid_t gid_t; + + + + +typedef __mode_t mode_t; + + + + +typedef __nlink_t nlink_t; + + + + +typedef __uid_t uid_t; + + + + + +typedef __off_t off_t; + + + + + + +typedef __pid_t pid_t; + + + + +typedef __id_t id_t; + + + + +typedef __ssize_t ssize_t; + + + + +typedef __daddr_t daddr_t; +typedef __caddr_t caddr_t; + + + +typedef __key_t key_t; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef __time_t time_t; + + + + + + + + + + +typedef __clockid_t clockid_t; + + + + + + + + + + +typedef __timer_t timer_t; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef unsigned long int ulong; +typedef unsigned short int ushort; +typedef unsigned int uint; + + + + + + + + + + + + +typedef int int8_t __attribute__ ((__mode__ ( __QI__ ))) ; +typedef int int16_t __attribute__ ((__mode__ ( __HI__ ))) ; +typedef int int32_t __attribute__ ((__mode__ ( __SI__ ))) ; +typedef int int64_t __attribute__ ((__mode__ ( __DI__ ))) ; + + +typedef unsigned int u_int8_t __attribute__ ((__mode__ ( __QI__ ))) ; +typedef unsigned int u_int16_t __attribute__ ((__mode__ ( __HI__ ))) ; +typedef unsigned int u_int32_t __attribute__ ((__mode__ ( __SI__ ))) ; +typedef unsigned int u_int64_t __attribute__ ((__mode__ ( __DI__ ))) ; + +typedef int register_t __attribute__ ((__mode__ (__word__))); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef int __sig_atomic_t; + + + + +typedef struct + { + unsigned long int __val[(1024 / (8 * sizeof (unsigned long int))) ]; + } __sigset_t; + + + + + + + + + + + + + + + +typedef __sigset_t sigset_t; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +struct timespec + { + long int tv_sec; + long int tv_nsec; + }; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +struct timeval + { + __time_t tv_sec; + __suseconds_t tv_usec; + }; + + + + + + +typedef long int __fd_mask; + + + + + + + +typedef struct + { + + + + __fd_mask __fds_bits[1024 / (8 * sizeof (__fd_mask)) ]; + + + } fd_set; + + + + + + +typedef __fd_mask fd_mask; + + + + + + + + + + + + + +extern "C" { + + + + + + +extern int select (int __nfds, fd_set *__restrict __readfds, + fd_set *__restrict __writefds, + fd_set *__restrict __exceptfds, + struct timeval *__restrict __timeout) throw () ; + + + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef __blkcnt_t blkcnt_t; + + + +typedef __fsblkcnt_t fsblkcnt_t; + + + +typedef __fsfilcnt_t fsfilcnt_t; + + + + + + +} + + + + + + + + + +extern long int random (void) throw () ; + + +extern void srandom (unsigned int __seed) throw () ; + + + + + +extern char *initstate (unsigned int __seed, char *__statebuf, + size_t __statelen) throw () ; + + + +extern char *setstate (char *__statebuf) throw () ; + + + + + + + +struct random_data + { + int32_t *fptr; + int32_t *rptr; + int32_t *state; + int rand_type; + int rand_deg; + int rand_sep; + int32_t *end_ptr; + }; + +extern int random_r (struct random_data *__restrict __buf, + int32_t *__restrict __result) throw () ; + +extern int srandom_r (unsigned int __seed, struct random_data *__buf) throw () ; + +extern int initstate_r (unsigned int __seed, char *__restrict __statebuf, + size_t __statelen, + struct random_data *__restrict __buf) throw () ; + +extern int setstate_r (char *__restrict __statebuf, + struct random_data *__restrict __buf) throw () ; + + + + + +extern int rand (void) throw () ; + +extern void srand (unsigned int __seed) throw () ; + + + +extern int rand_r (unsigned int *__seed) throw () ; + + + + + + + +extern double drand48 (void) throw () ; +extern double erand48 (unsigned short int __xsubi[3]) throw () ; + + +extern long int lrand48 (void) throw () ; +extern long int nrand48 (unsigned short int __xsubi[3]) throw () ; + + +extern long int mrand48 (void) throw () ; +extern long int jrand48 (unsigned short int __xsubi[3]) throw () ; + + +extern void srand48 (long int __seedval) throw () ; +extern unsigned short int *seed48 (unsigned short int __seed16v[3]) throw () ; +extern void lcong48 (unsigned short int __param[7]) throw () ; + + + + + +struct drand48_data + { + unsigned short int __x[3]; + unsigned short int __old_x[3]; + unsigned short int __c; + unsigned short int __init; + unsigned long long int __a; + }; + + +extern int drand48_r (struct drand48_data *__restrict __buffer, + double *__restrict __result) throw () ; +extern int erand48_r (unsigned short int __xsubi[3], + struct drand48_data *__restrict __buffer, + double *__restrict __result) throw () ; + + +extern int lrand48_r (struct drand48_data *__restrict __buffer, + long int *__restrict __result) throw () ; +extern int nrand48_r (unsigned short int __xsubi[3], + struct drand48_data *__restrict __buffer, + long int *__restrict __result) throw () ; + + +extern int mrand48_r (struct drand48_data *__restrict __buffer, + long int *__restrict __result) throw () ; +extern int jrand48_r (unsigned short int __xsubi[3], + struct drand48_data *__restrict __buffer, + long int *__restrict __result) throw () ; + + +extern int srand48_r (long int __seedval, struct drand48_data *__buffer) + throw () ; + +extern int seed48_r (unsigned short int __seed16v[3], + struct drand48_data *__buffer) throw () ; + +extern int lcong48_r (unsigned short int __param[7], + struct drand48_data *__buffer) throw () ; + + + + + + + + +extern void *malloc (size_t __size) throw () ; + +extern void *calloc (size_t __nmemb, size_t __size) + throw () ; + + + + + +extern void *realloc (void *__ptr, size_t __size) throw () ; + +extern void free (void *__ptr) throw () ; + + + +extern void cfree (void *__ptr) throw () ; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern "C" { + + + + + +extern void *alloca (size_t __size) throw () ; + + + + + +} + + + + + + + +extern void *valloc (size_t __size) throw () ; + + + + + +extern void abort (void) throw () __attribute__ ((__noreturn__)); + + + +extern int atexit (void (*__func) (void)) throw () ; + + + + +extern int on_exit (void (*__func) (int __status, void *__arg), void *__arg) + throw () ; + + + + + +extern void exit (int __status) throw () __attribute__ ((__noreturn__)); + + + + + +extern char *getenv (__const char *__name) throw () ; + + + +extern char *__secure_getenv (__const char *__name) throw () ; + + + + + +extern int putenv (char *__string) throw () ; + + + + + +extern int setenv (__const char *__name, __const char *__value, int __replace) + throw () ; + + +extern int unsetenv (__const char *__name) throw () ; + + + + + + +extern int clearenv (void) throw () ; + + + + + + + + +extern char *mktemp (char *__template) throw () ; + + + + + + + +extern int mkstemp (char *__template) throw () ; + + + + + + + + + + +extern char *mkdtemp (char *__template) throw () ; + + + + +extern int system (__const char *__command) throw () ; + + + + + + + + + + + +extern char *realpath (__const char *__restrict __name, + char *__restrict __resolved) throw () ; + + + + + + +typedef int (*__compar_fn_t) (__const void *, __const void *); + + + + + + +extern void *bsearch (__const void *__key, __const void *__base, + size_t __nmemb, size_t __size, __compar_fn_t __compar); + + + +extern void qsort (void *__base, size_t __nmemb, size_t __size, + __compar_fn_t __compar); + + + +extern int abs (int __x) throw () __attribute__ ((__const__)); +extern long int labs (long int __x) throw () __attribute__ ((__const__)); + + + + + + +extern div_t div (int __numer, int __denom) + throw () __attribute__ ((__const__)); +extern ldiv_t ldiv (long int __numer, long int __denom) + throw () __attribute__ ((__const__)); + + + + + + + + + + +extern char *ecvt (double __value, int __ndigit, int *__restrict __decpt, + int *__restrict __sign) throw () ; + + + + +extern char *fcvt (double __value, int __ndigit, int *__restrict __decpt, + int *__restrict __sign) throw () ; + + + + +extern char *gcvt (double __value, int __ndigit, char *__buf) throw () ; + + + + +extern char *qecvt (long double __value, int __ndigit, + int *__restrict __decpt, int *__restrict __sign) throw () ; +extern char *qfcvt (long double __value, int __ndigit, + int *__restrict __decpt, int *__restrict __sign) throw () ; +extern char *qgcvt (long double __value, int __ndigit, char *__buf) throw () ; + + + + +extern int ecvt_r (double __value, int __ndigit, int *__restrict __decpt, + int *__restrict __sign, char *__restrict __buf, + size_t __len) throw () ; +extern int fcvt_r (double __value, int __ndigit, int *__restrict __decpt, + int *__restrict __sign, char *__restrict __buf, + size_t __len) throw () ; + +extern int qecvt_r (long double __value, int __ndigit, + int *__restrict __decpt, int *__restrict __sign, + char *__restrict __buf, size_t __len) throw () ; +extern int qfcvt_r (long double __value, int __ndigit, + int *__restrict __decpt, int *__restrict __sign, + char *__restrict __buf, size_t __len) throw () ; + + + + + + +extern int mblen (__const char *__s, size_t __n) throw () ; + + +extern int mbtowc (wchar_t *__restrict __pwc, + __const char *__restrict __s, size_t __n) throw () ; + + +extern int wctomb (char *__s, wchar_t __wchar) throw () ; + + + +extern size_t mbstowcs (wchar_t *__restrict __pwcs, + __const char *__restrict __s, size_t __n) throw () ; + +extern size_t wcstombs (char *__restrict __s, + __const wchar_t *__restrict __pwcs, size_t __n) + throw () ; + + + + + + + +extern int rpmatch (__const char *__response) throw () ; + + + + + + + + + + + + + + + + + + + + + +extern int getloadavg (double __loadavg[], int __nelem) throw () ; + + + + + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern "C" { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern long int __sysconf (int); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef __clock_t clock_t; + + + + + + + + + + + + + + + + + + + + +struct tm +{ + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + + + long int tm_gmtoff; + __const char *tm_zone; + +}; + + + + +struct itimerspec + { + struct timespec it_interval; + struct timespec it_value; + }; + + +struct sigevent; + + + + + + + + +extern clock_t clock (void) throw () ; + + +extern time_t time (time_t *__timer) throw () ; + + +extern double difftime (time_t __time1, time_t __time0) + throw () __attribute__ ((__const__)); + + +extern time_t mktime (struct tm *__tp) throw () ; + + + + + +extern size_t strftime (char *__restrict __s, size_t __maxsize, + __const char *__restrict __format, + __const struct tm *__restrict __tp) throw () ; + + + + + + +extern struct tm *gmtime (__const time_t *__timer) throw () ; + + + +extern struct tm *localtime (__const time_t *__timer) throw () ; + + + + +extern struct tm *gmtime_r (__const time_t *__restrict __timer, + struct tm *__restrict __tp) throw () ; + + + +extern struct tm *localtime_r (__const time_t *__restrict __timer, + struct tm *__restrict __tp) throw () ; + + + + +extern char *asctime (__const struct tm *__tp) throw () ; + + +extern char *ctime (__const time_t *__timer) throw () ; + + + + + + +extern char *asctime_r (__const struct tm *__restrict __tp, + char *__restrict __buf) throw () ; + + +extern char *ctime_r (__const time_t *__restrict __timer, + char *__restrict __buf) throw () ; + + + + +extern char *__tzname[2]; +extern int __daylight; +extern long int __timezone; + + + + +extern char *tzname[2]; + + + +extern void tzset (void) throw () ; + + + +extern int daylight; +extern long int timezone; + + + + + +extern int stime (__const time_t *__when) throw () ; + + + + + + + + + + + + + +extern time_t timegm (struct tm *__tp) throw () ; + + +extern time_t timelocal (struct tm *__tp) throw () ; + + +extern int dysize (int __year) throw () __attribute__ ((__const__)); + + + + + +extern int nanosleep (__const struct timespec *__requested_time, + struct timespec *__remaining) throw () ; + + + +extern int clock_getres (clockid_t __clock_id, struct timespec *__res) throw () ; + + +extern int clock_gettime (clockid_t __clock_id, struct timespec *__tp) throw () ; + + +extern int clock_settime (clockid_t __clock_id, __const struct timespec *__tp) + throw () ; + + + + + +extern int timer_create (clockid_t __clock_id, + struct sigevent *__restrict __evp, + timer_t *__restrict __timerid) throw () ; + + +extern int timer_delete (timer_t __timerid) throw () ; + + +extern int timer_settime (timer_t __timerid, int __flags, + __const struct itimerspec *__restrict __value, + struct itimerspec *__restrict __ovalue) throw () ; + + +extern int timer_gettime (timer_t __timerid, struct itimerspec *__value) + throw () ; + + +extern int timer_getoverrun (timer_t __timerid) throw () ; + + + + + + + + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef int ptrdiff_t; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef unsigned int wint_t; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern "C" { + + + + +extern int __malloc_initialized; + + + + + +extern void * malloc (size_t __size) throw () ; + + +extern void * calloc (size_t __nmemb, size_t __size) throw () + ; + + + +extern void * realloc (void * __ptr, + size_t __size) throw () + ; + + +extern void free (void * __ptr) throw () ; + + +extern void cfree (void * __ptr) throw () ; + + +extern void * memalign (size_t __alignment, size_t __size) throw () ; + + +extern void * valloc (size_t __size) throw () ; + + + +extern void * pvalloc (size_t __size) throw () + ; + + + +extern void * (*__morecore) (ptrdiff_t __size) ; + + +extern void * __default_morecore (ptrdiff_t __size) throw () + ; + + +struct mallinfo { + int arena; + int ordblks; + int smblks; + int hblks; + int hblkhd; + int usmblks; + int fsmblks; + int uordblks; + int fordblks; + int keepcost; +}; + + +extern struct mallinfo mallinfo (void) throw () ; + + + + + + + + + + + + + + + + + + + + + + + +extern int mallopt (int __param, int __val) throw () ; + + + +extern int malloc_trim (size_t __pad) throw () ; + + + +extern size_t malloc_usable_size (void * __ptr) throw () ; + + +extern void malloc_stats (void) throw () ; + + +extern void * malloc_get_state (void) throw () ; + + + +extern int malloc_set_state (void * __ptr) throw () ; + + + + + +extern void (*__malloc_initialize_hook) (void) ; + +extern void (*__free_hook) (void * __ptr, + __const void * ) ; +extern void * (*__malloc_hook) (size_t __size, + __const void * ) ; +extern void * (*__realloc_hook) (void * __ptr, + size_t __size, + __const void * ) ; +extern void * (*__memalign_hook) (size_t __alignment, + size_t __size, + __const void * ) ; +extern void (*__after_morecore_hook) (void) ; + + +extern void __malloc_check_init (void) throw () ; + + + +}; + + + + +typedef unsigned char unchar; + +static __inline__ void * ALLOC (int alloc) +{ + void *mem = malloc(alloc); + + (static_cast (( mem != 0 ) ? 0 : (__assert_fail ("mem != 0" , "userfs_types.h", 46, __PRETTY_FUNCTION__ ), 0))) ; + return mem; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef struct { + unsigned long fds_bits [(1024 / (8 * sizeof(unsigned long)) ) ]; +} __kernel_fd_set; + + +typedef void (*__kernel_sighandler_t)(int); + + +typedef int __kernel_key_t; + + + + + + + + + + + + + + +struct ustat { + __kernel_daddr_t f_tfree; + __kernel_ino_t f_tinode; + char f_fname[6]; + char f_fpack[6]; +}; + + + + + + + + + + + + + +typedef struct +{ + unsigned long handle; +} up_handle; + +typedef unsigned long up_version; + +struct userfs_inode_info +{ + up_handle handle; + struct userfs_dir_ra *dir_ra; + up_version version; +}; + + + + + + + + + + +typedef unsigned long up_credtok; + +struct userfs_file_info { + up_credtok cred_tok; +}; + + + + + + + + + + + + + + + + + + +typedef unsigned char Uchar; +typedef unsigned short Ushort; +typedef unsigned long Ulong; +typedef unsigned long Uint; +typedef unsigned long long Ulonglong; +typedef long long longlong; + + +__inline__ static unsigned char *encode_char(const char *ch, unsigned char *buf) +{ + *buf = *ch; + return buf+1; +} + +__inline__ static unsigned char *decode_char(char *ch, unsigned char *buf) +{ + *ch = *buf; + return buf+1; +} + +__inline__ static unsigned int sizeof_char(const char *c) +{ + (void)c; + return 1; +} + + +__inline__ static unsigned char *encode_Uchar(const Uchar *ch, unsigned char *buf) +{ + *buf = *ch; + return buf+1; +} + +__inline__ static unsigned char *decode_Uchar(Uchar *ch, unsigned char *buf) +{ + *ch = *buf; + return buf+1; +} + +__inline__ static unsigned int sizeof_Uchar(const Uchar *c) +{ + (void)c; + return 1; +} + + +__inline__ static unsigned char *encode_short(const short *sh, unsigned char *buf) +{ + register short sv = *sh; + + buf[0] = (sv >> 8)& 0xff; + buf[1] = sv & 0xff; + return buf+2; +} + +__inline__ static unsigned char *decode_short(short *sh, unsigned char *buf) +{ + *sh = (buf[0] << 8) | buf[1]; + return buf+2; +} + +__inline__ static unsigned int sizeof_short(const short *c) +{ + (void)c; + return 2; +} + + +__inline__ static unsigned char *encode_Ushort(const Ushort *sh, unsigned char *buf) +{ + register Ushort sv = *sh; + + buf[0] = (sv >> 8)& 0xff; + buf[1] = sv & 0xff; + return buf+2; +} + +__inline__ static unsigned char *decode_Ushort(Ushort *sh, unsigned char *buf) +{ + *sh = (buf[0] << 8) | buf[1]; + return buf+2; +} + +__inline__ static unsigned int sizeof_Ushort(const Ushort *c) +{ + (void)c; + return 2; +} + + +__inline__ static unsigned char *encode_long(const long *l, unsigned char *buf) +{ + register long lv = *l; + + buf[0] = (lv >> 24) & 0xff; + buf[1] = (lv >> 16) & 0xff; + buf[2] = (lv >> 8) & 0xff; + buf[3] = lv & 0xff; + return buf+4; +} + +__inline__ static unsigned char *decode_long(long *l, unsigned char *buf) +{ + *l = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + return buf+4; +} + +__inline__ static unsigned int sizeof_long(const long *c) +{ + (void)c; + return 4; +} + + +__inline__ static unsigned char *encode_Ulong(const Ulong *l, unsigned char *buf) +{ + register Ulong lv = *l; + + buf[0] = (lv >> 24) & 0xff; + buf[1] = (lv >> 16) & 0xff; + buf[2] = (lv >> 8) & 0xff; + buf[3] = lv & 0xff; + return buf+4; +} + +__inline__ static unsigned char *decode_Ulong(Ulong *l, unsigned char *buf) +{ + *l = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + return buf+4; +} + +__inline__ static unsigned int sizeof_Ulong(const Ulong *c) +{ + (void)c; + return 4; +} + + +__inline__ static unsigned char *encode_longlong(const long long *l, + unsigned char *buf) +{ + register long long lv = *l; + + buf[0] = (lv >> 56) & 0xff; + buf[1] = (lv >> 48) & 0xff; + buf[2] = (lv >> 40) & 0xff; + buf[3] = (lv >> 32) & 0xff; + buf[4] = (lv >> 24) & 0xff; + buf[5] = (lv >> 16) & 0xff; + buf[6] = (lv >> 8) & 0xff; + buf[7] = lv & 0xff; + + return buf+8; +} + +__inline__ static unsigned char *decode_longlong(long long *l, + unsigned char *buf) +{ + + *l = (((long long)(buf[ 0 ])) << 56)|(((long long)(buf[ 1 ])) << 48)|(((long long)(buf[ 2 ])) << 40)|(((long long)(buf[ 3 ])) << 32)| + (((long long)(buf[ 4 ])) << 24)|(((long long)(buf[ 5 ])) << 16)|(((long long)(buf[ 6 ])) << 8)| ((long long)(buf[ 7 ])) ; + + return buf+8; +} + +__inline__ static unsigned int sizeof_longlong(const long long *c) +{ + (void)c; + return 8; +} + + +__inline__ static unsigned char *encode_Ulonglong(const unsigned long long *l, + unsigned char *buf) +{ + register unsigned long long lv = *l; + + buf[0] = (lv >> 56) & 0xff; + buf[1] = (lv >> 48) & 0xff; + buf[2] = (lv >> 40) & 0xff; + buf[3] = (lv >> 32) & 0xff; + buf[4] = (lv >> 24) & 0xff; + buf[5] = (lv >> 16) & 0xff; + buf[6] = (lv >> 8) & 0xff; + buf[7] = lv & 0xff; + + return buf+8; +} + +__inline__ static unsigned char *decode_Ulonglong(unsigned long long *l, + unsigned char *buf) +{ + + *l = (((unsigned long long)(buf[ 0 ])) << 56)|(((unsigned long long)(buf[ 1 ])) << 48)|(((unsigned long long)(buf[ 2 ])) << 40)|(((unsigned long long)(buf[ 3 ])) << 32)| + (((unsigned long long)(buf[ 4 ])) << 24)|(((unsigned long long)(buf[ 5 ])) << 16)|(((unsigned long long)(buf[ 6 ])) << 8)| ((unsigned long long)(buf[ 7 ])) ; + + return buf+8; +} + +__inline__ static unsigned int sizeof_Ulonglong(const unsigned long long *c) +{ + (void)c; + return 8; +} + + +__inline__ static unsigned char *encode_void(const void *v, unsigned char *buf) +{ + (void)v; + return buf; +} + +__inline__ static unsigned char *decode_void(void *v, unsigned char *buf) +{ + (void)v; + return buf; +} + +__inline__ static unsigned int sizeof_void(const void *c) +{ + (void)c; + return 0; +} + + + +__inline__ static unsigned char *encode_float(const float *f, unsigned char *buf) +{ + *(float *)buf = *f; + return buf + sizeof(float); +} + +__inline__ static unsigned char *decode_float(float *f, unsigned char *buf) +{ + *f = *(float *)buf; + return buf + sizeof(float); +} + +__inline__ static unsigned int sizeof_float(const float *c) +{ + (void)c; + return sizeof(float); +} + + +__inline__ static unsigned char *encode_double(const double *d, unsigned char *buf) +{ + *(double *)buf = *d; + return buf + sizeof(double); +} + +__inline__ static unsigned char *decode_double(double *d, unsigned char *buf) +{ + *d = *(double *)buf; + return buf + sizeof(double); +} + +__inline__ static unsigned int sizeof_double(const double *c) +{ + (void)c; + return sizeof(double); +} + + + + + + +typedef Ulong _userfs_types_001[32]; +typedef long _userfs_types_002[2]; +typedef Ulong _userfs_types_003[32]; +typedef ushort uf_uid_t; +typedef ushort uf_gid_t; +typedef ushort uf_nlink_t; +typedef ushort uf_dev_t; +typedef struct _userfs_types_S001 { + Ulong nelem; + long* elems; + + int alloced; + void _userfs_types_S001::alloc(unsigned size) {elems = new long [size]; alloced = 1; } + _userfs_types_S001::_userfs_types_S001() { alloced = 0; } + _userfs_types_S001::~_userfs_types_S001() { + if (alloced) { + delete [] elems; alloced = 0; + } + } + +} _userfs_types_004; +typedef struct +{ + uf_uid_t uid; + uf_uid_t euid; + uf_uid_t suid; + uf_uid_t gid; + uf_uid_t egid; + uf_uid_t sgid; + uf_uid_t umask; + _userfs_types_004 groups; +} up_cred; +typedef struct +{ + Ulong ia_valid; + umode_t ia_mode; + uf_uid_t ia_uid; + uf_gid_t ia_gid; + off_t ia_size; + time_t ia_atime; + time_t ia_mtime; + time_t ia_ctime; +} up_iattr; +typedef struct +{ + __s16 version; + long seq; + Uchar op; + Uchar isreq; + Ulong size; +} up_preamble; +typedef struct +{ + __s16 version; + long seq; + Uchar op; + Uchar isreq; + Ulong size; + long err_no; +} upp_repl; +typedef struct +{ + umode_t mode; + uf_nlink_t nlink; + uf_uid_t uid; + uf_gid_t gid; + off_t size; + time_t atime; + time_t mtime; + time_t ctime; + uf_dev_t rdev; + Ulong blksize; + Ulong blocks; +} up_inode; +typedef struct _userfs_types_S002 { + Ulong nelem; + __s8* elems; + + int alloced; + void _userfs_types_S002::alloc(unsigned size) {elems = new __s8 [size]; alloced = 1; } + _userfs_types_S002::_userfs_types_S002() { alloced = 0; } + _userfs_types_S002::~_userfs_types_S002() { + if (alloced) { + delete [] elems; alloced = 0; + } + } + +} up_name; +typedef struct +{ + up_inode ino; + up_handle handle; +} upp_iwrite_s; +typedef struct +{ + up_handle handle; +} upp_iread_s; +typedef struct +{ + up_handle handle; + up_inode ino; +} upp_iread_r; +typedef struct +{ + up_handle dir; + up_name name; +} upp_unlink_s; +typedef struct +{ + up_handle link; +} upp_readlink_s; +typedef struct +{ + up_name name; +} upp_readlink_r; +typedef struct +{ + up_handle dir; + up_handle link; + long flag; + long mode; +} upp_followlink_s; +typedef struct +{ + up_name path; +} upp_followlink_r; +typedef struct _userfs_types_S003 { + Ulong nelem; + long* elems; + + int alloced; + void _userfs_types_S003::alloc(unsigned size) {elems = new long [size]; alloced = 1; } + _userfs_types_S003::_userfs_types_S003() { alloced = 0; } + _userfs_types_S003::~_userfs_types_S003() { + if (alloced) { + delete [] elems; alloced = 0; + } + } + +} _userfs_types_005; +typedef struct +{ + long mode; + up_handle dir; + up_cred cred; + long rdev; + up_name name; +} upp_create_s; +typedef struct +{ + up_handle file; +} upp_create_r; +typedef struct +{ + up_handle dir; + up_name name; +} upp_lookup_s; +typedef struct +{ + up_handle handle; +} upp_lookup_r; +typedef struct +{ + up_handle file; + off_t off; + off_t size; + up_credtok ctok; +} upp_read_s; +typedef struct _userfs_types_S004 { + Ulong nelem; + Uchar* elems; + + int alloced; + void _userfs_types_S004::alloc(unsigned size) {elems = new Uchar [size]; alloced = 1; } + _userfs_types_S004::_userfs_types_S004() { alloced = 0; } + _userfs_types_S004::~_userfs_types_S004() { + if (alloced) { + delete [] elems; alloced = 0; + } + } + +} _userfs_types_006; +typedef struct +{ + _userfs_types_006 data; +} upp_read_r; +typedef struct _userfs_types_S005 { + Ulong nelem; + Uchar* elems; + + int alloced; + void _userfs_types_S005::alloc(unsigned size) {elems = new Uchar [size]; alloced = 1; } + _userfs_types_S005::_userfs_types_S005() { alloced = 0; } + _userfs_types_S005::~_userfs_types_S005() { + if (alloced) { + delete [] elems; alloced = 0; + } + } + +} _userfs_types_007; +typedef struct +{ + up_handle file; + off_t off; + up_credtok ctok; + _userfs_types_007 data; +} upp_write_s; +typedef struct +{ + off_t wrote; +} upp_write_r; +typedef struct +{ + up_handle dir; + off_t off; + up_credtok ctok; +} upp_readdir_s; +typedef struct +{ + up_handle file; + off_t off; + up_name name; +} upp_readdir_r; +typedef upp_readdir_s upp_multireaddir_s; +typedef struct _userfs_types_S006 { + Ulong nelem; + upp_readdir_r* elems; + + int alloced; + void _userfs_types_S006::alloc(unsigned size) {elems = new upp_readdir_r [size]; alloced = 1; } + _userfs_types_S006::_userfs_types_S006() { alloced = 0; } + _userfs_types_S006::~_userfs_types_S006() { + if (alloced) { + delete [] elems; alloced = 0; + } + } + +} upp_multireaddir_r; +typedef struct +{ + up_handle root; +} upp_mount_r; +typedef struct +{ + up_handle handle; +} upp_iput_s; +typedef struct _userfs_types_S007 { + Ulong nelem; + long* elems; + + int alloced; + void _userfs_types_S007::alloc(unsigned size) {elems = new long [size]; alloced = 1; } + _userfs_types_S007::_userfs_types_S007() { alloced = 0; } + _userfs_types_S007::~_userfs_types_S007() { + if (alloced) { + delete [] elems; alloced = 0; + } + } + +} _userfs_types_008; +typedef struct +{ + up_cred cred; + up_handle file; +} upp_open_s; +typedef struct +{ + up_credtok ctok; +} upp_open_r; +typedef struct +{ + up_handle file; + up_credtok ctok; +} upp_close_s; +typedef struct _userfs_types_S008 { + Ulong nelem; + long* elems; + + int alloced; + void _userfs_types_S008::alloc(unsigned size) {elems = new long [size]; alloced = 1; } + _userfs_types_S008::_userfs_types_S008() { alloced = 0; } + _userfs_types_S008::~_userfs_types_S008() { + if (alloced) { + delete [] elems; alloced = 0; + } + } + +} _userfs_types_009; +typedef struct +{ + up_cred cred; + up_handle file; + long mask; +} upp_permission_s; +typedef struct +{ + up_handle odir; + up_name oname; + up_handle ndir; + up_name nname; +} upp_rename_s; +typedef struct +{ + up_handle ofile; + up_handle dir; + up_name name; +} upp_link_s; +typedef struct _userfs_types_S009 { + Ulong nelem; + long* elems; + + int alloced; + void _userfs_types_S009::alloc(unsigned size) {elems = new long [size]; alloced = 1; } + _userfs_types_S009::_userfs_types_S009() { alloced = 0; } + _userfs_types_S009::~_userfs_types_S009() { + if (alloced) { + delete [] elems; alloced = 0; + } + } + +} _userfs_types_010; +typedef struct +{ + up_handle dir; + up_name name; + up_name symname; + up_cred cred; +} upp_symlink_s; +typedef long _userfs_types_011[2]; +typedef struct +{ + __kernel_off_t bsize; + __kernel_off_t blocks; + __kernel_off_t bfree; + __kernel_off_t bavail; + __kernel_off_t files; + __kernel_off_t ffree; + _userfs_types_011 fsid; + __kernel_off_t namelen; +} upp_statfs_r; +typedef struct +{ + up_handle file; + off_t size; +} upp_truncate_s; +typedef struct +{ + up_handle handle; + up_iattr iattr; +} upp_notify_change_s; +typedef struct +{ + up_handle handle; + up_version version; +} upp_inode_valid_s; +typedef struct +{ + up_version version; + __s8 valid; +} upp_inode_valid_r; +static unsigned char *encode_char(const char *, unsigned char *); +static unsigned char *decode_char(char *, unsigned char *); +static unsigned int sizeof_char(const char *); + +static unsigned char *encode_short(const short *, unsigned char *); +static unsigned char *decode_short(short *, unsigned char *); +static unsigned int sizeof_short(const short *); + +static unsigned char *encode_long(const long *, unsigned char *); +static unsigned char *decode_long(long *, unsigned char *); +static unsigned int sizeof_long(const long *); + +static unsigned char *encode_longlong(const longlong *, unsigned char *); +static unsigned char *decode_longlong(longlong *, unsigned char *); +static unsigned int sizeof_longlong(const longlong *); + +static unsigned char *encode_float(const float *, unsigned char *); +static unsigned char *decode_float(float *, unsigned char *); +static unsigned int sizeof_float(const float *); + +static unsigned char *encode_double(const double *, unsigned char *); +static unsigned char *decode_double(double *, unsigned char *); +static unsigned int sizeof_double(const double *); + +static unsigned char *encode_void(const void *, unsigned char *); +static unsigned char *decode_void(void *, unsigned char *); +static unsigned int sizeof_void(const void *); + +static unsigned char *encode_Uchar(const Uchar *, unsigned char *); +static unsigned char *decode_Uchar(Uchar *, unsigned char *); +static unsigned int sizeof_Uchar(const Uchar *); + +static unsigned char *encode_Ushort(const Ushort *, unsigned char *); +static unsigned char *decode_Ushort(Ushort *, unsigned char *); +static unsigned int sizeof_Ushort(const Ushort *); + +static unsigned char *encode_Ulong(const Ulong *, unsigned char *); +static unsigned char *decode_Ulong(Ulong *, unsigned char *); +static unsigned int sizeof_Ulong(const Ulong *); + +static unsigned char *encode_Ulonglong(const Ulonglong *, unsigned char *); +static unsigned char *decode_Ulonglong(Ulonglong *, unsigned char *); +static unsigned int sizeof_Ulonglong(const Ulonglong *); + +unsigned char *encode_Uint(const Uint *, unsigned char *); +unsigned char *decode_Uint(Uint *, unsigned char *); +unsigned int sizeof_Uint(const Uint *); + +unsigned char *encode_int(const int *, unsigned char *); +unsigned char *decode_int(int *, unsigned char *); +unsigned int sizeof_int(const int *); + +unsigned char *encode__userfs_types_001(const _userfs_types_001 *, unsigned char *); +unsigned char *decode__userfs_types_001(_userfs_types_001 *, unsigned char *); +unsigned int sizeof__userfs_types_001(const _userfs_types_001 *); + +unsigned char *encode___kernel_fd_set(const __kernel_fd_set *, unsigned char *); +unsigned char *decode___kernel_fd_set(__kernel_fd_set *, unsigned char *); +unsigned int sizeof___kernel_fd_set(const __kernel_fd_set *); + +unsigned char *encode___kernel_key_t(const __kernel_key_t *, unsigned char *); +unsigned char *decode___kernel_key_t(__kernel_key_t *, unsigned char *); +unsigned int sizeof___kernel_key_t(const __kernel_key_t *); + +unsigned char *encode___kernel_dev_t(const __kernel_dev_t *, unsigned char *); +unsigned char *decode___kernel_dev_t(__kernel_dev_t *, unsigned char *); +unsigned int sizeof___kernel_dev_t(const __kernel_dev_t *); + +unsigned char *encode___kernel_ino_t(const __kernel_ino_t *, unsigned char *); +unsigned char *decode___kernel_ino_t(__kernel_ino_t *, unsigned char *); +unsigned int sizeof___kernel_ino_t(const __kernel_ino_t *); + +unsigned char *encode___kernel_mode_t(const __kernel_mode_t *, unsigned char *); +unsigned char *decode___kernel_mode_t(__kernel_mode_t *, unsigned char *); +unsigned int sizeof___kernel_mode_t(const __kernel_mode_t *); + +unsigned char *encode___kernel_nlink_t(const __kernel_nlink_t *, unsigned char *); +unsigned char *decode___kernel_nlink_t(__kernel_nlink_t *, unsigned char *); +unsigned int sizeof___kernel_nlink_t(const __kernel_nlink_t *); + +unsigned char *encode___kernel_off_t(const __kernel_off_t *, unsigned char *); +unsigned char *decode___kernel_off_t(__kernel_off_t *, unsigned char *); +unsigned int sizeof___kernel_off_t(const __kernel_off_t *); + +unsigned char *encode___kernel_pid_t(const __kernel_pid_t *, unsigned char *); +unsigned char *decode___kernel_pid_t(__kernel_pid_t *, unsigned char *); +unsigned int sizeof___kernel_pid_t(const __kernel_pid_t *); + +unsigned char *encode___kernel_ipc_pid_t(const __kernel_ipc_pid_t *, unsigned char *); +unsigned char *decode___kernel_ipc_pid_t(__kernel_ipc_pid_t *, unsigned char *); +unsigned int sizeof___kernel_ipc_pid_t(const __kernel_ipc_pid_t *); + +unsigned char *encode___kernel_uid_t(const __kernel_uid_t *, unsigned char *); +unsigned char *decode___kernel_uid_t(__kernel_uid_t *, unsigned char *); +unsigned int sizeof___kernel_uid_t(const __kernel_uid_t *); + +unsigned char *encode___kernel_gid_t(const __kernel_gid_t *, unsigned char *); +unsigned char *decode___kernel_gid_t(__kernel_gid_t *, unsigned char *); +unsigned int sizeof___kernel_gid_t(const __kernel_gid_t *); + +unsigned char *encode___kernel_size_t(const __kernel_size_t *, unsigned char *); +unsigned char *decode___kernel_size_t(__kernel_size_t *, unsigned char *); +unsigned int sizeof___kernel_size_t(const __kernel_size_t *); + +unsigned char *encode___kernel_ssize_t(const __kernel_ssize_t *, unsigned char *); +unsigned char *decode___kernel_ssize_t(__kernel_ssize_t *, unsigned char *); +unsigned int sizeof___kernel_ssize_t(const __kernel_ssize_t *); + +unsigned char *encode___kernel_ptrdiff_t(const __kernel_ptrdiff_t *, unsigned char *); +unsigned char *decode___kernel_ptrdiff_t(__kernel_ptrdiff_t *, unsigned char *); +unsigned int sizeof___kernel_ptrdiff_t(const __kernel_ptrdiff_t *); + +unsigned char *encode___kernel_time_t(const __kernel_time_t *, unsigned char *); +unsigned char *decode___kernel_time_t(__kernel_time_t *, unsigned char *); +unsigned int sizeof___kernel_time_t(const __kernel_time_t *); + +unsigned char *encode___kernel_suseconds_t(const __kernel_suseconds_t *, unsigned char *); +unsigned char *decode___kernel_suseconds_t(__kernel_suseconds_t *, unsigned char *); +unsigned int sizeof___kernel_suseconds_t(const __kernel_suseconds_t *); + +unsigned char *encode___kernel_clock_t(const __kernel_clock_t *, unsigned char *); +unsigned char *decode___kernel_clock_t(__kernel_clock_t *, unsigned char *); +unsigned int sizeof___kernel_clock_t(const __kernel_clock_t *); + +unsigned char *encode___kernel_daddr_t(const __kernel_daddr_t *, unsigned char *); +unsigned char *decode___kernel_daddr_t(__kernel_daddr_t *, unsigned char *); +unsigned int sizeof___kernel_daddr_t(const __kernel_daddr_t *); + +unsigned char *encode___kernel_caddr_t(const __kernel_caddr_t *, unsigned char *); +unsigned char *decode___kernel_caddr_t(__kernel_caddr_t *, unsigned char *); +unsigned int sizeof___kernel_caddr_t(const __kernel_caddr_t *); + +unsigned char *encode___kernel_uid16_t(const __kernel_uid16_t *, unsigned char *); +unsigned char *decode___kernel_uid16_t(__kernel_uid16_t *, unsigned char *); +unsigned int sizeof___kernel_uid16_t(const __kernel_uid16_t *); + +unsigned char *encode___kernel_gid16_t(const __kernel_gid16_t *, unsigned char *); +unsigned char *decode___kernel_gid16_t(__kernel_gid16_t *, unsigned char *); +unsigned int sizeof___kernel_gid16_t(const __kernel_gid16_t *); + +unsigned char *encode___kernel_uid32_t(const __kernel_uid32_t *, unsigned char *); +unsigned char *decode___kernel_uid32_t(__kernel_uid32_t *, unsigned char *); +unsigned int sizeof___kernel_uid32_t(const __kernel_uid32_t *); + +unsigned char *encode___kernel_gid32_t(const __kernel_gid32_t *, unsigned char *); +unsigned char *decode___kernel_gid32_t(__kernel_gid32_t *, unsigned char *); +unsigned int sizeof___kernel_gid32_t(const __kernel_gid32_t *); + +unsigned char *encode___kernel_old_uid_t(const __kernel_old_uid_t *, unsigned char *); +unsigned char *decode___kernel_old_uid_t(__kernel_old_uid_t *, unsigned char *); +unsigned int sizeof___kernel_old_uid_t(const __kernel_old_uid_t *); + +unsigned char *encode___kernel_old_gid_t(const __kernel_old_gid_t *, unsigned char *); +unsigned char *decode___kernel_old_gid_t(__kernel_old_gid_t *, unsigned char *); +unsigned int sizeof___kernel_old_gid_t(const __kernel_old_gid_t *); + +unsigned char *encode__userfs_types_002(const _userfs_types_002 *, unsigned char *); +unsigned char *decode__userfs_types_002(_userfs_types_002 *, unsigned char *); +unsigned int sizeof__userfs_types_002(const _userfs_types_002 *); + +unsigned char *encode___kernel_fsid_t(const __kernel_fsid_t *, unsigned char *); +unsigned char *decode___kernel_fsid_t(__kernel_fsid_t *, unsigned char *); +unsigned int sizeof___kernel_fsid_t(const __kernel_fsid_t *); + +unsigned char *encode_umode_t(const umode_t *, unsigned char *); +unsigned char *decode_umode_t(umode_t *, unsigned char *); +unsigned int sizeof_umode_t(const umode_t *); + +unsigned char *encode___s8(const __s8 *, unsigned char *); +unsigned char *decode___s8(__s8 *, unsigned char *); +unsigned int sizeof___s8(const __s8 *); + +unsigned char *encode___u8(const __u8 *, unsigned char *); +unsigned char *decode___u8(__u8 *, unsigned char *); +unsigned int sizeof___u8(const __u8 *); + +unsigned char *encode___s16(const __s16 *, unsigned char *); +unsigned char *decode___s16(__s16 *, unsigned char *); +unsigned int sizeof___s16(const __s16 *); + +unsigned char *encode___u16(const __u16 *, unsigned char *); +unsigned char *decode___u16(__u16 *, unsigned char *); +unsigned int sizeof___u16(const __u16 *); + +unsigned char *encode___s32(const __s32 *, unsigned char *); +unsigned char *decode___s32(__s32 *, unsigned char *); +unsigned int sizeof___s32(const __s32 *); + +unsigned char *encode___u32(const __u32 *, unsigned char *); +unsigned char *decode___u32(__u32 *, unsigned char *); +unsigned int sizeof___u32(const __u32 *); + +unsigned char *encode__userfs_types_003(const _userfs_types_003 *, unsigned char *); +unsigned char *decode__userfs_types_003(_userfs_types_003 *, unsigned char *); +unsigned int sizeof__userfs_types_003(const _userfs_types_003 *); + +unsigned char *encode_fd_set(const fd_set *, unsigned char *); +unsigned char *decode_fd_set(fd_set *, unsigned char *); +unsigned int sizeof_fd_set(const fd_set *); + +unsigned char *encode_dev_t(const dev_t *, unsigned char *); +unsigned char *decode_dev_t(dev_t *, unsigned char *); +unsigned int sizeof_dev_t(const dev_t *); + +unsigned char *encode_ino_t(const ino_t *, unsigned char *); +unsigned char *decode_ino_t(ino_t *, unsigned char *); +unsigned int sizeof_ino_t(const ino_t *); + +unsigned char *encode_mode_t(const mode_t *, unsigned char *); +unsigned char *decode_mode_t(mode_t *, unsigned char *); +unsigned int sizeof_mode_t(const mode_t *); + +unsigned char *encode_nlink_t(const nlink_t *, unsigned char *); +unsigned char *decode_nlink_t(nlink_t *, unsigned char *); +unsigned int sizeof_nlink_t(const nlink_t *); + +unsigned char *encode_off_t(const off_t *, unsigned char *); +unsigned char *decode_off_t(off_t *, unsigned char *); +unsigned int sizeof_off_t(const off_t *); + +unsigned char *encode_pid_t(const pid_t *, unsigned char *); +unsigned char *decode_pid_t(pid_t *, unsigned char *); +unsigned int sizeof_pid_t(const pid_t *); + +unsigned char *encode_daddr_t(const daddr_t *, unsigned char *); +unsigned char *decode_daddr_t(daddr_t *, unsigned char *); +unsigned int sizeof_daddr_t(const daddr_t *); + +unsigned char *encode_key_t(const key_t *, unsigned char *); +unsigned char *decode_key_t(key_t *, unsigned char *); +unsigned int sizeof_key_t(const key_t *); + +unsigned char *encode_suseconds_t(const suseconds_t *, unsigned char *); +unsigned char *decode_suseconds_t(suseconds_t *, unsigned char *); +unsigned int sizeof_suseconds_t(const suseconds_t *); + +unsigned char *encode_uid_t(const uid_t *, unsigned char *); +unsigned char *decode_uid_t(uid_t *, unsigned char *); +unsigned int sizeof_uid_t(const uid_t *); + +unsigned char *encode_gid_t(const gid_t *, unsigned char *); +unsigned char *decode_gid_t(gid_t *, unsigned char *); +unsigned int sizeof_gid_t(const gid_t *); + +unsigned char *encode_size_t(const size_t *, unsigned char *); +unsigned char *decode_size_t(size_t *, unsigned char *); +unsigned int sizeof_size_t(const size_t *); + +unsigned char *encode_ssize_t(const ssize_t *, unsigned char *); +unsigned char *decode_ssize_t(ssize_t *, unsigned char *); +unsigned int sizeof_ssize_t(const ssize_t *); + +unsigned char *encode_ptrdiff_t(const ptrdiff_t *, unsigned char *); +unsigned char *decode_ptrdiff_t(ptrdiff_t *, unsigned char *); +unsigned int sizeof_ptrdiff_t(const ptrdiff_t *); + +unsigned char *encode_time_t(const time_t *, unsigned char *); +unsigned char *decode_time_t(time_t *, unsigned char *); +unsigned int sizeof_time_t(const time_t *); + +unsigned char *encode_clock_t(const clock_t *, unsigned char *); +unsigned char *decode_clock_t(clock_t *, unsigned char *); +unsigned int sizeof_clock_t(const clock_t *); + +unsigned char *encode_caddr_t(const caddr_t *, unsigned char *); +unsigned char *decode_caddr_t(caddr_t *, unsigned char *); +unsigned int sizeof_caddr_t(const caddr_t *); + +unsigned char *encode_u_char(const u_char *, unsigned char *); +unsigned char *decode_u_char(u_char *, unsigned char *); +unsigned int sizeof_u_char(const u_char *); + +unsigned char *encode_u_short(const u_short *, unsigned char *); +unsigned char *decode_u_short(u_short *, unsigned char *); +unsigned int sizeof_u_short(const u_short *); + +unsigned char *encode_u_int(const u_int *, unsigned char *); +unsigned char *decode_u_int(u_int *, unsigned char *); +unsigned int sizeof_u_int(const u_int *); + +unsigned char *encode_u_long(const u_long *, unsigned char *); +unsigned char *decode_u_long(u_long *, unsigned char *); +unsigned int sizeof_u_long(const u_long *); + +unsigned char *encode_unchar(const unchar *, unsigned char *); +unsigned char *decode_unchar(unchar *, unsigned char *); +unsigned int sizeof_unchar(const unchar *); + +unsigned char *encode_ushort(const ushort *, unsigned char *); +unsigned char *decode_ushort(ushort *, unsigned char *); +unsigned int sizeof_ushort(const ushort *); + +unsigned char *encode_uint(const uint *, unsigned char *); +unsigned char *decode_uint(uint *, unsigned char *); +unsigned int sizeof_uint(const uint *); + +unsigned char *encode_ulong(const ulong *, unsigned char *); +unsigned char *decode_ulong(ulong *, unsigned char *); +unsigned int sizeof_ulong(const ulong *); + +unsigned char *encode_u_int8_t(const u_int8_t *, unsigned char *); +unsigned char *decode_u_int8_t(u_int8_t *, unsigned char *); +unsigned int sizeof_u_int8_t(const u_int8_t *); + +unsigned char *encode_int8_t(const int8_t *, unsigned char *); +unsigned char *decode_int8_t(int8_t *, unsigned char *); +unsigned int sizeof_int8_t(const int8_t *); + +unsigned char *encode_u_int16_t(const u_int16_t *, unsigned char *); +unsigned char *decode_u_int16_t(u_int16_t *, unsigned char *); +unsigned int sizeof_u_int16_t(const u_int16_t *); + +unsigned char *encode_int16_t(const int16_t *, unsigned char *); +unsigned char *decode_int16_t(int16_t *, unsigned char *); +unsigned int sizeof_int16_t(const int16_t *); + +unsigned char *encode_u_int32_t(const u_int32_t *, unsigned char *); +unsigned char *decode_u_int32_t(u_int32_t *, unsigned char *); +unsigned int sizeof_u_int32_t(const u_int32_t *); + +unsigned char *encode_int32_t(const int32_t *, unsigned char *); +unsigned char *decode_int32_t(int32_t *, unsigned char *); +unsigned int sizeof_int32_t(const int32_t *); + +unsigned char *encode_uint8_t(const uint8_t *, unsigned char *); +unsigned char *decode_uint8_t(uint8_t *, unsigned char *); +unsigned int sizeof_uint8_t(const uint8_t *); + +unsigned char *encode_uint16_t(const uint16_t *, unsigned char *); +unsigned char *decode_uint16_t(uint16_t *, unsigned char *); +unsigned int sizeof_uint16_t(const uint16_t *); + +unsigned char *encode_uint32_t(const uint32_t *, unsigned char *); +unsigned char *decode_uint32_t(uint32_t *, unsigned char *); +unsigned int sizeof_uint32_t(const uint32_t *); + +unsigned char *encode_up_handle(const up_handle *, unsigned char *); +unsigned char *decode_up_handle(up_handle *, unsigned char *); +unsigned int sizeof_up_handle(const up_handle *); + +unsigned char *encode_up_version(const up_version *, unsigned char *); +unsigned char *decode_up_version(up_version *, unsigned char *); +unsigned int sizeof_up_version(const up_version *); + +unsigned char *encode_up_credtok(const up_credtok *, unsigned char *); +unsigned char *decode_up_credtok(up_credtok *, unsigned char *); +unsigned int sizeof_up_credtok(const up_credtok *); + +unsigned char *encode_uf_uid_t(const uf_uid_t *, unsigned char *); +unsigned char *decode_uf_uid_t(uf_uid_t *, unsigned char *); +unsigned int sizeof_uf_uid_t(const uf_uid_t *); + +unsigned char *encode_uf_gid_t(const uf_gid_t *, unsigned char *); +unsigned char *decode_uf_gid_t(uf_gid_t *, unsigned char *); +unsigned int sizeof_uf_gid_t(const uf_gid_t *); + +unsigned char *encode_uf_nlink_t(const uf_nlink_t *, unsigned char *); +unsigned char *decode_uf_nlink_t(uf_nlink_t *, unsigned char *); +unsigned int sizeof_uf_nlink_t(const uf_nlink_t *); + +unsigned char *encode_uf_dev_t(const uf_dev_t *, unsigned char *); +unsigned char *decode_uf_dev_t(uf_dev_t *, unsigned char *); +unsigned int sizeof_uf_dev_t(const uf_dev_t *); + +unsigned char *encode__userfs_types_004(const _userfs_types_004 *, unsigned char *); +unsigned char *decode__userfs_types_004(_userfs_types_004 *, unsigned char *); +unsigned int sizeof__userfs_types_004(const _userfs_types_004 *); + +unsigned char *encode_up_cred(const up_cred *, unsigned char *); +unsigned char *decode_up_cred(up_cred *, unsigned char *); +unsigned int sizeof_up_cred(const up_cred *); + +unsigned char *encode_up_iattr(const up_iattr *, unsigned char *); +unsigned char *decode_up_iattr(up_iattr *, unsigned char *); +unsigned int sizeof_up_iattr(const up_iattr *); + +unsigned char *encode_up_preamble(const up_preamble *, unsigned char *); +unsigned char *decode_up_preamble(up_preamble *, unsigned char *); +unsigned int sizeof_up_preamble(const up_preamble *); + +unsigned char *encode_upp_repl(const upp_repl *, unsigned char *); +unsigned char *decode_upp_repl(upp_repl *, unsigned char *); +unsigned int sizeof_upp_repl(const upp_repl *); + +unsigned char *encode_up_inode(const up_inode *, unsigned char *); +unsigned char *decode_up_inode(up_inode *, unsigned char *); +unsigned int sizeof_up_inode(const up_inode *); + +unsigned char *encode_up_name(const up_name *, unsigned char *); +unsigned char *decode_up_name(up_name *, unsigned char *); +unsigned int sizeof_up_name(const up_name *); + +unsigned char *encode_upp_iwrite_s(const upp_iwrite_s *, unsigned char *); +unsigned char *decode_upp_iwrite_s(upp_iwrite_s *, unsigned char *); +unsigned int sizeof_upp_iwrite_s(const upp_iwrite_s *); + +unsigned char *encode_upp_iread_s(const upp_iread_s *, unsigned char *); +unsigned char *decode_upp_iread_s(upp_iread_s *, unsigned char *); +unsigned int sizeof_upp_iread_s(const upp_iread_s *); + +unsigned char *encode_upp_iread_r(const upp_iread_r *, unsigned char *); +unsigned char *decode_upp_iread_r(upp_iread_r *, unsigned char *); +unsigned int sizeof_upp_iread_r(const upp_iread_r *); + +unsigned char *encode_upp_unlink_s(const upp_unlink_s *, unsigned char *); +unsigned char *decode_upp_unlink_s(upp_unlink_s *, unsigned char *); +unsigned int sizeof_upp_unlink_s(const upp_unlink_s *); + +unsigned char *encode_upp_readlink_s(const upp_readlink_s *, unsigned char *); +unsigned char *decode_upp_readlink_s(upp_readlink_s *, unsigned char *); +unsigned int sizeof_upp_readlink_s(const upp_readlink_s *); + +unsigned char *encode_upp_readlink_r(const upp_readlink_r *, unsigned char *); +unsigned char *decode_upp_readlink_r(upp_readlink_r *, unsigned char *); +unsigned int sizeof_upp_readlink_r(const upp_readlink_r *); + +unsigned char *encode_upp_followlink_s(const upp_followlink_s *, unsigned char *); +unsigned char *decode_upp_followlink_s(upp_followlink_s *, unsigned char *); +unsigned int sizeof_upp_followlink_s(const upp_followlink_s *); + +unsigned char *encode_upp_followlink_r(const upp_followlink_r *, unsigned char *); +unsigned char *decode_upp_followlink_r(upp_followlink_r *, unsigned char *); +unsigned int sizeof_upp_followlink_r(const upp_followlink_r *); + +unsigned char *encode__userfs_types_005(const _userfs_types_005 *, unsigned char *); +unsigned char *decode__userfs_types_005(_userfs_types_005 *, unsigned char *); +unsigned int sizeof__userfs_types_005(const _userfs_types_005 *); + +unsigned char *encode_upp_create_s(const upp_create_s *, unsigned char *); +unsigned char *decode_upp_create_s(upp_create_s *, unsigned char *); +unsigned int sizeof_upp_create_s(const upp_create_s *); + +unsigned char *encode_upp_create_r(const upp_create_r *, unsigned char *); +unsigned char *decode_upp_create_r(upp_create_r *, unsigned char *); +unsigned int sizeof_upp_create_r(const upp_create_r *); + +unsigned char *encode_upp_lookup_s(const upp_lookup_s *, unsigned char *); +unsigned char *decode_upp_lookup_s(upp_lookup_s *, unsigned char *); +unsigned int sizeof_upp_lookup_s(const upp_lookup_s *); + +unsigned char *encode_upp_lookup_r(const upp_lookup_r *, unsigned char *); +unsigned char *decode_upp_lookup_r(upp_lookup_r *, unsigned char *); +unsigned int sizeof_upp_lookup_r(const upp_lookup_r *); + +unsigned char *encode_upp_read_s(const upp_read_s *, unsigned char *); +unsigned char *decode_upp_read_s(upp_read_s *, unsigned char *); +unsigned int sizeof_upp_read_s(const upp_read_s *); + +unsigned char *encode__userfs_types_006(const _userfs_types_006 *, unsigned char *); +unsigned char *decode__userfs_types_006(_userfs_types_006 *, unsigned char *); +unsigned int sizeof__userfs_types_006(const _userfs_types_006 *); + +unsigned char *encode_upp_read_r(const upp_read_r *, unsigned char *); +unsigned char *decode_upp_read_r(upp_read_r *, unsigned char *); +unsigned int sizeof_upp_read_r(const upp_read_r *); + +unsigned char *encode__userfs_types_007(const _userfs_types_007 *, unsigned char *); +unsigned char *decode__userfs_types_007(_userfs_types_007 *, unsigned char *); +unsigned int sizeof__userfs_types_007(const _userfs_types_007 *); + +unsigned char *encode_upp_write_s(const upp_write_s *, unsigned char *); +unsigned char *decode_upp_write_s(upp_write_s *, unsigned char *); +unsigned int sizeof_upp_write_s(const upp_write_s *); + +unsigned char *encode_upp_write_r(const upp_write_r *, unsigned char *); +unsigned char *decode_upp_write_r(upp_write_r *, unsigned char *); +unsigned int sizeof_upp_write_r(const upp_write_r *); + +unsigned char *encode_upp_readdir_s(const upp_readdir_s *, unsigned char *); +unsigned char *decode_upp_readdir_s(upp_readdir_s *, unsigned char *); +unsigned int sizeof_upp_readdir_s(const upp_readdir_s *); + +unsigned char *encode_upp_readdir_r(const upp_readdir_r *, unsigned char *); +unsigned char *decode_upp_readdir_r(upp_readdir_r *, unsigned char *); +unsigned int sizeof_upp_readdir_r(const upp_readdir_r *); + +unsigned char *encode_upp_multireaddir_s(const upp_multireaddir_s *, unsigned char *); +unsigned char *decode_upp_multireaddir_s(upp_multireaddir_s *, unsigned char *); +unsigned int sizeof_upp_multireaddir_s(const upp_multireaddir_s *); + +unsigned char *encode_upp_multireaddir_r(const upp_multireaddir_r *, unsigned char *); +unsigned char *decode_upp_multireaddir_r(upp_multireaddir_r *, unsigned char *); +unsigned int sizeof_upp_multireaddir_r(const upp_multireaddir_r *); + +unsigned char *encode_upp_mount_r(const upp_mount_r *, unsigned char *); +unsigned char *decode_upp_mount_r(upp_mount_r *, unsigned char *); +unsigned int sizeof_upp_mount_r(const upp_mount_r *); + +unsigned char *encode_upp_iput_s(const upp_iput_s *, unsigned char *); +unsigned char *decode_upp_iput_s(upp_iput_s *, unsigned char *); +unsigned int sizeof_upp_iput_s(const upp_iput_s *); + +unsigned char *encode__userfs_types_008(const _userfs_types_008 *, unsigned char *); +unsigned char *decode__userfs_types_008(_userfs_types_008 *, unsigned char *); +unsigned int sizeof__userfs_types_008(const _userfs_types_008 *); + +unsigned char *encode_upp_open_s(const upp_open_s *, unsigned char *); +unsigned char *decode_upp_open_s(upp_open_s *, unsigned char *); +unsigned int sizeof_upp_open_s(const upp_open_s *); + +unsigned char *encode_upp_open_r(const upp_open_r *, unsigned char *); +unsigned char *decode_upp_open_r(upp_open_r *, unsigned char *); +unsigned int sizeof_upp_open_r(const upp_open_r *); + +unsigned char *encode_upp_close_s(const upp_close_s *, unsigned char *); +unsigned char *decode_upp_close_s(upp_close_s *, unsigned char *); +unsigned int sizeof_upp_close_s(const upp_close_s *); + +unsigned char *encode__userfs_types_009(const _userfs_types_009 *, unsigned char *); +unsigned char *decode__userfs_types_009(_userfs_types_009 *, unsigned char *); +unsigned int sizeof__userfs_types_009(const _userfs_types_009 *); + +unsigned char *encode_upp_permission_s(const upp_permission_s *, unsigned char *); +unsigned char *decode_upp_permission_s(upp_permission_s *, unsigned char *); +unsigned int sizeof_upp_permission_s(const upp_permission_s *); + +unsigned char *encode_upp_rename_s(const upp_rename_s *, unsigned char *); +unsigned char *decode_upp_rename_s(upp_rename_s *, unsigned char *); +unsigned int sizeof_upp_rename_s(const upp_rename_s *); + +unsigned char *encode_upp_link_s(const upp_link_s *, unsigned char *); +unsigned char *decode_upp_link_s(upp_link_s *, unsigned char *); +unsigned int sizeof_upp_link_s(const upp_link_s *); + +unsigned char *encode__userfs_types_010(const _userfs_types_010 *, unsigned char *); +unsigned char *decode__userfs_types_010(_userfs_types_010 *, unsigned char *); +unsigned int sizeof__userfs_types_010(const _userfs_types_010 *); + +unsigned char *encode_upp_symlink_s(const upp_symlink_s *, unsigned char *); +unsigned char *decode_upp_symlink_s(upp_symlink_s *, unsigned char *); +unsigned int sizeof_upp_symlink_s(const upp_symlink_s *); + +unsigned char *encode__userfs_types_011(const _userfs_types_011 *, unsigned char *); +unsigned char *decode__userfs_types_011(_userfs_types_011 *, unsigned char *); +unsigned int sizeof__userfs_types_011(const _userfs_types_011 *); + +unsigned char *encode_upp_statfs_r(const upp_statfs_r *, unsigned char *); +unsigned char *decode_upp_statfs_r(upp_statfs_r *, unsigned char *); +unsigned int sizeof_upp_statfs_r(const upp_statfs_r *); + +unsigned char *encode_upp_truncate_s(const upp_truncate_s *, unsigned char *); +unsigned char *decode_upp_truncate_s(upp_truncate_s *, unsigned char *); +unsigned int sizeof_upp_truncate_s(const upp_truncate_s *); + +unsigned char *encode_upp_notify_change_s(const upp_notify_change_s *, unsigned char *); +unsigned char *decode_upp_notify_change_s(upp_notify_change_s *, unsigned char *); +unsigned int sizeof_upp_notify_change_s(const upp_notify_change_s *); + +unsigned char *encode_upp_inode_valid_s(const upp_inode_valid_s *, unsigned char *); +unsigned char *decode_upp_inode_valid_s(upp_inode_valid_s *, unsigned char *); +unsigned int sizeof_upp_inode_valid_s(const upp_inode_valid_s *); + +unsigned char *encode_upp_inode_valid_r(const upp_inode_valid_r *, unsigned char *); +unsigned char *decode_upp_inode_valid_r(upp_inode_valid_r *, unsigned char *); +unsigned int sizeof_upp_inode_valid_r(const upp_inode_valid_r *); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef enum +{ + userfs_up_create, + userfs_up_lookup, + userfs_up_close, + userfs_up_read, + userfs_up_write, + userfs_up_truncate, + userfs_up_fsync, + userfs_up_readdir, + userfs_up_link, + userfs_up_unlink, + userfs_up_symlink, + userfs_up_readlink, + userfs_up_followlink, + userfs_up_mount, + userfs_up_umount, + userfs_up_iread, + userfs_up_iwrite, + userfs_up_statfs, + userfs_up_iput, + userfs_up_open, + userfs_up_permission, + userfs_up_rename, + userfs_up_multireaddir, + userfs_up_notify_change, + userfs_up_inode_valid, +} up_ops; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern "C" { + + +extern void __assert_fail (__const char *__assertion, __const char *__file, + unsigned int __line, __const char *__function) + throw () __attribute__ ((__noreturn__)); + + +extern void __assert_perror_fail (int __errnum, __const char *__file, + unsigned int __line, + __const char *__function) + throw () __attribute__ ((__noreturn__)); + + + + +extern void __assert (const char *__assertion, const char *__file, int __line) + throw () __attribute__ ((__noreturn__)); + + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#pragma interface + +typedef unsigned long Handle; +class Filesystem; + +class InodeList; +class DirInode; + +class Inode +{ + friend InodeList; + friend DirInode; + +private: + Inode *next, *prev; + short alive, onlist; + +protected: + + uid_t uid; + gid_t gid; + umode_t mode; + nlink_t nlink; + off_t size; + time_t atime; + time_t mtime; + time_t ctime; + dev_t rdev; + + + Handle handle; + + + Filesystem &filesys; + + Inode *findino(Handle h); + + + + virtual void update() {} + + virtual void cleanup() {} +public: + Inode(Filesystem &, Handle); + virtual ~Inode(); + + Handle gethandle() { return handle; } + Filesystem &getfilesys() { return filesys; } + + virtual void incref() { nlink++; } + virtual void decref() { nlink--; } + + virtual void beforeop(enum up_ops) { } + virtual void afterop(enum up_ops) { } + + virtual int link(const char *, int, Inode *) { return 38 ; } + virtual int unlink(const char *, int) { return 38 ; } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +virtual int do_create (const up_preamble &, upp_repl &, const upp_create_s &, upp_create_r &) ; +virtual int do_lookup (const up_preamble &, upp_repl &, const upp_lookup_s &, upp_lookup_r &) ; +virtual int do_link (const up_preamble &, upp_repl &, const upp_link_s &) ; +virtual int do_unlink (const up_preamble &, upp_repl &, const upp_unlink_s &) ; +virtual int do_symlink (const up_preamble &, upp_repl &, const upp_symlink_s &) ; +virtual int do_rename (const up_preamble &, upp_repl &, const upp_rename_s &) ; +virtual int do_readlink (const up_preamble &, upp_repl &, const upp_readlink_s &, upp_readlink_r &) ; +virtual int do_followlink (const up_preamble &, upp_repl &, const upp_followlink_s &, upp_followlink_r &) ; +virtual int do_permission (const up_preamble &, upp_repl &, const upp_permission_s &) ; +virtual int do_iwrite (const up_preamble &, upp_repl &, const upp_iwrite_s &) ; +virtual int do_iread (const up_preamble &, upp_repl &, const upp_iread_s &, upp_iread_r &) ; +virtual int do_iput (const up_preamble &, upp_repl &, const upp_iput_s &) ; +virtual int do_notify_change (const up_preamble &, upp_repl &, const upp_notify_change_s &) ; +virtual int do_truncate (const up_preamble &, upp_repl &, const upp_truncate_s &) ; +virtual int do_inode_valid (const up_preamble &, upp_repl &, const upp_inode_valid_s &, upp_inode_valid_r &) ; + + + + + + + +virtual int do_read (const up_preamble &, upp_repl &, const upp_read_s &, upp_read_r &) ; +virtual int do_write (const up_preamble &, upp_repl &, const upp_write_s &, upp_write_r &) ; +virtual int do_readdir (const up_preamble &, upp_repl &, const upp_readdir_s &, upp_readdir_r &) ; +virtual int do_multireaddir (const up_preamble &, upp_repl &, const upp_multireaddir_s &, upp_multireaddir_r &) ; +virtual int do_open (const up_preamble &, upp_repl &, const upp_open_s &, upp_open_r &) ; +virtual int do_close (const up_preamble &, upp_repl &, const upp_close_s &) ; + + + + + + + + + + +}; + + + + +class InodeList +{ +private: + Inode *list; + +public: + InodeList(); + ~InodeList(); + Inode *find(Handle); + void add(Inode *); + void del(Inode *); +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef __suseconds_t suseconds_t; + + + + +extern "C" { + + + + + + + +struct timezone + { + int tz_minuteswest; + int tz_dsttime; + }; + +typedef struct timezone *__restrict __timezone_ptr_t; + + + + + + + +extern int gettimeofday (struct timeval *__restrict __tv, + __timezone_ptr_t __tz) throw () ; + + + + +extern int settimeofday (__const struct timeval *__tv, + __const struct timezone *__tz) throw () ; + + + + + +extern int adjtime (__const struct timeval *__delta, + struct timeval *__olddelta) throw () ; + + + + +enum __itimer_which + { + + ITIMER_REAL = 0, + + + ITIMER_VIRTUAL = 1, + + + + ITIMER_PROF = 2 + + }; + + + +struct itimerval + { + + struct timeval it_interval; + + struct timeval it_value; + }; + + +typedef int __itimer_which_t; + + + + +extern int getitimer (__itimer_which_t __which, + struct itimerval *__value) throw () ; + + + + +extern int setitimer (__itimer_which_t __which, + __const struct itimerval *__restrict __new, + struct itimerval *__restrict __old) throw () ; + + + +extern int utimes (__const char *__file, __const struct timeval __tvp[2]) + throw () ; + + + + + + + + + + + + +} + + + + +#pragma interface + +class Filesystem; +class DispatchFD; +class DispToKern; + + + + + + + + + + +class CommBase +{ + friend Filesystem; + friend DispToKern; + + + struct dispq_t + { + struct disp_fd *h, *t; + } dispqs[4 ]; + int dispatches; + + + unsigned int tokern; + +protected: + + Filesystem &filesys; + + DispatchFD *req; + +public: + CommBase(Filesystem &, unsigned int to, unsigned int from); + virtual ~CommBase(); + + struct disp_fd *addDispatch(int fd, DispatchFD *dfd, int what= 1 , int pri = 2); + void delDispatch(struct disp_fd *); + + + int Run(); + + + int DeferRepl(); + + + + void CloseFDs(int all = 0); +}; + + +class DispatchFD +{ +public: + virtual int dispatch(int fd, int what) = 0; + virtual ~DispatchFD(); +}; + + +class DispToKern : public DispatchFD +{ +protected: + int tokern; +public: + DispToKern(const CommBase *); +}; + + + + +#pragma interface + +typedef unsigned char Data; +class Comm; + +class Filesystem +{ + friend CommBase; + friend Inode; + + const char *mpoint; + + CommBase *comm_p; + void setcomm(CommBase *c) { comm_p = c; } + +protected: + InodeList inodes; + virtual int Enquire(up_ops op); + + Handle rootdir; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +virtual int do_mount (const up_preamble &, upp_repl &, upp_mount_r &) ; +virtual int do_umount (const up_preamble &, upp_repl &) ; +virtual int do_statfs (const up_preamble &, upp_repl &, upp_statfs_r &) ; + + + + + + + +virtual int do_create (const up_preamble &, upp_repl &, const upp_create_s &, upp_create_r &) ; +virtual int do_lookup (const up_preamble &, upp_repl &, const upp_lookup_s &, upp_lookup_r &) ; +virtual int do_link (const up_preamble &, upp_repl &, const upp_link_s &) ; +virtual int do_unlink (const up_preamble &, upp_repl &, const upp_unlink_s &) ; +virtual int do_symlink (const up_preamble &, upp_repl &, const upp_symlink_s &) ; +virtual int do_rename (const up_preamble &, upp_repl &, const upp_rename_s &) ; +virtual int do_readlink (const up_preamble &, upp_repl &, const upp_readlink_s &, upp_readlink_r &) ; +virtual int do_followlink (const up_preamble &, upp_repl &, const upp_followlink_s &, upp_followlink_r &) ; +virtual int do_permission (const up_preamble &, upp_repl &, const upp_permission_s &) ; +virtual int do_iwrite (const up_preamble &, upp_repl &, const upp_iwrite_s &) ; +virtual int do_iread (const up_preamble &, upp_repl &, const upp_iread_s &, upp_iread_r &) ; +virtual int do_iput (const up_preamble &, upp_repl &, const upp_iput_s &) ; +virtual int do_notify_change (const up_preamble &, upp_repl &, const upp_notify_change_s &) ; +virtual int do_truncate (const up_preamble &, upp_repl &, const upp_truncate_s &) ; +virtual int do_inode_valid (const up_preamble &, upp_repl &, const upp_inode_valid_s &, upp_inode_valid_r &) ; + + + + + + + +virtual int do_read (const up_preamble &, upp_repl &, const upp_read_s &, upp_read_r &) ; +virtual int do_write (const up_preamble &, upp_repl &, const upp_write_s &, upp_write_r &) ; +virtual int do_readdir (const up_preamble &, upp_repl &, const upp_readdir_s &, upp_readdir_r &) ; +virtual int do_multireaddir (const up_preamble &, upp_repl &, const upp_multireaddir_s &, upp_multireaddir_r &) ; +virtual int do_open (const up_preamble &, upp_repl &, const upp_open_s &, upp_open_r &) ; +virtual int do_close (const up_preamble &, upp_repl &, const upp_close_s &) ; + + + + + + + + + + + +public: + Filesystem(const char *mpoint); + virtual ~Filesystem(); + + Inode *findino(Handle h) { return inodes.find(h); } + + + + int DoOp(const up_preamble &, upp_repl &, Data *data); + + CommBase *comm() const { return comm_p; } +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern "C" { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef __intptr_t intptr_t; + + + + + + +typedef __socklen_t socklen_t; + + + + + + + + + + + + +extern int access (__const char *__name, int __type) throw () ; + + + + + + + + + + + + + + + + + + + + + + + + + +extern __off_t lseek (int __fd, __off_t __offset, int __whence) throw () ; + + + + +extern int close (int __fd) throw () ; + + + +extern ssize_t read (int __fd, void *__buf, size_t __nbytes) throw () ; + + +extern ssize_t write (int __fd, __const void *__buf, size_t __n) throw () ; + + + + + + + +extern int pipe (int __pipedes[2]) throw () ; + + + + + + + + +extern unsigned int alarm (unsigned int __seconds) throw () ; + + + + + + + + +extern unsigned int sleep (unsigned int __seconds) throw () ; + + + + + + +extern __useconds_t ualarm (__useconds_t __value, __useconds_t __interval) + throw () ; + + + +extern int usleep (__useconds_t __useconds) throw () ; + + + + + +extern int pause (void) throw () ; + + + +extern int chown (__const char *__file, __uid_t __owner, __gid_t __group) + throw () ; + + + +extern int fchown (int __fd, __uid_t __owner, __gid_t __group) throw () ; + + + + +extern int lchown (__const char *__file, __uid_t __owner, __gid_t __group) + throw () ; + + + + +extern int chdir (__const char *__path) throw () ; + + + +extern int fchdir (int __fd) throw () ; + + + + + + + + + +extern char *getcwd (char *__buf, size_t __size) throw () ; + + + + + + + +extern char *getwd (char *__buf) throw () ; + + + + +extern int dup (int __fd) throw () ; + + +extern int dup2 (int __fd, int __fd2) throw () ; + + +extern char **__environ; + + + + + +extern int execve (__const char *__path, char *__const __argv[], + char *__const __envp[]) throw () ; + + + + + +extern int execv (__const char *__path, char *__const __argv[]) throw () ; + + + +extern int execle (__const char *__path, __const char *__arg, ...) throw () ; + + + +extern int execl (__const char *__path, __const char *__arg, ...) throw () ; + + + +extern int execvp (__const char *__file, char *__const __argv[]) throw () ; + + + + +extern int execlp (__const char *__file, __const char *__arg, ...) throw () ; + + + + +extern int nice (int __inc) throw () ; + + + + +extern void _exit (int __status) __attribute__ ((__noreturn__)); + + + + + + + + + + + + + + + + + + + + + + + + + + + +enum + { + _PC_LINK_MAX, + + _PC_MAX_CANON, + + _PC_MAX_INPUT, + + _PC_NAME_MAX, + + _PC_PATH_MAX, + + _PC_PIPE_BUF, + + _PC_CHOWN_RESTRICTED, + + _PC_NO_TRUNC, + + _PC_VDISABLE, + + _PC_SYNC_IO, + + _PC_ASYNC_IO, + + _PC_PRIO_IO, + + _PC_SOCK_MAXBUF, + + _PC_FILESIZEBITS, + + _PC_REC_INCR_XFER_SIZE, + + _PC_REC_MAX_XFER_SIZE, + + _PC_REC_MIN_XFER_SIZE, + + _PC_REC_XFER_ALIGN + + }; + + +enum + { + _SC_ARG_MAX, + + _SC_CHILD_MAX, + + _SC_CLK_TCK, + + _SC_NGROUPS_MAX, + + _SC_OPEN_MAX, + + _SC_STREAM_MAX, + + _SC_TZNAME_MAX, + + _SC_JOB_CONTROL, + + _SC_SAVED_IDS, + + _SC_REALTIME_SIGNALS, + + _SC_PRIORITY_SCHEDULING, + + _SC_TIMERS, + + _SC_ASYNCHRONOUS_IO, + + _SC_PRIORITIZED_IO, + + _SC_SYNCHRONIZED_IO, + + _SC_FSYNC, + + _SC_MAPPED_FILES, + + _SC_MEMLOCK, + + _SC_MEMLOCK_RANGE, + + _SC_MEMORY_PROTECTION, + + _SC_MESSAGE_PASSING, + + _SC_SEMAPHORES, + + _SC_SHARED_MEMORY_OBJECTS, + + _SC_AIO_LISTIO_MAX, + + _SC_AIO_MAX, + + _SC_AIO_PRIO_DELTA_MAX, + + _SC_DELAYTIMER_MAX, + + _SC_MQ_OPEN_MAX, + + _SC_MQ_PRIO_MAX, + + _SC_VERSION, + + _SC_PAGESIZE, + + + _SC_RTSIG_MAX, + + _SC_SEM_NSEMS_MAX, + + _SC_SEM_VALUE_MAX, + + _SC_SIGQUEUE_MAX, + + _SC_TIMER_MAX, + + + + + _SC_BC_BASE_MAX, + + _SC_BC_DIM_MAX, + + _SC_BC_SCALE_MAX, + + _SC_BC_STRING_MAX, + + _SC_COLL_WEIGHTS_MAX, + + _SC_EQUIV_CLASS_MAX, + + _SC_EXPR_NEST_MAX, + + _SC_LINE_MAX, + + _SC_RE_DUP_MAX, + + _SC_CHARCLASS_NAME_MAX, + + + _SC_2_VERSION, + + _SC_2_C_BIND, + + _SC_2_C_DEV, + + _SC_2_FORT_DEV, + + _SC_2_FORT_RUN, + + _SC_2_SW_DEV, + + _SC_2_LOCALEDEF, + + + _SC_PII, + + _SC_PII_XTI, + + _SC_PII_SOCKET, + + _SC_PII_INTERNET, + + _SC_PII_OSI, + + _SC_POLL, + + _SC_SELECT, + + _SC_UIO_MAXIOV, + + _SC_IOV_MAX = _SC_UIO_MAXIOV , + + _SC_PII_INTERNET_STREAM, + + _SC_PII_INTERNET_DGRAM, + + _SC_PII_OSI_COTS, + + _SC_PII_OSI_CLTS, + + _SC_PII_OSI_M, + + _SC_T_IOV_MAX, + + + + _SC_THREADS, + + _SC_THREAD_SAFE_FUNCTIONS, + + _SC_GETGR_R_SIZE_MAX, + + _SC_GETPW_R_SIZE_MAX, + + _SC_LOGIN_NAME_MAX, + + _SC_TTY_NAME_MAX, + + _SC_THREAD_DESTRUCTOR_ITERATIONS, + + _SC_THREAD_KEYS_MAX, + + _SC_THREAD_STACK_MIN, + + _SC_THREAD_THREADS_MAX, + + _SC_THREAD_ATTR_STACKADDR, + + _SC_THREAD_ATTR_STACKSIZE, + + _SC_THREAD_PRIORITY_SCHEDULING, + + _SC_THREAD_PRIO_INHERIT, + + _SC_THREAD_PRIO_PROTECT, + + _SC_THREAD_PROCESS_SHARED, + + + _SC_NPROCESSORS_CONF, + + _SC_NPROCESSORS_ONLN, + + _SC_PHYS_PAGES, + + _SC_AVPHYS_PAGES, + + _SC_ATEXIT_MAX, + + _SC_PASS_MAX, + + + _SC_XOPEN_VERSION, + + _SC_XOPEN_XCU_VERSION, + + _SC_XOPEN_UNIX, + + _SC_XOPEN_CRYPT, + + _SC_XOPEN_ENH_I18N, + + _SC_XOPEN_SHM, + + + _SC_2_CHAR_TERM, + + _SC_2_C_VERSION, + + _SC_2_UPE, + + + _SC_XOPEN_XPG2, + + _SC_XOPEN_XPG3, + + _SC_XOPEN_XPG4, + + + _SC_CHAR_BIT, + + _SC_CHAR_MAX, + + _SC_CHAR_MIN, + + _SC_INT_MAX, + + _SC_INT_MIN, + + _SC_LONG_BIT, + + _SC_WORD_BIT, + + _SC_MB_LEN_MAX, + + _SC_NZERO, + + _SC_SSIZE_MAX, + + _SC_SCHAR_MAX, + + _SC_SCHAR_MIN, + + _SC_SHRT_MAX, + + _SC_SHRT_MIN, + + _SC_UCHAR_MAX, + + _SC_UINT_MAX, + + _SC_ULONG_MAX, + + _SC_USHRT_MAX, + + + _SC_NL_ARGMAX, + + _SC_NL_LANGMAX, + + _SC_NL_MSGMAX, + + _SC_NL_NMAX, + + _SC_NL_SETMAX, + + _SC_NL_TEXTMAX, + + + _SC_XBS5_ILP32_OFF32, + + _SC_XBS5_ILP32_OFFBIG, + + _SC_XBS5_LP64_OFF64, + + _SC_XBS5_LPBIG_OFFBIG, + + + _SC_XOPEN_LEGACY, + + _SC_XOPEN_REALTIME, + + _SC_XOPEN_REALTIME_THREADS, + + + _SC_ADVISORY_INFO, + + _SC_BARRIERS, + + _SC_BASE, + + _SC_C_LANG_SUPPORT, + + _SC_C_LANG_SUPPORT_R, + + _SC_CLOCK_SELECTION, + + _SC_CPUTIME, + + _SC_THREAD_CPUTIME, + + _SC_DEVICE_IO, + + _SC_DEVICE_SPECIFIC, + + _SC_DEVICE_SPECIFIC_R, + + _SC_FD_MGMT, + + _SC_FIFO, + + _SC_PIPE, + + _SC_FILE_ATTRIBUTES, + + _SC_FILE_LOCKING, + + _SC_FILE_SYSTEM, + + _SC_MONOTONIC_CLOCK, + + _SC_MULTIPLE_PROCESS, + + _SC_SINGLE_PROCESS, + + _SC_NETWORKING, + + _SC_READER_WRITER_LOCKS, + + _SC_SPIN_LOCKS, + + _SC_REGEXP, + + _SC_REGEX_VERSION, + + _SC_SHELL, + + _SC_SIGNALS, + + _SC_SPAWN, + + _SC_SPORADIC_SERVER, + + _SC_THREAD_SPORADIC_SERVER, + + _SC_SYSTEM_DATABASE, + + _SC_SYSTEM_DATABASE_R, + + _SC_TIMEOUTS, + + _SC_TYPED_MEMORY_OBJECTS, + + _SC_USER_GROUPS, + + _SC_USER_GROUPS_R, + + _SC_2_PBS, + + _SC_2_PBS_ACCOUNTING, + + _SC_2_PBS_LOCATE, + + _SC_2_PBS_MESSAGE, + + _SC_2_PBS_TRACK, + + _SC_SYMLOOP, + + _SC_STREAMS, + + _SC_2_PBS_CHECKPOINT + + }; + + + +enum + { + _CS_PATH + + + + + + }; + + + + +extern long int pathconf (__const char *__path, int __name) throw () ; + + +extern long int fpathconf (int __fd, int __name) throw () ; + + +extern long int sysconf (int __name) throw () __attribute__ ((__const__)); + + + +extern size_t confstr (int __name, char *__buf, size_t __len) throw () ; + + + + +extern __pid_t getpid (void) throw () ; + + +extern __pid_t getppid (void) throw () ; + + + + +extern __pid_t getpgrp (void) throw () ; + + + +extern __pid_t __getpgid (__pid_t __pid) throw () ; + + + + + + +extern int setpgid (__pid_t __pid, __pid_t __pgid) throw () ; + + + + + + + + + + + + + + + + +extern int setpgrp (void) throw () ; + + + + + + + +extern __pid_t setsid (void) throw () ; + + + + +extern __uid_t getuid (void) throw () ; + + +extern __uid_t geteuid (void) throw () ; + + +extern __gid_t getgid (void) throw () ; + + +extern __gid_t getegid (void) throw () ; + + + + +extern int getgroups (int __size, __gid_t __list[]) throw () ; + + + + + + + +extern int setuid (__uid_t __uid) throw () ; + + + + +extern int setreuid (__uid_t __ruid, __uid_t __euid) throw () ; + + + + +extern int seteuid (__uid_t __uid) throw () ; + + + + + + +extern int setgid (__gid_t __gid) throw () ; + + + + +extern int setregid (__gid_t __rgid, __gid_t __egid) throw () ; + + + + +extern int setegid (__gid_t __gid) throw () ; + + + + + + +extern __pid_t fork (void) throw () ; + + + + + + +extern __pid_t vfork (void) throw () ; + + + + + +extern char *ttyname (int __fd) throw () ; + + + +extern int ttyname_r (int __fd, char *__buf, size_t __buflen) throw () ; + + + +extern int isatty (int __fd) throw () ; + + + + +extern int ttyslot (void) throw () ; + + + + +extern int link (__const char *__from, __const char *__to) throw () ; + + + +extern int symlink (__const char *__from, __const char *__to) throw () ; + + + + +extern int readlink (__const char *__restrict __path, char *__restrict __buf, + size_t __len) throw () ; + + + +extern int unlink (__const char *__name) throw () ; + + +extern int rmdir (__const char *__path) throw () ; + + + +extern __pid_t tcgetpgrp (int __fd) throw () ; + + +extern int tcsetpgrp (int __fd, __pid_t __pgrp_id) throw () ; + + + +extern char *getlogin (void) throw () ; + + + + +extern int setlogin (__const char *__name) throw () ; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern "C" { + + + + + + + + +extern char *optarg; + + + + + + + + + + + + + +extern int optind; + + + + +extern int opterr; + + + +extern int optopt; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern int getopt (int __argc, char *const *__argv, const char *__shortopts); + + + + + + +} + + + + + + + + + + + + + + +extern int gethostname (char *__name, size_t __len) throw () ; + + + + + + +extern int sethostname (__const char *__name, size_t __len) throw () ; + + + +extern int sethostid (long int __id) throw () ; + + + + + +extern int getdomainname (char *__name, size_t __len) throw () ; +extern int setdomainname (__const char *__name, size_t __len) throw () ; + + + + + +extern int vhangup (void) throw () ; + + +extern int revoke (__const char *__file) throw () ; + + + + + + + +extern int profil (unsigned short int *__sample_buffer, size_t __size, + size_t __offset, unsigned int __scale) throw () ; + + + + + +extern int acct (__const char *__name) throw () ; + + + +extern char *getusershell (void) throw () ; +extern void endusershell (void) throw () ; +extern void setusershell (void) throw () ; + + + + + +extern int daemon (int __nochdir, int __noclose) throw () ; + + + + + + +extern int chroot (__const char *__path) throw () ; + + + +extern char *getpass (__const char *__prompt) throw () ; + + + + + +extern int fsync (int __fd) throw () ; + + + + + + +extern long int gethostid (void) throw () ; + + +extern void sync (void) throw () ; + + + + +extern int getpagesize (void) throw () __attribute__ ((__const__)); + + + + +extern int truncate (__const char *__file, __off_t __length) throw () ; + + + + + +extern int ftruncate (int __fd, __off_t __length) throw () ; + + + + + + +extern int getdtablesize (void) throw () ; + + + + + + + + +extern int brk (void *__addr) throw () ; + + + + + +extern void *sbrk (intptr_t __delta) throw () ; + + + + + + + + + + + + + + +extern long int syscall (long int __sysno, ...) throw () ; + + + + + + + + + + + + + + + + + + + +extern int lockf (int __fd, int __cmd, __off_t __len) throw () ; + + + + + + + + + + +extern int fdatasync (int __fildes) throw () ; + + + + + + + + + + + + + + + + + + + + + + + + + + +extern int pthread_atfork (void (*__prepare) (void), + void (*__parent) (void), + void (*__child) (void)) throw () ; + + +} + + + + + + + + + + + + +Filesystem::Filesystem(const char *mp) +{ + mpoint = mp; + rootdir = (Handle)-1; +} + +Filesystem::~Filesystem() +{ +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern "C" { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef struct _IO_FILE FILE; + + + + + + + + + +typedef struct _IO_FILE __FILE; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef struct +{ + int __count; + union + { + wint_t __wch; + char __wchb[4]; + } __value; +} __mbstate_t; + + + + + + + + + + + +typedef struct +{ + __off_t __pos; + __mbstate_t __state; +} _G_fpos_t; +typedef struct +{ + __off64_t __pos; + __mbstate_t __state; +} _G_fpos64_t; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +enum +{ + __GCONV_OK = 0, + __GCONV_NOCONV, + __GCONV_NODB, + __GCONV_NOMEM, + + __GCONV_EMPTY_INPUT, + __GCONV_FULL_OUTPUT, + __GCONV_ILLEGAL_INPUT, + __GCONV_INCOMPLETE_INPUT, + + __GCONV_ILLEGAL_DESCRIPTOR, + __GCONV_INTERNAL_ERROR +}; + + + +enum +{ + __GCONV_IS_LAST = 0x0001, + __GCONV_IGNORE_ERRORS = 0x0002 +}; + + + +struct __gconv_step; +struct __gconv_step_data; +struct __gconv_loaded_object; +struct __gconv_trans_data; + + + +typedef int (*__gconv_fct) (struct __gconv_step *, struct __gconv_step_data *, + __const unsigned char **, __const unsigned char *, + unsigned char **, size_t *, int, int); + + +typedef int (*__gconv_init_fct) (struct __gconv_step *); +typedef void (*__gconv_end_fct) (struct __gconv_step *); + + + +typedef int (*__gconv_trans_fct) (struct __gconv_step *, + struct __gconv_step_data *, void *, + __const unsigned char *, + __const unsigned char **, + __const unsigned char *, unsigned char **, + size_t *); + + +typedef int (*__gconv_trans_context_fct) (void *, __const unsigned char *, + __const unsigned char *, + unsigned char *, unsigned char *); + + +typedef int (*__gconv_trans_query_fct) (__const char *, __const char ***, + size_t *); + + +typedef int (*__gconv_trans_init_fct) (void **, const char *); +typedef void (*__gconv_trans_end_fct) (void *); + +struct __gconv_trans_data +{ + + __gconv_trans_fct __trans_fct; + __gconv_trans_context_fct __trans_context_fct; + __gconv_trans_end_fct __trans_end_fct; + void *__data; + struct __gconv_trans_data *__next; +}; + + + +struct __gconv_step +{ + struct __gconv_loaded_object *__shlib_handle; + __const char *__modname; + + int __counter; + + char *__from_name; + char *__to_name; + + __gconv_fct __fct; + __gconv_init_fct __init_fct; + __gconv_end_fct __end_fct; + + + + int __min_needed_from; + int __max_needed_from; + int __min_needed_to; + int __max_needed_to; + + + int __stateful; + + void *__data; +}; + + + +struct __gconv_step_data +{ + unsigned char *__outbuf; + unsigned char *__outbufend; + + + + int __flags; + + + + int __invocation_counter; + + + + int __internal_use; + + __mbstate_t *__statep; + __mbstate_t __state; + + + + struct __gconv_trans_data *__trans; +}; + + + +typedef struct __gconv_info +{ + size_t __nsteps; + struct __gconv_step *__steps; + __extension__ struct __gconv_step_data __data [0] ; +} *__gconv_t; + + + +typedef union +{ + struct __gconv_info __cd; + struct + { + struct __gconv_info __cd; + struct __gconv_step_data __data; + } __combined; +} _G_iconv_t; + +typedef int _G_int16_t __attribute__ ((__mode__ (__HI__))); +typedef int _G_int32_t __attribute__ ((__mode__ (__SI__))); +typedef unsigned int _G_uint16_t __attribute__ ((__mode__ (__HI__))); +typedef unsigned int _G_uint32_t __attribute__ ((__mode__ (__SI__))); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef void *__gnuc_va_list; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +struct _IO_jump_t; struct _IO_FILE; + + + +typedef void _IO_lock_t; + + + + + +struct _IO_marker { + struct _IO_marker *_next; + struct _IO_FILE *_sbuf; + + + + int _pos; + +}; + + +enum __codecvt_result +{ + __codecvt_ok, + __codecvt_partial, + __codecvt_error, + __codecvt_noconv +}; + + + +struct _IO_FILE { + int _flags; + + + + + char* _IO_read_ptr; + char* _IO_read_end; + char* _IO_read_base; + char* _IO_write_base; + char* _IO_write_ptr; + char* _IO_write_end; + char* _IO_buf_base; + char* _IO_buf_end; + + char *_IO_save_base; + char *_IO_backup_base; + char *_IO_save_end; + + struct _IO_marker *_markers; + + struct _IO_FILE *_chain; + + int _fileno; + int _blksize; + __off_t _old_offset; + + + + unsigned short _cur_column; + signed char _vtable_offset; + char _shortbuf[1]; + + + + _IO_lock_t *_lock; + + + __off64_t _offset; + + void *__pad1; + void *__pad2; + + int _mode; + + char _unused2[15 * sizeof (int) - 2 * sizeof (void *)]; + +}; + + + +struct _IO_FILE_plus; + +extern struct _IO_FILE_plus _IO_2_1_stdin_; +extern struct _IO_FILE_plus _IO_2_1_stdout_; +extern struct _IO_FILE_plus _IO_2_1_stderr_; + + + + + + + + + + + +typedef __ssize_t __io_read_fn (void *__cookie, char *__buf, size_t __nbytes); + + + + + + + +typedef __ssize_t __io_write_fn (void *__cookie, __const char *__buf, + size_t __n); + + + + + + + +typedef int __io_seek_fn (void *__cookie, __off64_t *__pos, int __w); + + +typedef int __io_close_fn (void *__cookie); + + + + + + +extern "C" { + + +extern int __underflow (_IO_FILE *) throw () ; +extern int __uflow (_IO_FILE *) throw () ; +extern int __overflow (_IO_FILE *, int) throw () ; +extern wint_t __wunderflow (_IO_FILE *) throw () ; +extern wint_t __wuflow (_IO_FILE *) throw () ; +extern wint_t __woverflow (_IO_FILE *, wint_t ) throw () ; + + + + + + + + + + + +extern int _IO_getc (_IO_FILE *__fp) throw () ; +extern int _IO_putc (int __c, _IO_FILE *__fp) throw () ; +extern int _IO_feof (_IO_FILE *__fp) throw () ; +extern int _IO_ferror (_IO_FILE *__fp) throw () ; + +extern int _IO_peekc_locked (_IO_FILE *__fp) throw () ; + + + + +extern void _IO_flockfile (_IO_FILE *) throw () ; +extern void _IO_funlockfile (_IO_FILE *) throw () ; +extern int _IO_ftrylockfile (_IO_FILE *) throw () ; + + + + + + + + + + +extern int _IO_vfscanf (_IO_FILE * __restrict, const char * __restrict, + __gnuc_va_list , int *__restrict) throw () ; +extern int _IO_vfprintf (_IO_FILE *__restrict, const char *__restrict, + __gnuc_va_list ) throw () ; +extern __ssize_t _IO_padn (_IO_FILE *, int, __ssize_t ) throw () ; +extern size_t _IO_sgetn (_IO_FILE *, void *, size_t ) throw () ; + +extern __off64_t _IO_seekoff (_IO_FILE *, __off64_t , int, int) throw () ; +extern __off64_t _IO_seekpos (_IO_FILE *, __off64_t , int) throw () ; + +extern void _IO_free_backup_area (_IO_FILE *) throw () ; + + + + +} + + + + + + + + + +typedef _G_fpos_t fpos_t; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern FILE *stdin; +extern FILE *stdout; +extern FILE *stderr; + + + + + + +extern int remove (__const char *__filename) throw () ; + +extern int rename (__const char *__old, __const char *__new) throw () ; + + + + +extern FILE *tmpfile (void) throw () ; + + + +extern char *tmpnam (char *__s) throw () ; + + + + +extern char *tmpnam_r (char *__s) throw () ; + + + + + + + + + + + +extern char *tempnam (__const char *__dir, __const char *__pfx) + throw () ; + + + + +extern int fclose (FILE *__stream) throw () ; + +extern int fflush (FILE *__stream) throw () ; + + + +extern int fflush_unlocked (FILE *__stream) throw () ; + + + + + + + +extern FILE *fopen (__const char *__restrict __filename, + __const char *__restrict __modes) throw () ; + +extern FILE *freopen (__const char *__restrict __filename, + __const char *__restrict __modes, + FILE *__restrict __stream) throw () ; + + + + + +extern FILE *fdopen (int __fd, __const char *__modes) throw () ; + + + + + + + +extern void setbuf (FILE *__restrict __stream, char *__restrict __buf) throw () ; + + + +extern int setvbuf (FILE *__restrict __stream, char *__restrict __buf, + int __modes, size_t __n) throw () ; + + + + +extern void setbuffer (FILE *__restrict __stream, char *__restrict __buf, + size_t __size) throw () ; + + +extern void setlinebuf (FILE *__stream) throw () ; + + + + +extern int fprintf (FILE *__restrict __stream, + __const char *__restrict __format, ...) throw () ; + +extern int printf (__const char *__restrict __format, ...) throw () ; + +extern int sprintf (char *__restrict __s, + __const char *__restrict __format, ...) throw () ; + + +extern int vfprintf (FILE *__restrict __s, __const char *__restrict __format, + __gnuc_va_list __arg) throw () ; + +extern int vprintf (__const char *__restrict __format, __gnuc_va_list __arg) + throw () ; + +extern int vsprintf (char *__restrict __s, __const char *__restrict __format, + __gnuc_va_list __arg) throw () ; + + + +extern int snprintf (char *__restrict __s, size_t __maxlen, + __const char *__restrict __format, ...) + throw () __attribute__ ((__format__ (__printf__, 3, 4))); + +extern int vsnprintf (char *__restrict __s, size_t __maxlen, + __const char *__restrict __format, __gnuc_va_list __arg) + throw () __attribute__ ((__format__ (__printf__, 3, 0))); + + + + + + +extern int fscanf (FILE *__restrict __stream, + __const char *__restrict __format, ...) throw () ; + +extern int scanf (__const char *__restrict __format, ...) throw () ; + +extern int sscanf (__const char *__restrict __s, + __const char *__restrict __format, ...) throw () ; + + + + + +extern int fgetc (FILE *__stream) throw () ; +extern int getc (FILE *__stream) throw () ; + + +extern int getchar (void) throw () ; + + + + + + + +extern int getc_unlocked (FILE *__stream) throw () ; +extern int getchar_unlocked (void) throw () ; + + + + +extern int fgetc_unlocked (FILE *__stream) throw () ; + + + + +extern int fputc (int __c, FILE *__stream) throw () ; +extern int putc (int __c, FILE *__stream) throw () ; + + +extern int putchar (int __c) throw () ; + + + + + + + +extern int fputc_unlocked (int __c, FILE *__stream) throw () ; + + + + +extern int putc_unlocked (int __c, FILE *__stream) throw () ; +extern int putchar_unlocked (int __c) throw () ; + + + + + +extern int getw (FILE *__stream) throw () ; + + +extern int putw (int __w, FILE *__stream) throw () ; + + + + +extern char *fgets (char *__restrict __s, int __n, FILE *__restrict __stream) + throw () ; + + + + + +extern char *gets (char *__s) throw () ; + + + + + + +extern int fputs (__const char *__restrict __s, FILE *__restrict __stream) + throw () ; + + + + +extern int puts (__const char *__s) throw () ; + + + +extern int ungetc (int __c, FILE *__stream) throw () ; + + + +extern size_t fread (void *__restrict __ptr, size_t __size, + size_t __n, FILE *__restrict __stream) throw () ; + +extern size_t fwrite (__const void *__restrict __ptr, size_t __size, + size_t __n, FILE *__restrict __s) throw () ; + + + +extern size_t fread_unlocked (void *__restrict __ptr, size_t __size, + size_t __n, FILE *__restrict __stream) throw () ; +extern size_t fwrite_unlocked (__const void *__restrict __ptr, size_t __size, + size_t __n, FILE *__restrict __stream) throw () ; + + + + +extern int fseek (FILE *__stream, long int __off, int __whence) throw () ; + +extern long int ftell (FILE *__stream) throw () ; + +extern void rewind (FILE *__stream) throw () ; + + + + + + + + + + +extern int fgetpos (FILE *__restrict __stream, fpos_t *__restrict __pos) + throw () ; + +extern int fsetpos (FILE *__stream, __const fpos_t *__pos) throw () ; + + + + + +extern void clearerr (FILE *__stream) throw () ; + +extern int feof (FILE *__stream) throw () ; + +extern int ferror (FILE *__stream) throw () ; + + + +extern void clearerr_unlocked (FILE *__stream) throw () ; +extern int feof_unlocked (FILE *__stream) throw () ; +extern int ferror_unlocked (FILE *__stream) throw () ; + + + + +extern void perror (__const char *__s) throw () ; + + + + +extern int sys_nerr; +extern __const char *__const sys_errlist[]; + + + + + + +extern int fileno (FILE *__stream) throw () ; + + + + +extern int fileno_unlocked (FILE *__stream) throw () ; + + + + + +extern FILE *popen (__const char *__command, __const char *__modes) throw () ; + + +extern int pclose (FILE *__stream) throw () ; + + + + + +extern char *ctermid (char *__s) throw () ; + + + + + + + + + + + + + +extern void flockfile (FILE *__stream) throw () ; + + + +extern int ftrylockfile (FILE *__stream) throw () ; + + +extern void funlockfile (FILE *__stream) throw () ; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +inline int +vprintf (__const char *__restrict __fmt, __gnuc_va_list __arg) throw () +{ + return vfprintf (stdout , __fmt, __arg); +} + + +inline int +getchar (void) throw () +{ + return _IO_getc (stdin ); +} + + + + +inline int +getc_unlocked (FILE *__fp) throw () +{ + return (( __fp )->_IO_read_ptr >= ( __fp )->_IO_read_end ? __uflow ( __fp ) : *(unsigned char *) ( __fp )->_IO_read_ptr++) ; +} + + +inline int +getchar_unlocked (void) throw () +{ + return (( stdin )->_IO_read_ptr >= ( stdin )->_IO_read_end ? __uflow ( stdin ) : *(unsigned char *) ( stdin )->_IO_read_ptr++) ; +} + + + + +inline int +putchar (int __c) throw () +{ + return _IO_putc (__c, stdout ); +} + + + + +inline int +fputc_unlocked (int __c, FILE *__stream) throw () +{ + return ((( __stream )->_IO_write_ptr >= ( __stream )->_IO_write_end) ? __overflow ( __stream , (unsigned char) ( __c )) : (unsigned char) (*( __stream )->_IO_write_ptr++ = ( __c ))) ; +} + + + + + +inline int +putc_unlocked (int __c, FILE *__stream) throw () +{ + return ((( __stream )->_IO_write_ptr >= ( __stream )->_IO_write_end) ? __overflow ( __stream , (unsigned char) ( __c )) : (unsigned char) (*( __stream )->_IO_write_ptr++ = ( __c ))) ; +} + + +inline int +putchar_unlocked (int __c) throw () +{ + return ((( stdout )->_IO_write_ptr >= ( stdout )->_IO_write_end) ? __overflow ( stdout , (unsigned char) ( __c )) : (unsigned char) (*( stdout )->_IO_write_ptr++ = ( __c ))) ; +} + + + + + + + + +inline int +feof_unlocked (FILE *__stream) throw () +{ + return ((( __stream )->_flags & 0x10 ) != 0) ; +} + + +inline int +ferror_unlocked (FILE *__stream) throw () +{ + return ((( __stream )->_flags & 0x20 ) != 0) ; +} + + + + + + + + + + + + + + + + + +} + + + + + + + +static void genrepl(const up_preamble &pre, upp_repl &repl) +{ + repl.size = 0; + repl.err_no = 0; + repl.isreq = 0 ; + repl.seq = pre.seq; + repl.op = pre.op; + repl.version = 16 ; +} + +int +Filesystem::DoOp(const up_preamble &pre, upp_repl &repl, Data *data) +{ + int err; + + ; + { int eq_ = (( pre.isreq == 2 ) || ( pre.isreq == 1 )); if (!eq_) { fprintf(stderr , "Check failed :""pre.isreq == UP_ENQ""(%d)""||""pre.isreq == UP_REQ""(%d)\n", ( pre.isreq == 2 ), ( pre.isreq == 1 )); } } ; + { int eq_ = (( pre.version ) == ( 16 )); if (!eq_) { fprintf(stderr , "Check failed :""pre.version""(%d)""==""UP_VERSION""(%d)\n", ( pre.version ), ( 16 )); } } ; + + genrepl(pre, repl); + + if (pre.isreq == 2 ) + { + repl.err_no = Enquire((up_ops)pre.op); + return 1; + } + + switch(pre.op) + { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +case up_mount : { ; upp_mount_r ret; err = do_mount (pre, repl, ret); if (!err) repl.size = encode_upp_mount_r(&ret, data) - data; break; } ; +case up_umount : ; err = do_umount (pre, repl); break; ; +case up_statfs : { ; upp_statfs_r ret; err = do_statfs (pre, repl, ret); if (!err) repl.size = encode_upp_statfs_r(&ret, data) - data; break; } ; + + + + + + + +case up_create : { ; upp_create_s arg; upp_create_r ret; decode_upp_create_s(&arg, data); err = do_create (pre, repl, arg, ret); if (!err) repl.size = encode_upp_create_r(&ret, data) - data; break; } ; +case up_lookup : { ; upp_lookup_s arg; upp_lookup_r ret; decode_upp_lookup_s(&arg, data); err = do_lookup (pre, repl, arg, ret); if (!err) repl.size = encode_upp_lookup_r(&ret, data) - data; break; } ; +case up_link : { ; upp_link_s arg; decode_upp_link_s(&arg, data); err = do_link (pre, repl, arg); break; } ; +case up_unlink : { ; upp_unlink_s arg; decode_upp_unlink_s(&arg, data); err = do_unlink (pre, repl, arg); break; } ; +case up_symlink : { ; upp_symlink_s arg; decode_upp_symlink_s(&arg, data); err = do_symlink (pre, repl, arg); break; } ; +case up_rename : { ; upp_rename_s arg; decode_upp_rename_s(&arg, data); err = do_rename (pre, repl, arg); break; } ; +case up_readlink : { ; upp_readlink_s arg; upp_readlink_r ret; decode_upp_readlink_s(&arg, data); err = do_readlink (pre, repl, arg, ret); if (!err) repl.size = encode_upp_readlink_r(&ret, data) - data; break; } ; +case up_followlink : { ; upp_followlink_s arg; upp_followlink_r ret; decode_upp_followlink_s(&arg, data); err = do_followlink (pre, repl, arg, ret); if (!err) repl.size = encode_upp_followlink_r(&ret, data) - data; break; } ; +case up_permission : { ; upp_permission_s arg; decode_upp_permission_s(&arg, data); err = do_permission (pre, repl, arg); break; } ; +case up_iwrite : { ; upp_iwrite_s arg; decode_upp_iwrite_s(&arg, data); err = do_iwrite (pre, repl, arg); break; } ; +case up_iread : { ; upp_iread_s arg; upp_iread_r ret; decode_upp_iread_s(&arg, data); err = do_iread (pre, repl, arg, ret); if (!err) repl.size = encode_upp_iread_r(&ret, data) - data; break; } ; +case up_iput : { ; upp_iput_s arg; decode_upp_iput_s(&arg, data); err = do_iput (pre, repl, arg); break; } ; +case up_notify_change : { ; upp_notify_change_s arg; decode_upp_notify_change_s(&arg, data); err = do_notify_change (pre, repl, arg); break; } ; +case up_truncate : { ; upp_truncate_s arg; decode_upp_truncate_s(&arg, data); err = do_truncate (pre, repl, arg); break; } ; +case up_inode_valid : { ; upp_inode_valid_s arg; upp_inode_valid_r ret; decode_upp_inode_valid_s(&arg, data); err = do_inode_valid (pre, repl, arg, ret); if (!err) repl.size = encode_upp_inode_valid_r(&ret, data) - data; break; } ; + + + + + + + +case up_read : { ; upp_read_s arg; upp_read_r ret; decode_upp_read_s(&arg, data); err = do_read (pre, repl, arg, ret); if (!err) repl.size = encode_upp_read_r(&ret, data) - data; break; } ; +case up_write : { ; upp_write_s arg; upp_write_r ret; decode_upp_write_s(&arg, data); err = do_write (pre, repl, arg, ret); if (!err) repl.size = encode_upp_write_r(&ret, data) - data; break; } ; +case up_readdir : { ; upp_readdir_s arg; upp_readdir_r ret; decode_upp_readdir_s(&arg, data); err = do_readdir (pre, repl, arg, ret); if (!err) repl.size = encode_upp_readdir_r(&ret, data) - data; break; } ; +case up_multireaddir : { ; upp_multireaddir_s arg; upp_multireaddir_r ret; decode_upp_multireaddir_s(&arg, data); err = do_multireaddir (pre, repl, arg, ret); if (!err) repl.size = encode_upp_multireaddir_r(&ret, data) - data; break; } ; +case up_open : { ; upp_open_s arg; upp_open_r ret; decode_upp_open_s(&arg, data); err = do_open (pre, repl, arg, ret); if (!err) repl.size = encode_upp_open_r(&ret, data) - data; break; } ; +case up_close : { ; upp_close_s arg; decode_upp_close_s(&arg, data); err = do_close (pre, repl, arg); break; } ; + + + + + + + + + + + + default: + err = 38 ; + break; + } + + if (err == -1) + return -1; + + if (err != 0) + { + { int eq_ = (( (int)repl.size ) == ( 0 )); if (!eq_) { fprintf(stderr , "Check failed :""(int)repl.size""(%d)""==""0""(%d)\n", ( (int)repl.size ), ( 0 )); } } ; + repl.size = 0; + repl.err_no = err; + } + + return 1; +} + +int +Filesystem::Enquire(up_ops) +{ + return 38 ; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +int Filesystem::do_mount (const up_preamble &, upp_repl &, upp_mount_r &) { return 38 ; } ; +int Filesystem::do_umount (const up_preamble &, upp_repl &) { return 38 ; } ; +int Filesystem::do_statfs (const up_preamble &, upp_repl &, upp_statfs_r &) { return 38 ; } ; + + + + + + + + + + + + + + + + + + + + + +int Filesystem::do_create (const up_preamble &pre, upp_repl &repl, const upp_create_s &arg, upp_create_r &ret) { ; Inode *ino = inodes.find(arg. dir .handle); if (ino == __null ) return 22 ; ino->beforeop(up_create ); int r = ino->do_create (pre, repl, arg, ret); ino->afterop(up_create ); return r; } ; +int Filesystem::do_lookup (const up_preamble &pre, upp_repl &repl, const upp_lookup_s &arg, upp_lookup_r &ret) { ; Inode *ino = inodes.find(arg. dir .handle); if (ino == __null ) return 22 ; ino->beforeop(up_lookup ); int r = ino->do_lookup (pre, repl, arg, ret); ino->afterop(up_lookup ); return r; } ; +int Filesystem::do_link (const up_preamble &pre, upp_repl &repl, const upp_link_s &arg) { ; Inode *ino = inodes.find(arg. dir .handle); if (ino == __null ) return 22 ; ino->beforeop(up_link ); int ret = ino->do_link (pre, repl, arg); ino->afterop(up_link ); return ret; } ; +int Filesystem::do_unlink (const up_preamble &pre, upp_repl &repl, const upp_unlink_s &arg) { ; Inode *ino = inodes.find(arg. dir .handle); if (ino == __null ) return 22 ; ino->beforeop(up_unlink ); int ret = ino->do_unlink (pre, repl, arg); ino->afterop(up_unlink ); return ret; } ; +int Filesystem::do_symlink (const up_preamble &pre, upp_repl &repl, const upp_symlink_s &arg) { ; Inode *ino = inodes.find(arg. dir .handle); if (ino == __null ) return 22 ; ino->beforeop(up_symlink ); int ret = ino->do_symlink (pre, repl, arg); ino->afterop(up_symlink ); return ret; } ; +int Filesystem::do_rename (const up_preamble &pre, upp_repl &repl, const upp_rename_s &arg) { ; Inode *ino = inodes.find(arg. odir .handle); if (ino == __null ) return 22 ; ino->beforeop(up_rename ); int ret = ino->do_rename (pre, repl, arg); ino->afterop(up_rename ); return ret; } ; +int Filesystem::do_readlink (const up_preamble &pre, upp_repl &repl, const upp_readlink_s &arg, upp_readlink_r &ret) { ; Inode *ino = inodes.find(arg. link .handle); if (ino == __null ) return 22 ; ino->beforeop(up_readlink ); int r = ino->do_readlink (pre, repl, arg, ret); ino->afterop(up_readlink ); return r; } ; +int Filesystem::do_followlink (const up_preamble &pre, upp_repl &repl, const upp_followlink_s &arg, upp_followlink_r &ret) { ; Inode *ino = inodes.find(arg. link .handle); if (ino == __null ) return 22 ; ino->beforeop(up_followlink ); int r = ino->do_followlink (pre, repl, arg, ret); ino->afterop(up_followlink ); return r; } ; +int Filesystem::do_permission (const up_preamble &pre, upp_repl &repl, const upp_permission_s &arg) { ; Inode *ino = inodes.find(arg. file .handle); if (ino == __null ) return 22 ; ino->beforeop(up_permission ); int ret = ino->do_permission (pre, repl, arg); ino->afterop(up_permission ); return ret; } ; +int Filesystem::do_iwrite (const up_preamble &pre, upp_repl &repl, const upp_iwrite_s &arg) { ; Inode *ino = inodes.find(arg. handle .handle); if (ino == __null ) return 22 ; ino->beforeop(up_iwrite ); int ret = ino->do_iwrite (pre, repl, arg); ino->afterop(up_iwrite ); return ret; } ; +int Filesystem::do_iread (const up_preamble &pre, upp_repl &repl, const upp_iread_s &arg, upp_iread_r &ret) { ; Inode *ino = inodes.find(arg. handle .handle); if (ino == __null ) return 22 ; ino->beforeop(up_iread ); int r = ino->do_iread (pre, repl, arg, ret); ino->afterop(up_iread ); return r; } ; +int Filesystem::do_notify_change (const up_preamble &pre, upp_repl &repl, const upp_notify_change_s &arg) { ; Inode *ino = inodes.find(arg. handle .handle); if (ino == __null ) return 22 ; ino->beforeop(up_notify_change ); int ret = ino->do_notify_change (pre, repl, arg); ino->afterop(up_notify_change ); return ret; } ; +int Filesystem::do_iput (const up_preamble &pre, upp_repl &repl, const upp_iput_s &arg) { ; Inode *ino = inodes.find(arg. handle .handle); if (ino == __null ) return 22 ; ino->beforeop(up_iput ); int ret = ino->do_iput (pre, repl, arg); ino->afterop(up_iput ); return ret; } ; + +int Filesystem::do_read (const up_preamble &pre, upp_repl &repl, const upp_read_s &arg, upp_read_r &ret) { ; Inode *ino = inodes.find(arg. file .handle); if (ino == __null ) return 22 ; ino->beforeop(up_read ); int r = ino->do_read (pre, repl, arg, ret); ino->afterop(up_read ); return r; } ; +int Filesystem::do_write (const up_preamble &pre, upp_repl &repl, const upp_write_s &arg, upp_write_r &ret) { ; Inode *ino = inodes.find(arg. file .handle); if (ino == __null ) return 22 ; ino->beforeop(up_write ); int r = ino->do_write (pre, repl, arg, ret); ino->afterop(up_write ); return r; } ; +int Filesystem::do_readdir (const up_preamble &pre, upp_repl &repl, const upp_readdir_s &arg, upp_readdir_r &ret) { ; Inode *ino = inodes.find(arg. dir .handle); if (ino == __null ) return 22 ; ino->beforeop(up_readdir ); int r = ino->do_readdir (pre, repl, arg, ret); ino->afterop(up_readdir ); return r; } ; +int Filesystem::do_multireaddir (const up_preamble &pre, upp_repl &repl, const upp_multireaddir_s &arg, upp_multireaddir_r &ret) { ; Inode *ino = inodes.find(arg. dir .handle); if (ino == __null ) return 22 ; ino->beforeop(up_multireaddir ); int r = ino->do_multireaddir (pre, repl, arg, ret); ino->afterop(up_multireaddir ); return r; } ; +int Filesystem::do_open (const up_preamble &pre, upp_repl &repl, const upp_open_s &arg, upp_open_r &ret) { ; Inode *ino = inodes.find(arg. file .handle); if (ino == __null ) return 22 ; ino->beforeop(up_open ); int r = ino->do_open (pre, repl, arg, ret); ino->afterop(up_open ); return r; } ; +int Filesystem::do_close (const up_preamble &pre, upp_repl &repl, const upp_close_s &arg) { ; Inode *ino = inodes.find(arg. file .handle); if (ino == __null ) return 22 ; ino->beforeop(up_close ); int ret = ino->do_close (pre, repl, arg); ino->afterop(up_close ); return ret; } ; +int Filesystem::do_truncate (const up_preamble &pre, upp_repl &repl, const upp_truncate_s &arg) { ; Inode *ino = inodes.find(arg. file .handle); if (ino == __null ) return 22 ; ino->beforeop(up_truncate ); int ret = ino->do_truncate (pre, repl, arg); ino->afterop(up_truncate ); return ret; } ; +int Filesystem::do_inode_valid (const up_preamble &pre, upp_repl &repl, const upp_inode_valid_s &arg, upp_inode_valid_r &ret) { ; Inode *ino = inodes.find(arg. handle .handle); if (ino == __null ) return 22 ; ino->beforeop(up_inode_valid ); int r = ino->do_inode_valid (pre, repl, arg, ret); ino->afterop(up_inode_valid ); return r; } ; Added: trunk/lib/dbg.h ============================================================================== --- trunk/lib/dbg.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/lib/dbg.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,11 @@ +// -*- C++ -*- +// Just a stub + +#ifdef DEBUG +#include +#define LOG(x) fprintf(stderr, __FILE__":%d: %s\n", __LINE__, x) +#define DB(x) x +#else +#define LOG(x) +#define DB(x) +#endif Added: trunk/lib/coder.h ============================================================================== --- trunk/lib/coder.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/lib/coder.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,283 @@ +/* Base type primitives */ + +#ifndef __CODER_H_SEEN__ +#define __CODER_H_SEEN__ + +#ifndef __GNUC__ +#define __inline__ /* */ +#endif + +#ifndef __cplusplus +#ifndef ALLOC +extern void *malloc(unsigned long); +extern void free(void *); +#define ALLOC(s) malloc(s) +#define FREE(s) free(s) +#endif /* ALLOC */ +#endif __cplusplus + +/* Types we use */ +typedef unsigned char Uchar; +typedef unsigned short Ushort; +typedef unsigned long Ulong; +typedef unsigned long Uint; +typedef unsigned long long Ulonglong; +typedef long long longlong; + +/** char **/ +__inline__ static unsigned char *encode_char(const char *ch, unsigned char *buf) +{ + *buf = *ch; + return buf+1; +} + +__inline__ static unsigned char *decode_char(char *ch, unsigned char *buf) +{ + *ch = *buf; + return buf+1; +} + +__inline__ static unsigned int sizeof_char(const char *c) +{ + (void)c; + return 1; +} + +/** unsigned char **/ +__inline__ static unsigned char *encode_Uchar(const Uchar *ch, unsigned char *buf) +{ + *buf = *ch; + return buf+1; +} + +__inline__ static unsigned char *decode_Uchar(Uchar *ch, unsigned char *buf) +{ + *ch = *buf; + return buf+1; +} + +__inline__ static unsigned int sizeof_Uchar(const Uchar *c) +{ + (void)c; + return 1; +} + +/** short **/ +__inline__ static unsigned char *encode_short(const short *sh, unsigned char *buf) +{ + register short sv = *sh; + + buf[0] = (sv >> 8)& 0xff; + buf[1] = sv & 0xff; + return buf+2; +} + +__inline__ static unsigned char *decode_short(short *sh, unsigned char *buf) +{ + *sh = (buf[0] << 8) | buf[1]; + return buf+2; +} + +__inline__ static unsigned int sizeof_short(const short *c) +{ + (void)c; + return 2; +} + +/** unsigned short **/ +__inline__ static unsigned char *encode_Ushort(const Ushort *sh, unsigned char *buf) +{ + register Ushort sv = *sh; + + buf[0] = (sv >> 8)& 0xff; + buf[1] = sv & 0xff; + return buf+2; +} + +__inline__ static unsigned char *decode_Ushort(Ushort *sh, unsigned char *buf) +{ + *sh = (buf[0] << 8) | buf[1]; + return buf+2; +} + +__inline__ static unsigned int sizeof_Ushort(const Ushort *c) +{ + (void)c; + return 2; +} + +/** long **/ +__inline__ static unsigned char *encode_long(const long *l, unsigned char *buf) +{ + register long lv = *l; + + buf[0] = (lv >> 24) & 0xff; + buf[1] = (lv >> 16) & 0xff; + buf[2] = (lv >> 8) & 0xff; + buf[3] = lv & 0xff; + return buf+4; +} + +__inline__ static unsigned char *decode_long(long *l, unsigned char *buf) +{ + *l = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + return buf+4; +} + +__inline__ static unsigned int sizeof_long(const long *c) +{ + (void)c; + return 4; +} + +/** unsigned long **/ +__inline__ static unsigned char *encode_Ulong(const Ulong *l, unsigned char *buf) +{ + register Ulong lv = *l; + + buf[0] = (lv >> 24) & 0xff; + buf[1] = (lv >> 16) & 0xff; + buf[2] = (lv >> 8) & 0xff; + buf[3] = lv & 0xff; + return buf+4; +} + +__inline__ static unsigned char *decode_Ulong(Ulong *l, unsigned char *buf) +{ + *l = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + return buf+4; +} + +__inline__ static unsigned int sizeof_Ulong(const Ulong *c) +{ + (void)c; + return 4; +} + +/** long long */ +__inline__ static unsigned char *encode_longlong(const long long *l, + unsigned char *buf) +{ + register long long lv = *l; + + buf[0] = (lv >> 56) & 0xff; + buf[1] = (lv >> 48) & 0xff; + buf[2] = (lv >> 40) & 0xff; + buf[3] = (lv >> 32) & 0xff; + buf[4] = (lv >> 24) & 0xff; + buf[5] = (lv >> 16) & 0xff; + buf[6] = (lv >> 8) & 0xff; + buf[7] = lv & 0xff; + + return buf+8; +} + +__inline__ static unsigned char *decode_longlong(long long *l, + unsigned char *buf) +{ +#define BUF(x) ((long long)(buf[x])) + *l = (BUF(0) << 56)|(BUF(1) << 48)|(BUF(2) << 40)|(BUF(3) << 32)| + (BUF(4) << 24)|(BUF(5) << 16)|(BUF(6) << 8)|BUF(7); +#undef BUF + return buf+8; +} + +__inline__ static unsigned int sizeof_longlong(const long long *c) +{ + (void)c; + return 8; +} + +/** unsigned long long */ +__inline__ static unsigned char *encode_Ulonglong(const unsigned long long *l, + unsigned char *buf) +{ + register unsigned long long lv = *l; + + buf[0] = (lv >> 56) & 0xff; + buf[1] = (lv >> 48) & 0xff; + buf[2] = (lv >> 40) & 0xff; + buf[3] = (lv >> 32) & 0xff; + buf[4] = (lv >> 24) & 0xff; + buf[5] = (lv >> 16) & 0xff; + buf[6] = (lv >> 8) & 0xff; + buf[7] = lv & 0xff; + + return buf+8; +} + +__inline__ static unsigned char *decode_Ulonglong(unsigned long long *l, + unsigned char *buf) +{ +#define BUF(x) ((unsigned long long)(buf[x])) + *l = (BUF(0) << 56)|(BUF(1) << 48)|(BUF(2) << 40)|(BUF(3) << 32)| + (BUF(4) << 24)|(BUF(5) << 16)|(BUF(6) << 8)|BUF(7); +#undef BUF + return buf+8; +} + +__inline__ static unsigned int sizeof_Ulonglong(const unsigned long long *c) +{ + (void)c; + return 8; +} + +/** void **/ +__inline__ static unsigned char *encode_void(const void *v, unsigned char *buf) +{ + (void)v; + return buf; +} + +__inline__ static unsigned char *decode_void(void *v, unsigned char *buf) +{ + (void)v; + return buf; +} + +__inline__ static unsigned int sizeof_void(const void *c) +{ + (void)c; + return 0; +} + +/* Assuming this host has IEEE 754 floats, this is all OK */ +/** float **/ +__inline__ static unsigned char *encode_float(const float *f, unsigned char *buf) +{ + *(float *)buf = *f; + return buf + sizeof(float); +} + +__inline__ static unsigned char *decode_float(float *f, unsigned char *buf) +{ + *f = *(float *)buf; + return buf + sizeof(float); +} + +__inline__ static unsigned int sizeof_float(const float *c) +{ + (void)c; + return sizeof(float); +} + +/** double **/ +__inline__ static unsigned char *encode_double(const double *d, unsigned char *buf) +{ + *(double *)buf = *d; + return buf + sizeof(double); +} + +__inline__ static unsigned char *decode_double(double *d, unsigned char *buf) +{ + *d = *(double *)buf; + return buf + sizeof(double); +} + +__inline__ static unsigned int sizeof_double(const double *c) +{ + (void)c; + return sizeof(double); +} + +#endif /* __CODER_H_SEEN__ */ Added: trunk/lib/Inode.cc ============================================================================== --- trunk/lib/Inode.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/lib/Inode.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,127 @@ +// -*- C++ -*- +// Inode handling class +// +// This program is distributed under the terms of the +// Free Software Foundation General Public Licence. +// Copyright Jeremy Fitzhardinge 1993 + +#pragma implementation + +#include "Inode.h" +#include "Filesystem.h" + +#include + +InodeList::InodeList() +{ + list = NULL; +} + +InodeList::~InodeList() +{ + Inode *next; + + for(next = list; next != NULL; next = next->next) + next->cleanup(); + + for(; list != NULL; list = next) + { + next = list->next; + delete list; + } +} + +void +InodeList::add(Inode *ino) +{ + if (ino->onlist) + { + fprintf(stderr, "Adding %p onto list again\n", ino); + return; + } + ino->next = list; + ino->prev = NULL; + if (ino->next) + ino->next->prev = ino; + list = ino; + ino->onlist = 1; +} + +void +InodeList::del(Inode *ino) +{ + if (!ino->onlist) + return; + if (ino->prev) + ino->prev->next = ino->next; + else + list = ino->next; + if (ino->next) + ino->next->prev = ino->prev; + ino->onlist = 0; +} + +Inode * +InodeList::find(Handle hand) +{ + Inode *ino; + + for(ino = list; ino != NULL; ino = ino->next) + if (ino->handle == hand) + break; + + if (ino == NULL) + return NULL; + + // Move to head of list + del(ino); + add(ino); + + return ino; +} + +Inode::Inode(Filesystem &fs, Handle hand) + :next(NULL),prev(NULL),nlink(0),handle(hand),filesys(fs) +{ + alive = 1; + onlist = 0; + filesys.inodes.add(this); +} + +Inode::~Inode() +{ + if (!alive) + fprintf(stderr, "Inode %p already dead!\n", this); + filesys.inodes.del(this); + alive = 0; +} + +Inode * +Inode::findino(Handle h) +{ + return filesys.inodes.find(h); +} + +#if 0 +void +Inode::iread(up_inode &ino) +{ + ino.uid = uid; + ino.gid = gid; + ino.mode = mode; + ino.nlink = nlink; + ino.mtime = mtime; + ino.ctime = ctime; + ino.atime = atime; + ino.size = size; +} +#endif + +#define DO(op) int Inode::do_##op(const up_preamble &, upp_repl &) { return ENOSYS; } +#define DOa(op) int Inode::do_##op(const up_preamble &, upp_repl &, const upp_##op##_s &) { return ENOSYS; } +#define DOr(op) int Inode::do_##op(const up_preamble &, upp_repl &, upp_##op##_r &) { return ENOSYS; } +#define DOar(op) int Inode::do_##op(const up_preamble &, upp_repl &, const upp_##op##_s &, upp_##op##_r &) { return ENOSYS; } +#define opFILE +#define opINODE +#include "operations.h" + Added: trunk/lib/DirInode.h ============================================================================== --- trunk/lib/DirInode.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/lib/DirInode.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,81 @@ +// -*- C++ -*- + +/* Copyright (C) 1993 Tuomas J. Lukka, based on Jeremy Fitzhardinge's work */ +// Further modified by Jeremy as a general Directory Inode. +// This program is distributed under the terms of the +// Free Software Foundation General Public Licence. +// See COPYING for details + +// A directory inode + +#ifndef __DIRINODE_H_SEEN__ +#define __DIRINODE_H_SEEN__ + +#include + +#include +#include + +#pragma interface + +class Filesystem; +class DirInode; + +class DirEntry +{ + friend DirInode; + string name; + Inode *ino; // NULL if none + + DirEntry *prev, *next; + +public: + DirEntry(const string, Inode *); + DirEntry() { ino = NULL; } + ~DirEntry(); + + const string getname() const { return name; } + Inode *geti() const { return ino; } +}; + +class DirInode : public SimpleInode +{ +private: + int max_multird; + DirEntry *entries, *end; + +protected: + Inode *parent; + +public: + DirInode(Filesystem &fs, Handle h, Inode *parent, int mm = 100); + ~DirInode(); + + // Userfs operations + int do_lookup(const up_preamble &, upp_repl &, + const upp_lookup_s &, upp_lookup_r &); + int do_readdir(const up_preamble &, upp_repl &, + const upp_readdir_s &, upp_readdir_r &); + int do_multireaddir(const up_preamble &, upp_repl &, + const upp_multireaddir_s &, upp_multireaddir_r &); + int do_rename(const up_preamble &, upp_repl &, + const upp_rename_s &); + int do_unlink(const up_preamble &, upp_repl &, + const upp_unlink_s &arg); + int do_link(const up_preamble &, upp_repl &, + const upp_link_s &); + int do_read(const up_preamble &, upp_repl &, + const upp_read_s &, upp_read_r &); + int do_write(const up_preamble &, upp_repl &, + const upp_write_s &, upp_write_r &); + + // Inode operations + int link(const string &, Inode *); + DirEntry *lookup(const string &) const; + int unlink(const string &); + DirEntry *scan(int &pos) const; + DirEntry *scan(DirEntry *&pos) const; + int link(const char *n, int l, Inode *i) { return link(string(n, l), i); } + int unlink(const char *n, int l) { return unlink(string(n, l)); } +}; +#endif Added: trunk/lib/DeferComm.cc ============================================================================== --- trunk/lib/DeferComm.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/lib/DeferComm.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,205 @@ +// -*- C++ -*- + +// Cope with deferred replies in the form of sub-processes + +#pragma implementation + +#include +#include +#include + +#include "DeferComm.h" +#include "DeferFilesys.h" +#include "io.h" + +class Defer_doreq: public Comm_doreq +{ + int deferred; + + int dispatch(int fd, int flag); +public: + Defer_doreq(const CommBase *, Filesystem &); + void defer(int fd); +}; + +class copy : public DispToKern +{ +public: + copy(const CommBase *); + int dispatch(int fd, int); +}; + +copy::copy(const CommBase *c) + :DispToKern(c) +{ +} + +int +copy::dispatch(int from, int) +{ + int rd; + char buf[1024]; + + again: + while((rd = read(from, buf, sizeof(buf))) > 0) + { + char *wrp = buf; + + while(rd > 0) + { + int wr = write(tokern, wrp, rd); + + if (wr == -1 && errno == EINTR) + continue; + + if (wr == -1 || wr == 0) + return -1; + wrp += wr; + rd -= wr; + } + } + + if (rd == -1) + { + if (errno == EINTR) + goto again; + return -1; + } + + return 0; +} + +DeferComm::DeferComm(DeferFilesys &fs, unsigned int to, unsigned int from) + :CommBase(fs, to, from),filesys(fs) +{ + req = ourreq = new Defer_doreq(this, filesys); + addDispatch(from, req); + fs.setcomm(this); +} + +// This can be (indirectly) called by filesystem methods so they +// can defer replying until later, allowing the filesystem to be +// used by other processes in the meantime. This would happen, +// for example, if a read takes a long time to generate and the +// filesystem should be available for directory scans and name +// lookups. +// The function uses fork(); the parent returns so the main +// filesystem process can keep accepting requests. The child +// works away and sends the reply when its ready. This goes +// through a pipe from the child to the parent for copying +// to the kernel in one piece. Everything is set up so the +// Comm class in the child knows what to do, and exits when +// done. +int +DeferComm::DeferRepl() +{ + int p[2]; + int pid; + + if (pipe(p) == -1) + { + perror("DeferComm::DeferRepl pipe() failed"); + return -1; + } + + switch(pid = fork()) + { + case -1: + perror("DeferComm::DeferRepl fork() failed"); + return -1; + case 0: + CloseFDs(0); + ourreq->defer(p[1]); + ::close(p[0]); + break; + default: + ::close(p[1]); + addDispatch(p[0], new copy(this)); + break; + } + + return pid; +} + +DispatchFD * +DeferComm::kern_disp() +{ + return req; +} + +Defer_doreq::Defer_doreq(const CommBase *comm, Filesystem &fs) + : Comm_doreq(comm, fs) +{ + deferred = 0; +} + +// Process a request from the kernel +// Returns 0 on EOF, -1 on error and 1 for OK +int +Defer_doreq::dispatch(int fd, int) +{ + up_preamble pre; + size_t presize = sizeof_up_preamble(&pre); + Uchar hbuf[256]; + Uchar buf[4096]; + int ret; + + ret = fullread(fd, hbuf, presize); + if (ret == 0) + return 0; + + if (ret != (int)presize) + { + fprintf(stderr, "Defer_doreq::dispatch failed to get whole header (%d wanted, %d got)\n", + presize, ret); + return -1; + } + + upp_repl repl; + size_t replsize = sizeof_upp_repl(&repl); + + assert(sizeof(hbuf) > replsize); + + decode_up_preamble(&pre, hbuf); + + if (pre.size != 0 && (ret = fullread(fd, buf, pre.size)) != (int)pre.size) + { + fprintf(stderr, "Defer_doreq::dispatch: failed to get whole body (%li wanted, %d got)\n", + pre.size, ret); + return -1; + } + + ret = filesys.DoOp(pre, repl, buf); + + if (ret == -1 && !deferred) + return 1; + + if (!ret) + return -1; + +#ifdef DEBUG + if (repl.errno != 0) + { + fprintf(stderr, "Request %d failing with %d %s\n", + pre.op, repl.errno, strerror(repl.errno)); + } +#endif + + encode_upp_repl(&repl, hbuf); + + if (fullwrite(tokern, hbuf, replsize) != replsize) + return -1; + + if (repl.size != 0 && fullwrite(tokern, buf, repl.size) != repl.size) + return -1; + + return deferred ? 0 : 1; +} + +void +Defer_doreq::defer(int fd) +{ + ::close(tokern); + tokern = fd; + deferred = 1; +} Added: trunk/lib/DeferComm.h ============================================================================== --- trunk/lib/DeferComm.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/lib/DeferComm.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,24 @@ +// -*- C++ -*- + +// Deferred reply Comm class + +#ifndef _DEFERCOMM_H_ +#define _DEFERCOMM_H_ + +#pragma interface + +#include "Comm.h" + +class DeferComm : public CommBase +{ + class Defer_doreq *ourreq; + DispatchFD *kern_disp(); + + class DeferFilesys &filesys; + +public: + DeferComm(class DeferFilesys &, unsigned int to, unsigned int from); + int DeferRepl(); +}; + +#endif /* _DEFERCOMM_H_ */ Added: trunk/lib/Inode.p ============================================================================== --- trunk/lib/Inode.p 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/lib/Inode.p 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,7911 @@ + + + + + + + +#pragma implementation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef enum +{ + userfs_up_create, + userfs_up_lookup, + userfs_up_close, + userfs_up_read, + userfs_up_write, + userfs_up_truncate, + userfs_up_fsync, + userfs_up_readdir, + userfs_up_link, + userfs_up_unlink, + userfs_up_symlink, + userfs_up_readlink, + userfs_up_followlink, + userfs_up_mount, + userfs_up_umount, + userfs_up_iread, + userfs_up_iwrite, + userfs_up_statfs, + userfs_up_iput, + userfs_up_open, + userfs_up_permission, + userfs_up_rename, + userfs_up_multireaddir, + userfs_up_notify_change, + userfs_up_inode_valid, +} up_ops; + + + + + + + + + + + + + + + + + + + + + + + + +#pragma interface "userfs_types" + + + + + + + + + + + + +typedef unsigned short __kernel_dev_t; +typedef unsigned long __kernel_ino_t; +typedef unsigned short __kernel_mode_t; +typedef unsigned short __kernel_nlink_t; +typedef long __kernel_off_t; +typedef int __kernel_pid_t; +typedef unsigned short __kernel_ipc_pid_t; +typedef unsigned short __kernel_uid_t; +typedef unsigned short __kernel_gid_t; +typedef unsigned int __kernel_size_t; +typedef int __kernel_ssize_t; +typedef int __kernel_ptrdiff_t; +typedef long __kernel_time_t; +typedef long __kernel_suseconds_t; +typedef long __kernel_clock_t; +typedef int __kernel_daddr_t; +typedef char * __kernel_caddr_t; +typedef unsigned short __kernel_uid16_t; +typedef unsigned short __kernel_gid16_t; +typedef unsigned int __kernel_uid32_t; +typedef unsigned int __kernel_gid32_t; + +typedef unsigned short __kernel_old_uid_t; +typedef unsigned short __kernel_old_gid_t; + + +typedef long long __kernel_loff_t; + + +typedef struct { + + int __val[2]; + +} __kernel_fsid_t; + + + + + + + + + + + + + + + + + + + + + + +typedef unsigned short umode_t; + + + + + + +typedef __signed__ char __s8; +typedef unsigned char __u8; + +typedef __signed__ short __s16; +typedef unsigned short __u16; + +typedef __signed__ int __s32; +typedef unsigned int __u32; + + +typedef __signed__ long long __s64; +typedef unsigned long long __u64; + + + + + + + + + +typedef __kernel_suseconds_t suseconds_t; +typedef __u8 uint8_t; +typedef __u16 uint16_t; +typedef __u32 uint32_t; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern "C" { + + +extern void __assert_fail (__const char *__assertion, __const char *__file, + unsigned int __line, __const char *__function) + throw () __attribute__ ((__noreturn__)); + + +extern void __assert_perror_fail (int __errnum, __const char *__file, + unsigned int __line, + __const char *__function) + throw () __attribute__ ((__noreturn__)); + + + + +extern void __assert (const char *__assertion, const char *__file, int __line) + throw () __attribute__ ((__noreturn__)); + + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef unsigned int size_t; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern "C" { + + + + + + + +typedef struct + { + int quot; + int rem; + } div_t; + + + +typedef struct + { + long int quot; + long int rem; + } ldiv_t; + + + + + + + + + + + + + + + + + + +extern size_t __ctype_get_mb_cur_max (void) throw () ; + + + +extern double atof (__const char *__nptr) throw () ; + +extern int atoi (__const char *__nptr) throw () ; + +extern long int atol (__const char *__nptr) throw () ; + + + +__extension__ extern long long int atoll (__const char *__nptr) + throw () ; + + + +extern double strtod (__const char *__restrict __nptr, + char **__restrict __endptr) throw () ; + + + + +extern long int strtol (__const char *__restrict __nptr, + char **__restrict __endptr, int __base) throw () ; + +extern unsigned long int strtoul (__const char *__restrict __nptr, + char **__restrict __endptr, int __base) + throw () ; + + + +__extension__ +extern long long int strtoq (__const char *__restrict __nptr, + char **__restrict __endptr, int __base) throw () ; + +__extension__ +extern unsigned long long int strtouq (__const char *__restrict __nptr, + char **__restrict __endptr, int __base) + throw () ; + + + + + + +__extension__ +extern long long int strtoll (__const char *__restrict __nptr, + char **__restrict __endptr, int __base) throw () ; + +__extension__ +extern unsigned long long int strtoull (__const char *__restrict __nptr, + char **__restrict __endptr, int __base) + throw () ; + + + + + + + + + +extern double __strtod_internal (__const char *__restrict __nptr, + char **__restrict __endptr, int __group) + throw () ; +extern float __strtof_internal (__const char *__restrict __nptr, + char **__restrict __endptr, int __group) + throw () ; +extern long double __strtold_internal (__const char *__restrict __nptr, + char **__restrict __endptr, + int __group) throw () ; + +extern long int __strtol_internal (__const char *__restrict __nptr, + char **__restrict __endptr, + int __base, int __group) throw () ; + + + +extern unsigned long int __strtoul_internal (__const char *__restrict __nptr, + char **__restrict __endptr, + int __base, int __group) throw () ; + + + + +__extension__ +extern long long int __strtoll_internal (__const char *__restrict __nptr, + char **__restrict __endptr, + int __base, int __group) throw () ; + + + +__extension__ +extern unsigned long long int __strtoull_internal (__const char * + __restrict __nptr, + char **__restrict __endptr, + int __base, int __group) + throw () ; + + + + + + + +extern __inline double +strtod (__const char *__restrict __nptr, char **__restrict __endptr) throw () +{ + return __strtod_internal (__nptr, __endptr, 0); +} +extern __inline long int +strtol (__const char *__restrict __nptr, char **__restrict __endptr, + int __base) throw () +{ + return __strtol_internal (__nptr, __endptr, __base, 0); +} +extern __inline unsigned long int +strtoul (__const char *__restrict __nptr, char **__restrict __endptr, + int __base) throw () +{ + return __strtoul_internal (__nptr, __endptr, __base, 0); +} + + + + +__extension__ extern __inline long long int +strtoq (__const char *__restrict __nptr, char **__restrict __endptr, + int __base) throw () +{ + return __strtoll_internal (__nptr, __endptr, __base, 0); +} +__extension__ extern __inline unsigned long long int +strtouq (__const char *__restrict __nptr, char **__restrict __endptr, + int __base) throw () +{ + return __strtoull_internal (__nptr, __endptr, __base, 0); +} + + + +__extension__ extern __inline long long int +strtoll (__const char *__restrict __nptr, char **__restrict __endptr, + int __base) throw () +{ + return __strtoll_internal (__nptr, __endptr, __base, 0); +} +__extension__ extern __inline unsigned long long int +strtoull (__const char * __restrict __nptr, char **__restrict __endptr, + int __base) throw () +{ + return __strtoull_internal (__nptr, __endptr, __base, 0); +} + + +extern __inline double +atof (__const char *__nptr) throw () +{ + return strtod (__nptr, (char **) __null ); +} +extern __inline int +atoi (__const char *__nptr) throw () +{ + return (int) strtol (__nptr, (char **) __null , 10); +} +extern __inline long int +atol (__const char *__nptr) throw () +{ + return strtol (__nptr, (char **) __null , 10); +} + + +__extension__ extern __inline long long int +atoll (__const char *__nptr) throw () +{ + return strtoll (__nptr, (char **) __null , 10); +} + + + + + + + + +extern char *l64a (long int __n) throw () ; + + +extern long int a64l (__const char *__s) throw () ; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern "C" { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef unsigned char __u_char; +typedef unsigned short __u_short; +typedef unsigned int __u_int; +typedef unsigned long __u_long; + +__extension__ typedef unsigned long long int __u_quad_t; +__extension__ typedef long long int __quad_t; + +typedef signed char __int8_t; +typedef unsigned char __uint8_t; +typedef signed short int __int16_t; +typedef unsigned short int __uint16_t; +typedef signed int __int32_t; +typedef unsigned int __uint32_t; + +__extension__ typedef signed long long int __int64_t; +__extension__ typedef unsigned long long int __uint64_t; + +typedef __quad_t *__qaddr_t; + +typedef __u_quad_t __dev_t; +typedef __u_int __uid_t; +typedef __u_int __gid_t; +typedef __u_long __ino_t; +typedef __u_int __mode_t; +typedef __u_int __nlink_t; +typedef long int __off_t; +typedef __quad_t __loff_t; +typedef int __pid_t; +typedef int __ssize_t; +typedef __u_long __rlim_t; +typedef __u_quad_t __rlim64_t; +typedef __u_int __id_t; + +typedef struct + { + int __val[2]; + } __fsid_t; + + +typedef int __daddr_t; +typedef char *__caddr_t; +typedef long int __time_t; +typedef unsigned int __useconds_t; +typedef long int __suseconds_t; +typedef long int __swblk_t; + +typedef long int __clock_t; + + +typedef int __clockid_t; + + +typedef int __timer_t; + + + + + + +typedef int __key_t; + + +typedef unsigned short int __ipc_pid_t; + + + +typedef long int __blksize_t; + + + + +typedef long int __blkcnt_t; +typedef __quad_t __blkcnt64_t; + + +typedef __u_long __fsblkcnt_t; +typedef __u_quad_t __fsblkcnt64_t; + + +typedef __u_long __fsfilcnt_t; +typedef __u_quad_t __fsfilcnt64_t; + + +typedef __u_quad_t __ino64_t; + + +typedef __loff_t __off64_t; + + +typedef long int __t_scalar_t; +typedef unsigned long int __t_uscalar_t; + + +typedef int __intptr_t; + + +typedef unsigned int __socklen_t; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +struct __sched_param + { + int __sched_priority; + }; + + + + +typedef int _lt_spinlock_t; + + +struct _pthread_fastlock +{ + long int __status; + _lt_spinlock_t __spinlock; + +}; + + + +typedef struct _pthread_descr_struct *_pthread_descr; + + + + + +typedef struct __pthread_attr_s +{ + int __detachstate; + int __schedpolicy; + struct __sched_param __schedparam; + int __inheritsched; + int __scope; + size_t __guardsize; + int __stackaddr_set; + void *__stackaddr; + size_t __stacksize; +} pthread_attr_t; + + + +typedef struct +{ + struct _pthread_fastlock __c_lock; + _pthread_descr __c_waiting; +} pthread_cond_t; + + + +typedef struct +{ + int __dummy; +} pthread_condattr_t; + + +typedef unsigned int pthread_key_t; + + + + + +typedef struct +{ + int __m_reserved; + int __m_count; + _pthread_descr __m_owner; + int __m_kind; + struct _pthread_fastlock __m_lock; +} pthread_mutex_t; + + + +typedef struct +{ + int __mutexkind; +} pthread_mutexattr_t; + + + +typedef int pthread_once_t; + + + + + + + + +typedef unsigned long int pthread_t; + + + + + + + + + +typedef __u_char u_char; +typedef __u_short u_short; +typedef __u_int u_int; +typedef __u_long u_long; +typedef __quad_t quad_t; +typedef __u_quad_t u_quad_t; +typedef __fsid_t fsid_t; + + +typedef __loff_t loff_t; + + + +typedef __ino_t ino_t; + + + + + + +typedef __dev_t dev_t; + + + + +typedef __gid_t gid_t; + + + + +typedef __mode_t mode_t; + + + + +typedef __nlink_t nlink_t; + + + + +typedef __uid_t uid_t; + + + + + +typedef __off_t off_t; + + + + + + +typedef __pid_t pid_t; + + + + +typedef __id_t id_t; + + + + +typedef __ssize_t ssize_t; + + + + +typedef __daddr_t daddr_t; +typedef __caddr_t caddr_t; + + + +typedef __key_t key_t; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef __time_t time_t; + + + + + + + + + + +typedef __clockid_t clockid_t; + + + + + + + + + + +typedef __timer_t timer_t; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef unsigned long int ulong; +typedef unsigned short int ushort; +typedef unsigned int uint; + + + + + + + + + + + + +typedef int int8_t __attribute__ ((__mode__ ( __QI__ ))) ; +typedef int int16_t __attribute__ ((__mode__ ( __HI__ ))) ; +typedef int int32_t __attribute__ ((__mode__ ( __SI__ ))) ; +typedef int int64_t __attribute__ ((__mode__ ( __DI__ ))) ; + + +typedef unsigned int u_int8_t __attribute__ ((__mode__ ( __QI__ ))) ; +typedef unsigned int u_int16_t __attribute__ ((__mode__ ( __HI__ ))) ; +typedef unsigned int u_int32_t __attribute__ ((__mode__ ( __SI__ ))) ; +typedef unsigned int u_int64_t __attribute__ ((__mode__ ( __DI__ ))) ; + +typedef int register_t __attribute__ ((__mode__ (__word__))); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef int __sig_atomic_t; + + + + +typedef struct + { + unsigned long int __val[(1024 / (8 * sizeof (unsigned long int))) ]; + } __sigset_t; + + + + + + + + + + + + + + + +typedef __sigset_t sigset_t; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +struct timespec + { + long int tv_sec; + long int tv_nsec; + }; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +struct timeval + { + __time_t tv_sec; + __suseconds_t tv_usec; + }; + + + + + + +typedef long int __fd_mask; + + + + + + + +typedef struct + { + + + + __fd_mask __fds_bits[1024 / (8 * sizeof (__fd_mask)) ]; + + + } fd_set; + + + + + + +typedef __fd_mask fd_mask; + + + + + + + + + + + + + +extern "C" { + + + + + + +extern int select (int __nfds, fd_set *__restrict __readfds, + fd_set *__restrict __writefds, + fd_set *__restrict __exceptfds, + struct timeval *__restrict __timeout) throw () ; + + + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef __blkcnt_t blkcnt_t; + + + +typedef __fsblkcnt_t fsblkcnt_t; + + + +typedef __fsfilcnt_t fsfilcnt_t; + + + + + + +} + + + + + + + + + +extern long int random (void) throw () ; + + +extern void srandom (unsigned int __seed) throw () ; + + + + + +extern char *initstate (unsigned int __seed, char *__statebuf, + size_t __statelen) throw () ; + + + +extern char *setstate (char *__statebuf) throw () ; + + + + + + + +struct random_data + { + int32_t *fptr; + int32_t *rptr; + int32_t *state; + int rand_type; + int rand_deg; + int rand_sep; + int32_t *end_ptr; + }; + +extern int random_r (struct random_data *__restrict __buf, + int32_t *__restrict __result) throw () ; + +extern int srandom_r (unsigned int __seed, struct random_data *__buf) throw () ; + +extern int initstate_r (unsigned int __seed, char *__restrict __statebuf, + size_t __statelen, + struct random_data *__restrict __buf) throw () ; + +extern int setstate_r (char *__restrict __statebuf, + struct random_data *__restrict __buf) throw () ; + + + + + +extern int rand (void) throw () ; + +extern void srand (unsigned int __seed) throw () ; + + + +extern int rand_r (unsigned int *__seed) throw () ; + + + + + + + +extern double drand48 (void) throw () ; +extern double erand48 (unsigned short int __xsubi[3]) throw () ; + + +extern long int lrand48 (void) throw () ; +extern long int nrand48 (unsigned short int __xsubi[3]) throw () ; + + +extern long int mrand48 (void) throw () ; +extern long int jrand48 (unsigned short int __xsubi[3]) throw () ; + + +extern void srand48 (long int __seedval) throw () ; +extern unsigned short int *seed48 (unsigned short int __seed16v[3]) throw () ; +extern void lcong48 (unsigned short int __param[7]) throw () ; + + + + + +struct drand48_data + { + unsigned short int __x[3]; + unsigned short int __old_x[3]; + unsigned short int __c; + unsigned short int __init; + unsigned long long int __a; + }; + + +extern int drand48_r (struct drand48_data *__restrict __buffer, + double *__restrict __result) throw () ; +extern int erand48_r (unsigned short int __xsubi[3], + struct drand48_data *__restrict __buffer, + double *__restrict __result) throw () ; + + +extern int lrand48_r (struct drand48_data *__restrict __buffer, + long int *__restrict __result) throw () ; +extern int nrand48_r (unsigned short int __xsubi[3], + struct drand48_data *__restrict __buffer, + long int *__restrict __result) throw () ; + + +extern int mrand48_r (struct drand48_data *__restrict __buffer, + long int *__restrict __result) throw () ; +extern int jrand48_r (unsigned short int __xsubi[3], + struct drand48_data *__restrict __buffer, + long int *__restrict __result) throw () ; + + +extern int srand48_r (long int __seedval, struct drand48_data *__buffer) + throw () ; + +extern int seed48_r (unsigned short int __seed16v[3], + struct drand48_data *__buffer) throw () ; + +extern int lcong48_r (unsigned short int __param[7], + struct drand48_data *__buffer) throw () ; + + + + + + + + +extern void *malloc (size_t __size) throw () ; + +extern void *calloc (size_t __nmemb, size_t __size) + throw () ; + + + + + +extern void *realloc (void *__ptr, size_t __size) throw () ; + +extern void free (void *__ptr) throw () ; + + + +extern void cfree (void *__ptr) throw () ; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern "C" { + + + + + +extern void *alloca (size_t __size) throw () ; + + + + + +} + + + + + + + +extern void *valloc (size_t __size) throw () ; + + + + + +extern void abort (void) throw () __attribute__ ((__noreturn__)); + + + +extern int atexit (void (*__func) (void)) throw () ; + + + + +extern int on_exit (void (*__func) (int __status, void *__arg), void *__arg) + throw () ; + + + + + +extern void exit (int __status) throw () __attribute__ ((__noreturn__)); + + + + + +extern char *getenv (__const char *__name) throw () ; + + + +extern char *__secure_getenv (__const char *__name) throw () ; + + + + + +extern int putenv (char *__string) throw () ; + + + + + +extern int setenv (__const char *__name, __const char *__value, int __replace) + throw () ; + + +extern int unsetenv (__const char *__name) throw () ; + + + + + + +extern int clearenv (void) throw () ; + + + + + + + + +extern char *mktemp (char *__template) throw () ; + + + + + + + +extern int mkstemp (char *__template) throw () ; + + + + + + + + + + +extern char *mkdtemp (char *__template) throw () ; + + + + +extern int system (__const char *__command) throw () ; + + + + + + + + + + + +extern char *realpath (__const char *__restrict __name, + char *__restrict __resolved) throw () ; + + + + + + +typedef int (*__compar_fn_t) (__const void *, __const void *); + + + + + + +extern void *bsearch (__const void *__key, __const void *__base, + size_t __nmemb, size_t __size, __compar_fn_t __compar); + + + +extern void qsort (void *__base, size_t __nmemb, size_t __size, + __compar_fn_t __compar); + + + +extern int abs (int __x) throw () __attribute__ ((__const__)); +extern long int labs (long int __x) throw () __attribute__ ((__const__)); + + + + + + +extern div_t div (int __numer, int __denom) + throw () __attribute__ ((__const__)); +extern ldiv_t ldiv (long int __numer, long int __denom) + throw () __attribute__ ((__const__)); + + + + + + + + + + +extern char *ecvt (double __value, int __ndigit, int *__restrict __decpt, + int *__restrict __sign) throw () ; + + + + +extern char *fcvt (double __value, int __ndigit, int *__restrict __decpt, + int *__restrict __sign) throw () ; + + + + +extern char *gcvt (double __value, int __ndigit, char *__buf) throw () ; + + + + +extern char *qecvt (long double __value, int __ndigit, + int *__restrict __decpt, int *__restrict __sign) throw () ; +extern char *qfcvt (long double __value, int __ndigit, + int *__restrict __decpt, int *__restrict __sign) throw () ; +extern char *qgcvt (long double __value, int __ndigit, char *__buf) throw () ; + + + + +extern int ecvt_r (double __value, int __ndigit, int *__restrict __decpt, + int *__restrict __sign, char *__restrict __buf, + size_t __len) throw () ; +extern int fcvt_r (double __value, int __ndigit, int *__restrict __decpt, + int *__restrict __sign, char *__restrict __buf, + size_t __len) throw () ; + +extern int qecvt_r (long double __value, int __ndigit, + int *__restrict __decpt, int *__restrict __sign, + char *__restrict __buf, size_t __len) throw () ; +extern int qfcvt_r (long double __value, int __ndigit, + int *__restrict __decpt, int *__restrict __sign, + char *__restrict __buf, size_t __len) throw () ; + + + + + + +extern int mblen (__const char *__s, size_t __n) throw () ; + + +extern int mbtowc (wchar_t *__restrict __pwc, + __const char *__restrict __s, size_t __n) throw () ; + + +extern int wctomb (char *__s, wchar_t __wchar) throw () ; + + + +extern size_t mbstowcs (wchar_t *__restrict __pwcs, + __const char *__restrict __s, size_t __n) throw () ; + +extern size_t wcstombs (char *__restrict __s, + __const wchar_t *__restrict __pwcs, size_t __n) + throw () ; + + + + + + + +extern int rpmatch (__const char *__response) throw () ; + + + + + + + + + + + + + + + + + + + + + +extern int getloadavg (double __loadavg[], int __nelem) throw () ; + + + + + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern "C" { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern long int __sysconf (int); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef __clock_t clock_t; + + + + + + + + + + + + + + + + + + + + +struct tm +{ + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + + + long int tm_gmtoff; + __const char *tm_zone; + +}; + + + + +struct itimerspec + { + struct timespec it_interval; + struct timespec it_value; + }; + + +struct sigevent; + + + + + + + + +extern clock_t clock (void) throw () ; + + +extern time_t time (time_t *__timer) throw () ; + + +extern double difftime (time_t __time1, time_t __time0) + throw () __attribute__ ((__const__)); + + +extern time_t mktime (struct tm *__tp) throw () ; + + + + + +extern size_t strftime (char *__restrict __s, size_t __maxsize, + __const char *__restrict __format, + __const struct tm *__restrict __tp) throw () ; + + + + + + +extern struct tm *gmtime (__const time_t *__timer) throw () ; + + + +extern struct tm *localtime (__const time_t *__timer) throw () ; + + + + +extern struct tm *gmtime_r (__const time_t *__restrict __timer, + struct tm *__restrict __tp) throw () ; + + + +extern struct tm *localtime_r (__const time_t *__restrict __timer, + struct tm *__restrict __tp) throw () ; + + + + +extern char *asctime (__const struct tm *__tp) throw () ; + + +extern char *ctime (__const time_t *__timer) throw () ; + + + + + + +extern char *asctime_r (__const struct tm *__restrict __tp, + char *__restrict __buf) throw () ; + + +extern char *ctime_r (__const time_t *__restrict __timer, + char *__restrict __buf) throw () ; + + + + +extern char *__tzname[2]; +extern int __daylight; +extern long int __timezone; + + + + +extern char *tzname[2]; + + + +extern void tzset (void) throw () ; + + + +extern int daylight; +extern long int timezone; + + + + + +extern int stime (__const time_t *__when) throw () ; + + + + + + + + + + + + + +extern time_t timegm (struct tm *__tp) throw () ; + + +extern time_t timelocal (struct tm *__tp) throw () ; + + +extern int dysize (int __year) throw () __attribute__ ((__const__)); + + + + + +extern int nanosleep (__const struct timespec *__requested_time, + struct timespec *__remaining) throw () ; + + + +extern int clock_getres (clockid_t __clock_id, struct timespec *__res) throw () ; + + +extern int clock_gettime (clockid_t __clock_id, struct timespec *__tp) throw () ; + + +extern int clock_settime (clockid_t __clock_id, __const struct timespec *__tp) + throw () ; + + + + + +extern int timer_create (clockid_t __clock_id, + struct sigevent *__restrict __evp, + timer_t *__restrict __timerid) throw () ; + + +extern int timer_delete (timer_t __timerid) throw () ; + + +extern int timer_settime (timer_t __timerid, int __flags, + __const struct itimerspec *__restrict __value, + struct itimerspec *__restrict __ovalue) throw () ; + + +extern int timer_gettime (timer_t __timerid, struct itimerspec *__value) + throw () ; + + +extern int timer_getoverrun (timer_t __timerid) throw () ; + + + + + + + + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef int ptrdiff_t; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef unsigned int wint_t; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern "C" { + + + + +extern int __malloc_initialized; + + + + + +extern void * malloc (size_t __size) throw () ; + + +extern void * calloc (size_t __nmemb, size_t __size) throw () + ; + + + +extern void * realloc (void * __ptr, + size_t __size) throw () + ; + + +extern void free (void * __ptr) throw () ; + + +extern void cfree (void * __ptr) throw () ; + + +extern void * memalign (size_t __alignment, size_t __size) throw () ; + + +extern void * valloc (size_t __size) throw () ; + + + +extern void * pvalloc (size_t __size) throw () + ; + + + +extern void * (*__morecore) (ptrdiff_t __size) ; + + +extern void * __default_morecore (ptrdiff_t __size) throw () + ; + + +struct mallinfo { + int arena; + int ordblks; + int smblks; + int hblks; + int hblkhd; + int usmblks; + int fsmblks; + int uordblks; + int fordblks; + int keepcost; +}; + + +extern struct mallinfo mallinfo (void) throw () ; + + + + + + + + + + + + + + + + + + + + + + + +extern int mallopt (int __param, int __val) throw () ; + + + +extern int malloc_trim (size_t __pad) throw () ; + + + +extern size_t malloc_usable_size (void * __ptr) throw () ; + + +extern void malloc_stats (void) throw () ; + + +extern void * malloc_get_state (void) throw () ; + + + +extern int malloc_set_state (void * __ptr) throw () ; + + + + + +extern void (*__malloc_initialize_hook) (void) ; + +extern void (*__free_hook) (void * __ptr, + __const void * ) ; +extern void * (*__malloc_hook) (size_t __size, + __const void * ) ; +extern void * (*__realloc_hook) (void * __ptr, + size_t __size, + __const void * ) ; +extern void * (*__memalign_hook) (size_t __alignment, + size_t __size, + __const void * ) ; +extern void (*__after_morecore_hook) (void) ; + + +extern void __malloc_check_init (void) throw () ; + + + +}; + + + + +typedef unsigned char unchar; + +static __inline__ void * ALLOC (int alloc) +{ + void *mem = malloc(alloc); + + (static_cast (( mem != 0 ) ? 0 : (__assert_fail ("mem != 0" , "userfs_types.h", 46, __PRETTY_FUNCTION__ ), 0))) ; + return mem; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef struct { + unsigned long fds_bits [(1024 / (8 * sizeof(unsigned long)) ) ]; +} __kernel_fd_set; + + +typedef void (*__kernel_sighandler_t)(int); + + +typedef int __kernel_key_t; + + + + + + + + + + + + + + +struct ustat { + __kernel_daddr_t f_tfree; + __kernel_ino_t f_tinode; + char f_fname[6]; + char f_fpack[6]; +}; + + + + + + + + + + + + + +typedef struct +{ + unsigned long handle; +} up_handle; + +typedef unsigned long up_version; + +struct userfs_inode_info +{ + up_handle handle; + struct userfs_dir_ra *dir_ra; + up_version version; +}; + + + + + + + + + + +typedef unsigned long up_credtok; + +struct userfs_file_info { + up_credtok cred_tok; +}; + + + + + + + + + + + + + + + + + + +typedef unsigned char Uchar; +typedef unsigned short Ushort; +typedef unsigned long Ulong; +typedef unsigned long Uint; +typedef unsigned long long Ulonglong; +typedef long long longlong; + + +__inline__ static unsigned char *encode_char(const char *ch, unsigned char *buf) +{ + *buf = *ch; + return buf+1; +} + +__inline__ static unsigned char *decode_char(char *ch, unsigned char *buf) +{ + *ch = *buf; + return buf+1; +} + +__inline__ static unsigned int sizeof_char(const char *c) +{ + (void)c; + return 1; +} + + +__inline__ static unsigned char *encode_Uchar(const Uchar *ch, unsigned char *buf) +{ + *buf = *ch; + return buf+1; +} + +__inline__ static unsigned char *decode_Uchar(Uchar *ch, unsigned char *buf) +{ + *ch = *buf; + return buf+1; +} + +__inline__ static unsigned int sizeof_Uchar(const Uchar *c) +{ + (void)c; + return 1; +} + + +__inline__ static unsigned char *encode_short(const short *sh, unsigned char *buf) +{ + register short sv = *sh; + + buf[0] = (sv >> 8)& 0xff; + buf[1] = sv & 0xff; + return buf+2; +} + +__inline__ static unsigned char *decode_short(short *sh, unsigned char *buf) +{ + *sh = (buf[0] << 8) | buf[1]; + return buf+2; +} + +__inline__ static unsigned int sizeof_short(const short *c) +{ + (void)c; + return 2; +} + + +__inline__ static unsigned char *encode_Ushort(const Ushort *sh, unsigned char *buf) +{ + register Ushort sv = *sh; + + buf[0] = (sv >> 8)& 0xff; + buf[1] = sv & 0xff; + return buf+2; +} + +__inline__ static unsigned char *decode_Ushort(Ushort *sh, unsigned char *buf) +{ + *sh = (buf[0] << 8) | buf[1]; + return buf+2; +} + +__inline__ static unsigned int sizeof_Ushort(const Ushort *c) +{ + (void)c; + return 2; +} + + +__inline__ static unsigned char *encode_long(const long *l, unsigned char *buf) +{ + register long lv = *l; + + buf[0] = (lv >> 24) & 0xff; + buf[1] = (lv >> 16) & 0xff; + buf[2] = (lv >> 8) & 0xff; + buf[3] = lv & 0xff; + return buf+4; +} + +__inline__ static unsigned char *decode_long(long *l, unsigned char *buf) +{ + *l = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + return buf+4; +} + +__inline__ static unsigned int sizeof_long(const long *c) +{ + (void)c; + return 4; +} + + +__inline__ static unsigned char *encode_Ulong(const Ulong *l, unsigned char *buf) +{ + register Ulong lv = *l; + + buf[0] = (lv >> 24) & 0xff; + buf[1] = (lv >> 16) & 0xff; + buf[2] = (lv >> 8) & 0xff; + buf[3] = lv & 0xff; + return buf+4; +} + +__inline__ static unsigned char *decode_Ulong(Ulong *l, unsigned char *buf) +{ + *l = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + return buf+4; +} + +__inline__ static unsigned int sizeof_Ulong(const Ulong *c) +{ + (void)c; + return 4; +} + + +__inline__ static unsigned char *encode_longlong(const long long *l, + unsigned char *buf) +{ + register long long lv = *l; + + buf[0] = (lv >> 56) & 0xff; + buf[1] = (lv >> 48) & 0xff; + buf[2] = (lv >> 40) & 0xff; + buf[3] = (lv >> 32) & 0xff; + buf[4] = (lv >> 24) & 0xff; + buf[5] = (lv >> 16) & 0xff; + buf[6] = (lv >> 8) & 0xff; + buf[7] = lv & 0xff; + + return buf+8; +} + +__inline__ static unsigned char *decode_longlong(long long *l, + unsigned char *buf) +{ + + *l = (((long long)(buf[ 0 ])) << 56)|(((long long)(buf[ 1 ])) << 48)|(((long long)(buf[ 2 ])) << 40)|(((long long)(buf[ 3 ])) << 32)| + (((long long)(buf[ 4 ])) << 24)|(((long long)(buf[ 5 ])) << 16)|(((long long)(buf[ 6 ])) << 8)| ((long long)(buf[ 7 ])) ; + + return buf+8; +} + +__inline__ static unsigned int sizeof_longlong(const long long *c) +{ + (void)c; + return 8; +} + + +__inline__ static unsigned char *encode_Ulonglong(const unsigned long long *l, + unsigned char *buf) +{ + register unsigned long long lv = *l; + + buf[0] = (lv >> 56) & 0xff; + buf[1] = (lv >> 48) & 0xff; + buf[2] = (lv >> 40) & 0xff; + buf[3] = (lv >> 32) & 0xff; + buf[4] = (lv >> 24) & 0xff; + buf[5] = (lv >> 16) & 0xff; + buf[6] = (lv >> 8) & 0xff; + buf[7] = lv & 0xff; + + return buf+8; +} + +__inline__ static unsigned char *decode_Ulonglong(unsigned long long *l, + unsigned char *buf) +{ + + *l = (((unsigned long long)(buf[ 0 ])) << 56)|(((unsigned long long)(buf[ 1 ])) << 48)|(((unsigned long long)(buf[ 2 ])) << 40)|(((unsigned long long)(buf[ 3 ])) << 32)| + (((unsigned long long)(buf[ 4 ])) << 24)|(((unsigned long long)(buf[ 5 ])) << 16)|(((unsigned long long)(buf[ 6 ])) << 8)| ((unsigned long long)(buf[ 7 ])) ; + + return buf+8; +} + +__inline__ static unsigned int sizeof_Ulonglong(const unsigned long long *c) +{ + (void)c; + return 8; +} + + +__inline__ static unsigned char *encode_void(const void *v, unsigned char *buf) +{ + (void)v; + return buf; +} + +__inline__ static unsigned char *decode_void(void *v, unsigned char *buf) +{ + (void)v; + return buf; +} + +__inline__ static unsigned int sizeof_void(const void *c) +{ + (void)c; + return 0; +} + + + +__inline__ static unsigned char *encode_float(const float *f, unsigned char *buf) +{ + *(float *)buf = *f; + return buf + sizeof(float); +} + +__inline__ static unsigned char *decode_float(float *f, unsigned char *buf) +{ + *f = *(float *)buf; + return buf + sizeof(float); +} + +__inline__ static unsigned int sizeof_float(const float *c) +{ + (void)c; + return sizeof(float); +} + + +__inline__ static unsigned char *encode_double(const double *d, unsigned char *buf) +{ + *(double *)buf = *d; + return buf + sizeof(double); +} + +__inline__ static unsigned char *decode_double(double *d, unsigned char *buf) +{ + *d = *(double *)buf; + return buf + sizeof(double); +} + +__inline__ static unsigned int sizeof_double(const double *c) +{ + (void)c; + return sizeof(double); +} + + + + + + +typedef Ulong _userfs_types_001[32]; +typedef long _userfs_types_002[2]; +typedef Ulong _userfs_types_003[32]; +typedef ushort uf_uid_t; +typedef ushort uf_gid_t; +typedef ushort uf_nlink_t; +typedef ushort uf_dev_t; +typedef struct _userfs_types_S001 { + Ulong nelem; + long* elems; + + int alloced; + void _userfs_types_S001::alloc(unsigned size) {elems = new long [size]; alloced = 1; } + _userfs_types_S001::_userfs_types_S001() { alloced = 0; } + _userfs_types_S001::~_userfs_types_S001() { + if (alloced) { + delete [] elems; alloced = 0; + } + } + +} _userfs_types_004; +typedef struct +{ + uf_uid_t uid; + uf_uid_t euid; + uf_uid_t suid; + uf_uid_t gid; + uf_uid_t egid; + uf_uid_t sgid; + uf_uid_t umask; + _userfs_types_004 groups; +} up_cred; +typedef struct +{ + Ulong ia_valid; + umode_t ia_mode; + uf_uid_t ia_uid; + uf_gid_t ia_gid; + off_t ia_size; + time_t ia_atime; + time_t ia_mtime; + time_t ia_ctime; +} up_iattr; +typedef struct +{ + __s16 version; + long seq; + Uchar op; + Uchar isreq; + Ulong size; +} up_preamble; +typedef struct +{ + __s16 version; + long seq; + Uchar op; + Uchar isreq; + Ulong size; + long err_no; +} upp_repl; +typedef struct +{ + umode_t mode; + uf_nlink_t nlink; + uf_uid_t uid; + uf_gid_t gid; + off_t size; + time_t atime; + time_t mtime; + time_t ctime; + uf_dev_t rdev; + Ulong blksize; + Ulong blocks; +} up_inode; +typedef struct _userfs_types_S002 { + Ulong nelem; + __s8* elems; + + int alloced; + void _userfs_types_S002::alloc(unsigned size) {elems = new __s8 [size]; alloced = 1; } + _userfs_types_S002::_userfs_types_S002() { alloced = 0; } + _userfs_types_S002::~_userfs_types_S002() { + if (alloced) { + delete [] elems; alloced = 0; + } + } + +} up_name; +typedef struct +{ + up_inode ino; + up_handle handle; +} upp_iwrite_s; +typedef struct +{ + up_handle handle; +} upp_iread_s; +typedef struct +{ + up_handle handle; + up_inode ino; +} upp_iread_r; +typedef struct +{ + up_handle dir; + up_name name; +} upp_unlink_s; +typedef struct +{ + up_handle link; +} upp_readlink_s; +typedef struct +{ + up_name name; +} upp_readlink_r; +typedef struct +{ + up_handle dir; + up_handle link; + long flag; + long mode; +} upp_followlink_s; +typedef struct +{ + up_name path; +} upp_followlink_r; +typedef struct _userfs_types_S003 { + Ulong nelem; + long* elems; + + int alloced; + void _userfs_types_S003::alloc(unsigned size) {elems = new long [size]; alloced = 1; } + _userfs_types_S003::_userfs_types_S003() { alloced = 0; } + _userfs_types_S003::~_userfs_types_S003() { + if (alloced) { + delete [] elems; alloced = 0; + } + } + +} _userfs_types_005; +typedef struct +{ + long mode; + up_handle dir; + up_cred cred; + long rdev; + up_name name; +} upp_create_s; +typedef struct +{ + up_handle file; +} upp_create_r; +typedef struct +{ + up_handle dir; + up_name name; +} upp_lookup_s; +typedef struct +{ + up_handle handle; +} upp_lookup_r; +typedef struct +{ + up_handle file; + off_t off; + off_t size; + up_credtok ctok; +} upp_read_s; +typedef struct _userfs_types_S004 { + Ulong nelem; + Uchar* elems; + + int alloced; + void _userfs_types_S004::alloc(unsigned size) {elems = new Uchar [size]; alloced = 1; } + _userfs_types_S004::_userfs_types_S004() { alloced = 0; } + _userfs_types_S004::~_userfs_types_S004() { + if (alloced) { + delete [] elems; alloced = 0; + } + } + +} _userfs_types_006; +typedef struct +{ + _userfs_types_006 data; +} upp_read_r; +typedef struct _userfs_types_S005 { + Ulong nelem; + Uchar* elems; + + int alloced; + void _userfs_types_S005::alloc(unsigned size) {elems = new Uchar [size]; alloced = 1; } + _userfs_types_S005::_userfs_types_S005() { alloced = 0; } + _userfs_types_S005::~_userfs_types_S005() { + if (alloced) { + delete [] elems; alloced = 0; + } + } + +} _userfs_types_007; +typedef struct +{ + up_handle file; + off_t off; + up_credtok ctok; + _userfs_types_007 data; +} upp_write_s; +typedef struct +{ + off_t wrote; +} upp_write_r; +typedef struct +{ + up_handle dir; + off_t off; + up_credtok ctok; +} upp_readdir_s; +typedef struct +{ + up_handle file; + off_t off; + up_name name; +} upp_readdir_r; +typedef upp_readdir_s upp_multireaddir_s; +typedef struct _userfs_types_S006 { + Ulong nelem; + upp_readdir_r* elems; + + int alloced; + void _userfs_types_S006::alloc(unsigned size) {elems = new upp_readdir_r [size]; alloced = 1; } + _userfs_types_S006::_userfs_types_S006() { alloced = 0; } + _userfs_types_S006::~_userfs_types_S006() { + if (alloced) { + delete [] elems; alloced = 0; + } + } + +} upp_multireaddir_r; +typedef struct +{ + up_handle root; +} upp_mount_r; +typedef struct +{ + up_handle handle; +} upp_iput_s; +typedef struct _userfs_types_S007 { + Ulong nelem; + long* elems; + + int alloced; + void _userfs_types_S007::alloc(unsigned size) {elems = new long [size]; alloced = 1; } + _userfs_types_S007::_userfs_types_S007() { alloced = 0; } + _userfs_types_S007::~_userfs_types_S007() { + if (alloced) { + delete [] elems; alloced = 0; + } + } + +} _userfs_types_008; +typedef struct +{ + up_cred cred; + up_handle file; +} upp_open_s; +typedef struct +{ + up_credtok ctok; +} upp_open_r; +typedef struct +{ + up_handle file; + up_credtok ctok; +} upp_close_s; +typedef struct _userfs_types_S008 { + Ulong nelem; + long* elems; + + int alloced; + void _userfs_types_S008::alloc(unsigned size) {elems = new long [size]; alloced = 1; } + _userfs_types_S008::_userfs_types_S008() { alloced = 0; } + _userfs_types_S008::~_userfs_types_S008() { + if (alloced) { + delete [] elems; alloced = 0; + } + } + +} _userfs_types_009; +typedef struct +{ + up_cred cred; + up_handle file; + long mask; +} upp_permission_s; +typedef struct +{ + up_handle odir; + up_name oname; + up_handle ndir; + up_name nname; +} upp_rename_s; +typedef struct +{ + up_handle ofile; + up_handle dir; + up_name name; +} upp_link_s; +typedef struct _userfs_types_S009 { + Ulong nelem; + long* elems; + + int alloced; + void _userfs_types_S009::alloc(unsigned size) {elems = new long [size]; alloced = 1; } + _userfs_types_S009::_userfs_types_S009() { alloced = 0; } + _userfs_types_S009::~_userfs_types_S009() { + if (alloced) { + delete [] elems; alloced = 0; + } + } + +} _userfs_types_010; +typedef struct +{ + up_handle dir; + up_name name; + up_name symname; + up_cred cred; +} upp_symlink_s; +typedef long _userfs_types_011[2]; +typedef struct +{ + __kernel_off_t bsize; + __kernel_off_t blocks; + __kernel_off_t bfree; + __kernel_off_t bavail; + __kernel_off_t files; + __kernel_off_t ffree; + _userfs_types_011 fsid; + __kernel_off_t namelen; +} upp_statfs_r; +typedef struct +{ + up_handle file; + off_t size; +} upp_truncate_s; +typedef struct +{ + up_handle handle; + up_iattr iattr; +} upp_notify_change_s; +typedef struct +{ + up_handle handle; + up_version version; +} upp_inode_valid_s; +typedef struct +{ + up_version version; + __s8 valid; +} upp_inode_valid_r; +static unsigned char *encode_char(const char *, unsigned char *); +static unsigned char *decode_char(char *, unsigned char *); +static unsigned int sizeof_char(const char *); + +static unsigned char *encode_short(const short *, unsigned char *); +static unsigned char *decode_short(short *, unsigned char *); +static unsigned int sizeof_short(const short *); + +static unsigned char *encode_long(const long *, unsigned char *); +static unsigned char *decode_long(long *, unsigned char *); +static unsigned int sizeof_long(const long *); + +static unsigned char *encode_longlong(const longlong *, unsigned char *); +static unsigned char *decode_longlong(longlong *, unsigned char *); +static unsigned int sizeof_longlong(const longlong *); + +static unsigned char *encode_float(const float *, unsigned char *); +static unsigned char *decode_float(float *, unsigned char *); +static unsigned int sizeof_float(const float *); + +static unsigned char *encode_double(const double *, unsigned char *); +static unsigned char *decode_double(double *, unsigned char *); +static unsigned int sizeof_double(const double *); + +static unsigned char *encode_void(const void *, unsigned char *); +static unsigned char *decode_void(void *, unsigned char *); +static unsigned int sizeof_void(const void *); + +static unsigned char *encode_Uchar(const Uchar *, unsigned char *); +static unsigned char *decode_Uchar(Uchar *, unsigned char *); +static unsigned int sizeof_Uchar(const Uchar *); + +static unsigned char *encode_Ushort(const Ushort *, unsigned char *); +static unsigned char *decode_Ushort(Ushort *, unsigned char *); +static unsigned int sizeof_Ushort(const Ushort *); + +static unsigned char *encode_Ulong(const Ulong *, unsigned char *); +static unsigned char *decode_Ulong(Ulong *, unsigned char *); +static unsigned int sizeof_Ulong(const Ulong *); + +static unsigned char *encode_Ulonglong(const Ulonglong *, unsigned char *); +static unsigned char *decode_Ulonglong(Ulonglong *, unsigned char *); +static unsigned int sizeof_Ulonglong(const Ulonglong *); + +unsigned char *encode_Uint(const Uint *, unsigned char *); +unsigned char *decode_Uint(Uint *, unsigned char *); +unsigned int sizeof_Uint(const Uint *); + +unsigned char *encode_int(const int *, unsigned char *); +unsigned char *decode_int(int *, unsigned char *); +unsigned int sizeof_int(const int *); + +unsigned char *encode__userfs_types_001(const _userfs_types_001 *, unsigned char *); +unsigned char *decode__userfs_types_001(_userfs_types_001 *, unsigned char *); +unsigned int sizeof__userfs_types_001(const _userfs_types_001 *); + +unsigned char *encode___kernel_fd_set(const __kernel_fd_set *, unsigned char *); +unsigned char *decode___kernel_fd_set(__kernel_fd_set *, unsigned char *); +unsigned int sizeof___kernel_fd_set(const __kernel_fd_set *); + +unsigned char *encode___kernel_key_t(const __kernel_key_t *, unsigned char *); +unsigned char *decode___kernel_key_t(__kernel_key_t *, unsigned char *); +unsigned int sizeof___kernel_key_t(const __kernel_key_t *); + +unsigned char *encode___kernel_dev_t(const __kernel_dev_t *, unsigned char *); +unsigned char *decode___kernel_dev_t(__kernel_dev_t *, unsigned char *); +unsigned int sizeof___kernel_dev_t(const __kernel_dev_t *); + +unsigned char *encode___kernel_ino_t(const __kernel_ino_t *, unsigned char *); +unsigned char *decode___kernel_ino_t(__kernel_ino_t *, unsigned char *); +unsigned int sizeof___kernel_ino_t(const __kernel_ino_t *); + +unsigned char *encode___kernel_mode_t(const __kernel_mode_t *, unsigned char *); +unsigned char *decode___kernel_mode_t(__kernel_mode_t *, unsigned char *); +unsigned int sizeof___kernel_mode_t(const __kernel_mode_t *); + +unsigned char *encode___kernel_nlink_t(const __kernel_nlink_t *, unsigned char *); +unsigned char *decode___kernel_nlink_t(__kernel_nlink_t *, unsigned char *); +unsigned int sizeof___kernel_nlink_t(const __kernel_nlink_t *); + +unsigned char *encode___kernel_off_t(const __kernel_off_t *, unsigned char *); +unsigned char *decode___kernel_off_t(__kernel_off_t *, unsigned char *); +unsigned int sizeof___kernel_off_t(const __kernel_off_t *); + +unsigned char *encode___kernel_pid_t(const __kernel_pid_t *, unsigned char *); +unsigned char *decode___kernel_pid_t(__kernel_pid_t *, unsigned char *); +unsigned int sizeof___kernel_pid_t(const __kernel_pid_t *); + +unsigned char *encode___kernel_ipc_pid_t(const __kernel_ipc_pid_t *, unsigned char *); +unsigned char *decode___kernel_ipc_pid_t(__kernel_ipc_pid_t *, unsigned char *); +unsigned int sizeof___kernel_ipc_pid_t(const __kernel_ipc_pid_t *); + +unsigned char *encode___kernel_uid_t(const __kernel_uid_t *, unsigned char *); +unsigned char *decode___kernel_uid_t(__kernel_uid_t *, unsigned char *); +unsigned int sizeof___kernel_uid_t(const __kernel_uid_t *); + +unsigned char *encode___kernel_gid_t(const __kernel_gid_t *, unsigned char *); +unsigned char *decode___kernel_gid_t(__kernel_gid_t *, unsigned char *); +unsigned int sizeof___kernel_gid_t(const __kernel_gid_t *); + +unsigned char *encode___kernel_size_t(const __kernel_size_t *, unsigned char *); +unsigned char *decode___kernel_size_t(__kernel_size_t *, unsigned char *); +unsigned int sizeof___kernel_size_t(const __kernel_size_t *); + +unsigned char *encode___kernel_ssize_t(const __kernel_ssize_t *, unsigned char *); +unsigned char *decode___kernel_ssize_t(__kernel_ssize_t *, unsigned char *); +unsigned int sizeof___kernel_ssize_t(const __kernel_ssize_t *); + +unsigned char *encode___kernel_ptrdiff_t(const __kernel_ptrdiff_t *, unsigned char *); +unsigned char *decode___kernel_ptrdiff_t(__kernel_ptrdiff_t *, unsigned char *); +unsigned int sizeof___kernel_ptrdiff_t(const __kernel_ptrdiff_t *); + +unsigned char *encode___kernel_time_t(const __kernel_time_t *, unsigned char *); +unsigned char *decode___kernel_time_t(__kernel_time_t *, unsigned char *); +unsigned int sizeof___kernel_time_t(const __kernel_time_t *); + +unsigned char *encode___kernel_suseconds_t(const __kernel_suseconds_t *, unsigned char *); +unsigned char *decode___kernel_suseconds_t(__kernel_suseconds_t *, unsigned char *); +unsigned int sizeof___kernel_suseconds_t(const __kernel_suseconds_t *); + +unsigned char *encode___kernel_clock_t(const __kernel_clock_t *, unsigned char *); +unsigned char *decode___kernel_clock_t(__kernel_clock_t *, unsigned char *); +unsigned int sizeof___kernel_clock_t(const __kernel_clock_t *); + +unsigned char *encode___kernel_daddr_t(const __kernel_daddr_t *, unsigned char *); +unsigned char *decode___kernel_daddr_t(__kernel_daddr_t *, unsigned char *); +unsigned int sizeof___kernel_daddr_t(const __kernel_daddr_t *); + +unsigned char *encode___kernel_caddr_t(const __kernel_caddr_t *, unsigned char *); +unsigned char *decode___kernel_caddr_t(__kernel_caddr_t *, unsigned char *); +unsigned int sizeof___kernel_caddr_t(const __kernel_caddr_t *); + +unsigned char *encode___kernel_uid16_t(const __kernel_uid16_t *, unsigned char *); +unsigned char *decode___kernel_uid16_t(__kernel_uid16_t *, unsigned char *); +unsigned int sizeof___kernel_uid16_t(const __kernel_uid16_t *); + +unsigned char *encode___kernel_gid16_t(const __kernel_gid16_t *, unsigned char *); +unsigned char *decode___kernel_gid16_t(__kernel_gid16_t *, unsigned char *); +unsigned int sizeof___kernel_gid16_t(const __kernel_gid16_t *); + +unsigned char *encode___kernel_uid32_t(const __kernel_uid32_t *, unsigned char *); +unsigned char *decode___kernel_uid32_t(__kernel_uid32_t *, unsigned char *); +unsigned int sizeof___kernel_uid32_t(const __kernel_uid32_t *); + +unsigned char *encode___kernel_gid32_t(const __kernel_gid32_t *, unsigned char *); +unsigned char *decode___kernel_gid32_t(__kernel_gid32_t *, unsigned char *); +unsigned int sizeof___kernel_gid32_t(const __kernel_gid32_t *); + +unsigned char *encode___kernel_old_uid_t(const __kernel_old_uid_t *, unsigned char *); +unsigned char *decode___kernel_old_uid_t(__kernel_old_uid_t *, unsigned char *); +unsigned int sizeof___kernel_old_uid_t(const __kernel_old_uid_t *); + +unsigned char *encode___kernel_old_gid_t(const __kernel_old_gid_t *, unsigned char *); +unsigned char *decode___kernel_old_gid_t(__kernel_old_gid_t *, unsigned char *); +unsigned int sizeof___kernel_old_gid_t(const __kernel_old_gid_t *); + +unsigned char *encode__userfs_types_002(const _userfs_types_002 *, unsigned char *); +unsigned char *decode__userfs_types_002(_userfs_types_002 *, unsigned char *); +unsigned int sizeof__userfs_types_002(const _userfs_types_002 *); + +unsigned char *encode___kernel_fsid_t(const __kernel_fsid_t *, unsigned char *); +unsigned char *decode___kernel_fsid_t(__kernel_fsid_t *, unsigned char *); +unsigned int sizeof___kernel_fsid_t(const __kernel_fsid_t *); + +unsigned char *encode_umode_t(const umode_t *, unsigned char *); +unsigned char *decode_umode_t(umode_t *, unsigned char *); +unsigned int sizeof_umode_t(const umode_t *); + +unsigned char *encode___s8(const __s8 *, unsigned char *); +unsigned char *decode___s8(__s8 *, unsigned char *); +unsigned int sizeof___s8(const __s8 *); + +unsigned char *encode___u8(const __u8 *, unsigned char *); +unsigned char *decode___u8(__u8 *, unsigned char *); +unsigned int sizeof___u8(const __u8 *); + +unsigned char *encode___s16(const __s16 *, unsigned char *); +unsigned char *decode___s16(__s16 *, unsigned char *); +unsigned int sizeof___s16(const __s16 *); + +unsigned char *encode___u16(const __u16 *, unsigned char *); +unsigned char *decode___u16(__u16 *, unsigned char *); +unsigned int sizeof___u16(const __u16 *); + +unsigned char *encode___s32(const __s32 *, unsigned char *); +unsigned char *decode___s32(__s32 *, unsigned char *); +unsigned int sizeof___s32(const __s32 *); + +unsigned char *encode___u32(const __u32 *, unsigned char *); +unsigned char *decode___u32(__u32 *, unsigned char *); +unsigned int sizeof___u32(const __u32 *); + +unsigned char *encode__userfs_types_003(const _userfs_types_003 *, unsigned char *); +unsigned char *decode__userfs_types_003(_userfs_types_003 *, unsigned char *); +unsigned int sizeof__userfs_types_003(const _userfs_types_003 *); + +unsigned char *encode_fd_set(const fd_set *, unsigned char *); +unsigned char *decode_fd_set(fd_set *, unsigned char *); +unsigned int sizeof_fd_set(const fd_set *); + +unsigned char *encode_dev_t(const dev_t *, unsigned char *); +unsigned char *decode_dev_t(dev_t *, unsigned char *); +unsigned int sizeof_dev_t(const dev_t *); + +unsigned char *encode_ino_t(const ino_t *, unsigned char *); +unsigned char *decode_ino_t(ino_t *, unsigned char *); +unsigned int sizeof_ino_t(const ino_t *); + +unsigned char *encode_mode_t(const mode_t *, unsigned char *); +unsigned char *decode_mode_t(mode_t *, unsigned char *); +unsigned int sizeof_mode_t(const mode_t *); + +unsigned char *encode_nlink_t(const nlink_t *, unsigned char *); +unsigned char *decode_nlink_t(nlink_t *, unsigned char *); +unsigned int sizeof_nlink_t(const nlink_t *); + +unsigned char *encode_off_t(const off_t *, unsigned char *); +unsigned char *decode_off_t(off_t *, unsigned char *); +unsigned int sizeof_off_t(const off_t *); + +unsigned char *encode_pid_t(const pid_t *, unsigned char *); +unsigned char *decode_pid_t(pid_t *, unsigned char *); +unsigned int sizeof_pid_t(const pid_t *); + +unsigned char *encode_daddr_t(const daddr_t *, unsigned char *); +unsigned char *decode_daddr_t(daddr_t *, unsigned char *); +unsigned int sizeof_daddr_t(const daddr_t *); + +unsigned char *encode_key_t(const key_t *, unsigned char *); +unsigned char *decode_key_t(key_t *, unsigned char *); +unsigned int sizeof_key_t(const key_t *); + +unsigned char *encode_suseconds_t(const suseconds_t *, unsigned char *); +unsigned char *decode_suseconds_t(suseconds_t *, unsigned char *); +unsigned int sizeof_suseconds_t(const suseconds_t *); + +unsigned char *encode_uid_t(const uid_t *, unsigned char *); +unsigned char *decode_uid_t(uid_t *, unsigned char *); +unsigned int sizeof_uid_t(const uid_t *); + +unsigned char *encode_gid_t(const gid_t *, unsigned char *); +unsigned char *decode_gid_t(gid_t *, unsigned char *); +unsigned int sizeof_gid_t(const gid_t *); + +unsigned char *encode_size_t(const size_t *, unsigned char *); +unsigned char *decode_size_t(size_t *, unsigned char *); +unsigned int sizeof_size_t(const size_t *); + +unsigned char *encode_ssize_t(const ssize_t *, unsigned char *); +unsigned char *decode_ssize_t(ssize_t *, unsigned char *); +unsigned int sizeof_ssize_t(const ssize_t *); + +unsigned char *encode_ptrdiff_t(const ptrdiff_t *, unsigned char *); +unsigned char *decode_ptrdiff_t(ptrdiff_t *, unsigned char *); +unsigned int sizeof_ptrdiff_t(const ptrdiff_t *); + +unsigned char *encode_time_t(const time_t *, unsigned char *); +unsigned char *decode_time_t(time_t *, unsigned char *); +unsigned int sizeof_time_t(const time_t *); + +unsigned char *encode_clock_t(const clock_t *, unsigned char *); +unsigned char *decode_clock_t(clock_t *, unsigned char *); +unsigned int sizeof_clock_t(const clock_t *); + +unsigned char *encode_caddr_t(const caddr_t *, unsigned char *); +unsigned char *decode_caddr_t(caddr_t *, unsigned char *); +unsigned int sizeof_caddr_t(const caddr_t *); + +unsigned char *encode_u_char(const u_char *, unsigned char *); +unsigned char *decode_u_char(u_char *, unsigned char *); +unsigned int sizeof_u_char(const u_char *); + +unsigned char *encode_u_short(const u_short *, unsigned char *); +unsigned char *decode_u_short(u_short *, unsigned char *); +unsigned int sizeof_u_short(const u_short *); + +unsigned char *encode_u_int(const u_int *, unsigned char *); +unsigned char *decode_u_int(u_int *, unsigned char *); +unsigned int sizeof_u_int(const u_int *); + +unsigned char *encode_u_long(const u_long *, unsigned char *); +unsigned char *decode_u_long(u_long *, unsigned char *); +unsigned int sizeof_u_long(const u_long *); + +unsigned char *encode_unchar(const unchar *, unsigned char *); +unsigned char *decode_unchar(unchar *, unsigned char *); +unsigned int sizeof_unchar(const unchar *); + +unsigned char *encode_ushort(const ushort *, unsigned char *); +unsigned char *decode_ushort(ushort *, unsigned char *); +unsigned int sizeof_ushort(const ushort *); + +unsigned char *encode_uint(const uint *, unsigned char *); +unsigned char *decode_uint(uint *, unsigned char *); +unsigned int sizeof_uint(const uint *); + +unsigned char *encode_ulong(const ulong *, unsigned char *); +unsigned char *decode_ulong(ulong *, unsigned char *); +unsigned int sizeof_ulong(const ulong *); + +unsigned char *encode_u_int8_t(const u_int8_t *, unsigned char *); +unsigned char *decode_u_int8_t(u_int8_t *, unsigned char *); +unsigned int sizeof_u_int8_t(const u_int8_t *); + +unsigned char *encode_int8_t(const int8_t *, unsigned char *); +unsigned char *decode_int8_t(int8_t *, unsigned char *); +unsigned int sizeof_int8_t(const int8_t *); + +unsigned char *encode_u_int16_t(const u_int16_t *, unsigned char *); +unsigned char *decode_u_int16_t(u_int16_t *, unsigned char *); +unsigned int sizeof_u_int16_t(const u_int16_t *); + +unsigned char *encode_int16_t(const int16_t *, unsigned char *); +unsigned char *decode_int16_t(int16_t *, unsigned char *); +unsigned int sizeof_int16_t(const int16_t *); + +unsigned char *encode_u_int32_t(const u_int32_t *, unsigned char *); +unsigned char *decode_u_int32_t(u_int32_t *, unsigned char *); +unsigned int sizeof_u_int32_t(const u_int32_t *); + +unsigned char *encode_int32_t(const int32_t *, unsigned char *); +unsigned char *decode_int32_t(int32_t *, unsigned char *); +unsigned int sizeof_int32_t(const int32_t *); + +unsigned char *encode_uint8_t(const uint8_t *, unsigned char *); +unsigned char *decode_uint8_t(uint8_t *, unsigned char *); +unsigned int sizeof_uint8_t(const uint8_t *); + +unsigned char *encode_uint16_t(const uint16_t *, unsigned char *); +unsigned char *decode_uint16_t(uint16_t *, unsigned char *); +unsigned int sizeof_uint16_t(const uint16_t *); + +unsigned char *encode_uint32_t(const uint32_t *, unsigned char *); +unsigned char *decode_uint32_t(uint32_t *, unsigned char *); +unsigned int sizeof_uint32_t(const uint32_t *); + +unsigned char *encode_up_handle(const up_handle *, unsigned char *); +unsigned char *decode_up_handle(up_handle *, unsigned char *); +unsigned int sizeof_up_handle(const up_handle *); + +unsigned char *encode_up_version(const up_version *, unsigned char *); +unsigned char *decode_up_version(up_version *, unsigned char *); +unsigned int sizeof_up_version(const up_version *); + +unsigned char *encode_up_credtok(const up_credtok *, unsigned char *); +unsigned char *decode_up_credtok(up_credtok *, unsigned char *); +unsigned int sizeof_up_credtok(const up_credtok *); + +unsigned char *encode_uf_uid_t(const uf_uid_t *, unsigned char *); +unsigned char *decode_uf_uid_t(uf_uid_t *, unsigned char *); +unsigned int sizeof_uf_uid_t(const uf_uid_t *); + +unsigned char *encode_uf_gid_t(const uf_gid_t *, unsigned char *); +unsigned char *decode_uf_gid_t(uf_gid_t *, unsigned char *); +unsigned int sizeof_uf_gid_t(const uf_gid_t *); + +unsigned char *encode_uf_nlink_t(const uf_nlink_t *, unsigned char *); +unsigned char *decode_uf_nlink_t(uf_nlink_t *, unsigned char *); +unsigned int sizeof_uf_nlink_t(const uf_nlink_t *); + +unsigned char *encode_uf_dev_t(const uf_dev_t *, unsigned char *); +unsigned char *decode_uf_dev_t(uf_dev_t *, unsigned char *); +unsigned int sizeof_uf_dev_t(const uf_dev_t *); + +unsigned char *encode__userfs_types_004(const _userfs_types_004 *, unsigned char *); +unsigned char *decode__userfs_types_004(_userfs_types_004 *, unsigned char *); +unsigned int sizeof__userfs_types_004(const _userfs_types_004 *); + +unsigned char *encode_up_cred(const up_cred *, unsigned char *); +unsigned char *decode_up_cred(up_cred *, unsigned char *); +unsigned int sizeof_up_cred(const up_cred *); + +unsigned char *encode_up_iattr(const up_iattr *, unsigned char *); +unsigned char *decode_up_iattr(up_iattr *, unsigned char *); +unsigned int sizeof_up_iattr(const up_iattr *); + +unsigned char *encode_up_preamble(const up_preamble *, unsigned char *); +unsigned char *decode_up_preamble(up_preamble *, unsigned char *); +unsigned int sizeof_up_preamble(const up_preamble *); + +unsigned char *encode_upp_repl(const upp_repl *, unsigned char *); +unsigned char *decode_upp_repl(upp_repl *, unsigned char *); +unsigned int sizeof_upp_repl(const upp_repl *); + +unsigned char *encode_up_inode(const up_inode *, unsigned char *); +unsigned char *decode_up_inode(up_inode *, unsigned char *); +unsigned int sizeof_up_inode(const up_inode *); + +unsigned char *encode_up_name(const up_name *, unsigned char *); +unsigned char *decode_up_name(up_name *, unsigned char *); +unsigned int sizeof_up_name(const up_name *); + +unsigned char *encode_upp_iwrite_s(const upp_iwrite_s *, unsigned char *); +unsigned char *decode_upp_iwrite_s(upp_iwrite_s *, unsigned char *); +unsigned int sizeof_upp_iwrite_s(const upp_iwrite_s *); + +unsigned char *encode_upp_iread_s(const upp_iread_s *, unsigned char *); +unsigned char *decode_upp_iread_s(upp_iread_s *, unsigned char *); +unsigned int sizeof_upp_iread_s(const upp_iread_s *); + +unsigned char *encode_upp_iread_r(const upp_iread_r *, unsigned char *); +unsigned char *decode_upp_iread_r(upp_iread_r *, unsigned char *); +unsigned int sizeof_upp_iread_r(const upp_iread_r *); + +unsigned char *encode_upp_unlink_s(const upp_unlink_s *, unsigned char *); +unsigned char *decode_upp_unlink_s(upp_unlink_s *, unsigned char *); +unsigned int sizeof_upp_unlink_s(const upp_unlink_s *); + +unsigned char *encode_upp_readlink_s(const upp_readlink_s *, unsigned char *); +unsigned char *decode_upp_readlink_s(upp_readlink_s *, unsigned char *); +unsigned int sizeof_upp_readlink_s(const upp_readlink_s *); + +unsigned char *encode_upp_readlink_r(const upp_readlink_r *, unsigned char *); +unsigned char *decode_upp_readlink_r(upp_readlink_r *, unsigned char *); +unsigned int sizeof_upp_readlink_r(const upp_readlink_r *); + +unsigned char *encode_upp_followlink_s(const upp_followlink_s *, unsigned char *); +unsigned char *decode_upp_followlink_s(upp_followlink_s *, unsigned char *); +unsigned int sizeof_upp_followlink_s(const upp_followlink_s *); + +unsigned char *encode_upp_followlink_r(const upp_followlink_r *, unsigned char *); +unsigned char *decode_upp_followlink_r(upp_followlink_r *, unsigned char *); +unsigned int sizeof_upp_followlink_r(const upp_followlink_r *); + +unsigned char *encode__userfs_types_005(const _userfs_types_005 *, unsigned char *); +unsigned char *decode__userfs_types_005(_userfs_types_005 *, unsigned char *); +unsigned int sizeof__userfs_types_005(const _userfs_types_005 *); + +unsigned char *encode_upp_create_s(const upp_create_s *, unsigned char *); +unsigned char *decode_upp_create_s(upp_create_s *, unsigned char *); +unsigned int sizeof_upp_create_s(const upp_create_s *); + +unsigned char *encode_upp_create_r(const upp_create_r *, unsigned char *); +unsigned char *decode_upp_create_r(upp_create_r *, unsigned char *); +unsigned int sizeof_upp_create_r(const upp_create_r *); + +unsigned char *encode_upp_lookup_s(const upp_lookup_s *, unsigned char *); +unsigned char *decode_upp_lookup_s(upp_lookup_s *, unsigned char *); +unsigned int sizeof_upp_lookup_s(const upp_lookup_s *); + +unsigned char *encode_upp_lookup_r(const upp_lookup_r *, unsigned char *); +unsigned char *decode_upp_lookup_r(upp_lookup_r *, unsigned char *); +unsigned int sizeof_upp_lookup_r(const upp_lookup_r *); + +unsigned char *encode_upp_read_s(const upp_read_s *, unsigned char *); +unsigned char *decode_upp_read_s(upp_read_s *, unsigned char *); +unsigned int sizeof_upp_read_s(const upp_read_s *); + +unsigned char *encode__userfs_types_006(const _userfs_types_006 *, unsigned char *); +unsigned char *decode__userfs_types_006(_userfs_types_006 *, unsigned char *); +unsigned int sizeof__userfs_types_006(const _userfs_types_006 *); + +unsigned char *encode_upp_read_r(const upp_read_r *, unsigned char *); +unsigned char *decode_upp_read_r(upp_read_r *, unsigned char *); +unsigned int sizeof_upp_read_r(const upp_read_r *); + +unsigned char *encode__userfs_types_007(const _userfs_types_007 *, unsigned char *); +unsigned char *decode__userfs_types_007(_userfs_types_007 *, unsigned char *); +unsigned int sizeof__userfs_types_007(const _userfs_types_007 *); + +unsigned char *encode_upp_write_s(const upp_write_s *, unsigned char *); +unsigned char *decode_upp_write_s(upp_write_s *, unsigned char *); +unsigned int sizeof_upp_write_s(const upp_write_s *); + +unsigned char *encode_upp_write_r(const upp_write_r *, unsigned char *); +unsigned char *decode_upp_write_r(upp_write_r *, unsigned char *); +unsigned int sizeof_upp_write_r(const upp_write_r *); + +unsigned char *encode_upp_readdir_s(const upp_readdir_s *, unsigned char *); +unsigned char *decode_upp_readdir_s(upp_readdir_s *, unsigned char *); +unsigned int sizeof_upp_readdir_s(const upp_readdir_s *); + +unsigned char *encode_upp_readdir_r(const upp_readdir_r *, unsigned char *); +unsigned char *decode_upp_readdir_r(upp_readdir_r *, unsigned char *); +unsigned int sizeof_upp_readdir_r(const upp_readdir_r *); + +unsigned char *encode_upp_multireaddir_s(const upp_multireaddir_s *, unsigned char *); +unsigned char *decode_upp_multireaddir_s(upp_multireaddir_s *, unsigned char *); +unsigned int sizeof_upp_multireaddir_s(const upp_multireaddir_s *); + +unsigned char *encode_upp_multireaddir_r(const upp_multireaddir_r *, unsigned char *); +unsigned char *decode_upp_multireaddir_r(upp_multireaddir_r *, unsigned char *); +unsigned int sizeof_upp_multireaddir_r(const upp_multireaddir_r *); + +unsigned char *encode_upp_mount_r(const upp_mount_r *, unsigned char *); +unsigned char *decode_upp_mount_r(upp_mount_r *, unsigned char *); +unsigned int sizeof_upp_mount_r(const upp_mount_r *); + +unsigned char *encode_upp_iput_s(const upp_iput_s *, unsigned char *); +unsigned char *decode_upp_iput_s(upp_iput_s *, unsigned char *); +unsigned int sizeof_upp_iput_s(const upp_iput_s *); + +unsigned char *encode__userfs_types_008(const _userfs_types_008 *, unsigned char *); +unsigned char *decode__userfs_types_008(_userfs_types_008 *, unsigned char *); +unsigned int sizeof__userfs_types_008(const _userfs_types_008 *); + +unsigned char *encode_upp_open_s(const upp_open_s *, unsigned char *); +unsigned char *decode_upp_open_s(upp_open_s *, unsigned char *); +unsigned int sizeof_upp_open_s(const upp_open_s *); + +unsigned char *encode_upp_open_r(const upp_open_r *, unsigned char *); +unsigned char *decode_upp_open_r(upp_open_r *, unsigned char *); +unsigned int sizeof_upp_open_r(const upp_open_r *); + +unsigned char *encode_upp_close_s(const upp_close_s *, unsigned char *); +unsigned char *decode_upp_close_s(upp_close_s *, unsigned char *); +unsigned int sizeof_upp_close_s(const upp_close_s *); + +unsigned char *encode__userfs_types_009(const _userfs_types_009 *, unsigned char *); +unsigned char *decode__userfs_types_009(_userfs_types_009 *, unsigned char *); +unsigned int sizeof__userfs_types_009(const _userfs_types_009 *); + +unsigned char *encode_upp_permission_s(const upp_permission_s *, unsigned char *); +unsigned char *decode_upp_permission_s(upp_permission_s *, unsigned char *); +unsigned int sizeof_upp_permission_s(const upp_permission_s *); + +unsigned char *encode_upp_rename_s(const upp_rename_s *, unsigned char *); +unsigned char *decode_upp_rename_s(upp_rename_s *, unsigned char *); +unsigned int sizeof_upp_rename_s(const upp_rename_s *); + +unsigned char *encode_upp_link_s(const upp_link_s *, unsigned char *); +unsigned char *decode_upp_link_s(upp_link_s *, unsigned char *); +unsigned int sizeof_upp_link_s(const upp_link_s *); + +unsigned char *encode__userfs_types_010(const _userfs_types_010 *, unsigned char *); +unsigned char *decode__userfs_types_010(_userfs_types_010 *, unsigned char *); +unsigned int sizeof__userfs_types_010(const _userfs_types_010 *); + +unsigned char *encode_upp_symlink_s(const upp_symlink_s *, unsigned char *); +unsigned char *decode_upp_symlink_s(upp_symlink_s *, unsigned char *); +unsigned int sizeof_upp_symlink_s(const upp_symlink_s *); + +unsigned char *encode__userfs_types_011(const _userfs_types_011 *, unsigned char *); +unsigned char *decode__userfs_types_011(_userfs_types_011 *, unsigned char *); +unsigned int sizeof__userfs_types_011(const _userfs_types_011 *); + +unsigned char *encode_upp_statfs_r(const upp_statfs_r *, unsigned char *); +unsigned char *decode_upp_statfs_r(upp_statfs_r *, unsigned char *); +unsigned int sizeof_upp_statfs_r(const upp_statfs_r *); + +unsigned char *encode_upp_truncate_s(const upp_truncate_s *, unsigned char *); +unsigned char *decode_upp_truncate_s(upp_truncate_s *, unsigned char *); +unsigned int sizeof_upp_truncate_s(const upp_truncate_s *); + +unsigned char *encode_upp_notify_change_s(const upp_notify_change_s *, unsigned char *); +unsigned char *decode_upp_notify_change_s(upp_notify_change_s *, unsigned char *); +unsigned int sizeof_upp_notify_change_s(const upp_notify_change_s *); + +unsigned char *encode_upp_inode_valid_s(const upp_inode_valid_s *, unsigned char *); +unsigned char *decode_upp_inode_valid_s(upp_inode_valid_s *, unsigned char *); +unsigned int sizeof_upp_inode_valid_s(const upp_inode_valid_s *); + +unsigned char *encode_upp_inode_valid_r(const upp_inode_valid_r *, unsigned char *); +unsigned char *decode_upp_inode_valid_r(upp_inode_valid_r *, unsigned char *); +unsigned int sizeof_upp_inode_valid_r(const upp_inode_valid_r *); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern "C" { + + +extern void __assert_fail (__const char *__assertion, __const char *__file, + unsigned int __line, __const char *__function) + throw () __attribute__ ((__noreturn__)); + + +extern void __assert_perror_fail (int __errnum, __const char *__file, + unsigned int __line, + __const char *__function) + throw () __attribute__ ((__noreturn__)); + + + + +extern void __assert (const char *__assertion, const char *__file, int __line) + throw () __attribute__ ((__noreturn__)); + + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern "C" { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern int errno; + + +extern int *__errno_location (void) throw () __attribute__ ((__const__)); + + + + + + + + + + + + + + + + + + + + + + + + + + +} + + + + + + + + + + + +#pragma interface + +typedef unsigned long Handle; +class Filesystem; + +class InodeList; +class DirInode; + +class Inode +{ + friend InodeList; + friend DirInode; + +private: + Inode *next, *prev; + short alive, onlist; + +protected: + + uid_t uid; + gid_t gid; + umode_t mode; + nlink_t nlink; + off_t size; + time_t atime; + time_t mtime; + time_t ctime; + dev_t rdev; + + + Handle handle; + + + Filesystem &filesys; + + Inode *findino(Handle h); + + + + virtual void update() {} + + virtual void cleanup() {} +public: + Inode(Filesystem &, Handle); + virtual ~Inode(); + + Handle gethandle() { return handle; } + Filesystem &getfilesys() { return filesys; } + + virtual void incref() { nlink++; } + virtual void decref() { nlink--; } + + virtual void beforeop(enum up_ops) { } + virtual void afterop(enum up_ops) { } + + virtual int link(const char *, int, Inode *) { return 38 ; } + virtual int unlink(const char *, int) { return 38 ; } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +virtual int do_create (const up_preamble &, upp_repl &, const upp_create_s &, upp_create_r &) ; +virtual int do_lookup (const up_preamble &, upp_repl &, const upp_lookup_s &, upp_lookup_r &) ; +virtual int do_link (const up_preamble &, upp_repl &, const upp_link_s &) ; +virtual int do_unlink (const up_preamble &, upp_repl &, const upp_unlink_s &) ; +virtual int do_symlink (const up_preamble &, upp_repl &, const upp_symlink_s &) ; +virtual int do_rename (const up_preamble &, upp_repl &, const upp_rename_s &) ; +virtual int do_readlink (const up_preamble &, upp_repl &, const upp_readlink_s &, upp_readlink_r &) ; +virtual int do_followlink (const up_preamble &, upp_repl &, const upp_followlink_s &, upp_followlink_r &) ; +virtual int do_permission (const up_preamble &, upp_repl &, const upp_permission_s &) ; +virtual int do_iwrite (const up_preamble &, upp_repl &, const upp_iwrite_s &) ; +virtual int do_iread (const up_preamble &, upp_repl &, const upp_iread_s &, upp_iread_r &) ; +virtual int do_iput (const up_preamble &, upp_repl &, const upp_iput_s &) ; +virtual int do_notify_change (const up_preamble &, upp_repl &, const upp_notify_change_s &) ; +virtual int do_truncate (const up_preamble &, upp_repl &, const upp_truncate_s &) ; +virtual int do_inode_valid (const up_preamble &, upp_repl &, const upp_inode_valid_s &, upp_inode_valid_r &) ; + + + + + + + +virtual int do_read (const up_preamble &, upp_repl &, const upp_read_s &, upp_read_r &) ; +virtual int do_write (const up_preamble &, upp_repl &, const upp_write_s &, upp_write_r &) ; +virtual int do_readdir (const up_preamble &, upp_repl &, const upp_readdir_s &, upp_readdir_r &) ; +virtual int do_multireaddir (const up_preamble &, upp_repl &, const upp_multireaddir_s &, upp_multireaddir_r &) ; +virtual int do_open (const up_preamble &, upp_repl &, const upp_open_s &, upp_open_r &) ; +virtual int do_close (const up_preamble &, upp_repl &, const upp_close_s &) ; + + + + + + + + + + +}; + + + + +class InodeList +{ +private: + Inode *list; + +public: + InodeList(); + ~InodeList(); + Inode *find(Handle); + void add(Inode *); + void del(Inode *); +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef __suseconds_t suseconds_t; + + + + +extern "C" { + + + + + + + +struct timezone + { + int tz_minuteswest; + int tz_dsttime; + }; + +typedef struct timezone *__restrict __timezone_ptr_t; + + + + + + + +extern int gettimeofday (struct timeval *__restrict __tv, + __timezone_ptr_t __tz) throw () ; + + + + +extern int settimeofday (__const struct timeval *__tv, + __const struct timezone *__tz) throw () ; + + + + + +extern int adjtime (__const struct timeval *__delta, + struct timeval *__olddelta) throw () ; + + + + +enum __itimer_which + { + + ITIMER_REAL = 0, + + + ITIMER_VIRTUAL = 1, + + + + ITIMER_PROF = 2 + + }; + + + +struct itimerval + { + + struct timeval it_interval; + + struct timeval it_value; + }; + + +typedef int __itimer_which_t; + + + + +extern int getitimer (__itimer_which_t __which, + struct itimerval *__value) throw () ; + + + + +extern int setitimer (__itimer_which_t __which, + __const struct itimerval *__restrict __new, + struct itimerval *__restrict __old) throw () ; + + + +extern int utimes (__const char *__file, __const struct timeval __tvp[2]) + throw () ; + + + + + + + + + + + + +} + + + + +#pragma interface + +class Filesystem; +class DispatchFD; +class DispToKern; + + + + + + + + + + +class CommBase +{ + friend Filesystem; + friend DispToKern; + + + struct dispq_t + { + struct disp_fd *h, *t; + } dispqs[4 ]; + int dispatches; + + + unsigned int tokern; + +protected: + + Filesystem &filesys; + + DispatchFD *req; + +public: + CommBase(Filesystem &, unsigned int to, unsigned int from); + virtual ~CommBase(); + + struct disp_fd *addDispatch(int fd, DispatchFD *dfd, int what= 1 , int pri = 2); + void delDispatch(struct disp_fd *); + + + int Run(); + + + int DeferRepl(); + + + + void CloseFDs(int all = 0); +}; + + +class DispatchFD +{ +public: + virtual int dispatch(int fd, int what) = 0; + virtual ~DispatchFD(); +}; + + +class DispToKern : public DispatchFD +{ +protected: + int tokern; +public: + DispToKern(const CommBase *); +}; + + + + +#pragma interface + +typedef unsigned char Data; +class Comm; + +class Filesystem +{ + friend CommBase; + friend Inode; + + const char *mpoint; + + CommBase *comm_p; + void setcomm(CommBase *c) { comm_p = c; } + +protected: + InodeList inodes; + virtual int Enquire(up_ops op); + + Handle rootdir; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +virtual int do_mount (const up_preamble &, upp_repl &, upp_mount_r &) ; +virtual int do_umount (const up_preamble &, upp_repl &) ; +virtual int do_statfs (const up_preamble &, upp_repl &, upp_statfs_r &) ; + + + + + + + +virtual int do_create (const up_preamble &, upp_repl &, const upp_create_s &, upp_create_r &) ; +virtual int do_lookup (const up_preamble &, upp_repl &, const upp_lookup_s &, upp_lookup_r &) ; +virtual int do_link (const up_preamble &, upp_repl &, const upp_link_s &) ; +virtual int do_unlink (const up_preamble &, upp_repl &, const upp_unlink_s &) ; +virtual int do_symlink (const up_preamble &, upp_repl &, const upp_symlink_s &) ; +virtual int do_rename (const up_preamble &, upp_repl &, const upp_rename_s &) ; +virtual int do_readlink (const up_preamble &, upp_repl &, const upp_readlink_s &, upp_readlink_r &) ; +virtual int do_followlink (const up_preamble &, upp_repl &, const upp_followlink_s &, upp_followlink_r &) ; +virtual int do_permission (const up_preamble &, upp_repl &, const upp_permission_s &) ; +virtual int do_iwrite (const up_preamble &, upp_repl &, const upp_iwrite_s &) ; +virtual int do_iread (const up_preamble &, upp_repl &, const upp_iread_s &, upp_iread_r &) ; +virtual int do_iput (const up_preamble &, upp_repl &, const upp_iput_s &) ; +virtual int do_notify_change (const up_preamble &, upp_repl &, const upp_notify_change_s &) ; +virtual int do_truncate (const up_preamble &, upp_repl &, const upp_truncate_s &) ; +virtual int do_inode_valid (const up_preamble &, upp_repl &, const upp_inode_valid_s &, upp_inode_valid_r &) ; + + + + + + + +virtual int do_read (const up_preamble &, upp_repl &, const upp_read_s &, upp_read_r &) ; +virtual int do_write (const up_preamble &, upp_repl &, const upp_write_s &, upp_write_r &) ; +virtual int do_readdir (const up_preamble &, upp_repl &, const upp_readdir_s &, upp_readdir_r &) ; +virtual int do_multireaddir (const up_preamble &, upp_repl &, const upp_multireaddir_s &, upp_multireaddir_r &) ; +virtual int do_open (const up_preamble &, upp_repl &, const upp_open_s &, upp_open_r &) ; +virtual int do_close (const up_preamble &, upp_repl &, const upp_close_s &) ; + + + + + + + + + + + +public: + Filesystem(const char *mpoint); + virtual ~Filesystem(); + + Inode *findino(Handle h) { return inodes.find(h); } + + + + int DoOp(const up_preamble &, upp_repl &, Data *data); + + CommBase *comm() const { return comm_p; } +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern "C" { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef struct _IO_FILE FILE; + + + + + + + + + +typedef struct _IO_FILE __FILE; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef struct +{ + int __count; + union + { + wint_t __wch; + char __wchb[4]; + } __value; +} __mbstate_t; + + + + + + + + + + + +typedef struct +{ + __off_t __pos; + __mbstate_t __state; +} _G_fpos_t; +typedef struct +{ + __off64_t __pos; + __mbstate_t __state; +} _G_fpos64_t; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +enum +{ + __GCONV_OK = 0, + __GCONV_NOCONV, + __GCONV_NODB, + __GCONV_NOMEM, + + __GCONV_EMPTY_INPUT, + __GCONV_FULL_OUTPUT, + __GCONV_ILLEGAL_INPUT, + __GCONV_INCOMPLETE_INPUT, + + __GCONV_ILLEGAL_DESCRIPTOR, + __GCONV_INTERNAL_ERROR +}; + + + +enum +{ + __GCONV_IS_LAST = 0x0001, + __GCONV_IGNORE_ERRORS = 0x0002 +}; + + + +struct __gconv_step; +struct __gconv_step_data; +struct __gconv_loaded_object; +struct __gconv_trans_data; + + + +typedef int (*__gconv_fct) (struct __gconv_step *, struct __gconv_step_data *, + __const unsigned char **, __const unsigned char *, + unsigned char **, size_t *, int, int); + + +typedef int (*__gconv_init_fct) (struct __gconv_step *); +typedef void (*__gconv_end_fct) (struct __gconv_step *); + + + +typedef int (*__gconv_trans_fct) (struct __gconv_step *, + struct __gconv_step_data *, void *, + __const unsigned char *, + __const unsigned char **, + __const unsigned char *, unsigned char **, + size_t *); + + +typedef int (*__gconv_trans_context_fct) (void *, __const unsigned char *, + __const unsigned char *, + unsigned char *, unsigned char *); + + +typedef int (*__gconv_trans_query_fct) (__const char *, __const char ***, + size_t *); + + +typedef int (*__gconv_trans_init_fct) (void **, const char *); +typedef void (*__gconv_trans_end_fct) (void *); + +struct __gconv_trans_data +{ + + __gconv_trans_fct __trans_fct; + __gconv_trans_context_fct __trans_context_fct; + __gconv_trans_end_fct __trans_end_fct; + void *__data; + struct __gconv_trans_data *__next; +}; + + + +struct __gconv_step +{ + struct __gconv_loaded_object *__shlib_handle; + __const char *__modname; + + int __counter; + + char *__from_name; + char *__to_name; + + __gconv_fct __fct; + __gconv_init_fct __init_fct; + __gconv_end_fct __end_fct; + + + + int __min_needed_from; + int __max_needed_from; + int __min_needed_to; + int __max_needed_to; + + + int __stateful; + + void *__data; +}; + + + +struct __gconv_step_data +{ + unsigned char *__outbuf; + unsigned char *__outbufend; + + + + int __flags; + + + + int __invocation_counter; + + + + int __internal_use; + + __mbstate_t *__statep; + __mbstate_t __state; + + + + struct __gconv_trans_data *__trans; +}; + + + +typedef struct __gconv_info +{ + size_t __nsteps; + struct __gconv_step *__steps; + __extension__ struct __gconv_step_data __data [0] ; +} *__gconv_t; + + + +typedef union +{ + struct __gconv_info __cd; + struct + { + struct __gconv_info __cd; + struct __gconv_step_data __data; + } __combined; +} _G_iconv_t; + +typedef int _G_int16_t __attribute__ ((__mode__ (__HI__))); +typedef int _G_int32_t __attribute__ ((__mode__ (__SI__))); +typedef unsigned int _G_uint16_t __attribute__ ((__mode__ (__HI__))); +typedef unsigned int _G_uint32_t __attribute__ ((__mode__ (__SI__))); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef void *__gnuc_va_list; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +struct _IO_jump_t; struct _IO_FILE; + + + +typedef void _IO_lock_t; + + + + + +struct _IO_marker { + struct _IO_marker *_next; + struct _IO_FILE *_sbuf; + + + + int _pos; + +}; + + +enum __codecvt_result +{ + __codecvt_ok, + __codecvt_partial, + __codecvt_error, + __codecvt_noconv +}; + + + +struct _IO_FILE { + int _flags; + + + + + char* _IO_read_ptr; + char* _IO_read_end; + char* _IO_read_base; + char* _IO_write_base; + char* _IO_write_ptr; + char* _IO_write_end; + char* _IO_buf_base; + char* _IO_buf_end; + + char *_IO_save_base; + char *_IO_backup_base; + char *_IO_save_end; + + struct _IO_marker *_markers; + + struct _IO_FILE *_chain; + + int _fileno; + int _blksize; + __off_t _old_offset; + + + + unsigned short _cur_column; + signed char _vtable_offset; + char _shortbuf[1]; + + + + _IO_lock_t *_lock; + + + __off64_t _offset; + + void *__pad1; + void *__pad2; + + int _mode; + + char _unused2[15 * sizeof (int) - 2 * sizeof (void *)]; + +}; + + + +struct _IO_FILE_plus; + +extern struct _IO_FILE_plus _IO_2_1_stdin_; +extern struct _IO_FILE_plus _IO_2_1_stdout_; +extern struct _IO_FILE_plus _IO_2_1_stderr_; + + + + + + + + + + + +typedef __ssize_t __io_read_fn (void *__cookie, char *__buf, size_t __nbytes); + + + + + + + +typedef __ssize_t __io_write_fn (void *__cookie, __const char *__buf, + size_t __n); + + + + + + + +typedef int __io_seek_fn (void *__cookie, __off64_t *__pos, int __w); + + +typedef int __io_close_fn (void *__cookie); + + + + + + +extern "C" { + + +extern int __underflow (_IO_FILE *) throw () ; +extern int __uflow (_IO_FILE *) throw () ; +extern int __overflow (_IO_FILE *, int) throw () ; +extern wint_t __wunderflow (_IO_FILE *) throw () ; +extern wint_t __wuflow (_IO_FILE *) throw () ; +extern wint_t __woverflow (_IO_FILE *, wint_t ) throw () ; + + + + + + + + + + + +extern int _IO_getc (_IO_FILE *__fp) throw () ; +extern int _IO_putc (int __c, _IO_FILE *__fp) throw () ; +extern int _IO_feof (_IO_FILE *__fp) throw () ; +extern int _IO_ferror (_IO_FILE *__fp) throw () ; + +extern int _IO_peekc_locked (_IO_FILE *__fp) throw () ; + + + + +extern void _IO_flockfile (_IO_FILE *) throw () ; +extern void _IO_funlockfile (_IO_FILE *) throw () ; +extern int _IO_ftrylockfile (_IO_FILE *) throw () ; + + + + + + + + + + +extern int _IO_vfscanf (_IO_FILE * __restrict, const char * __restrict, + __gnuc_va_list , int *__restrict) throw () ; +extern int _IO_vfprintf (_IO_FILE *__restrict, const char *__restrict, + __gnuc_va_list ) throw () ; +extern __ssize_t _IO_padn (_IO_FILE *, int, __ssize_t ) throw () ; +extern size_t _IO_sgetn (_IO_FILE *, void *, size_t ) throw () ; + +extern __off64_t _IO_seekoff (_IO_FILE *, __off64_t , int, int) throw () ; +extern __off64_t _IO_seekpos (_IO_FILE *, __off64_t , int) throw () ; + +extern void _IO_free_backup_area (_IO_FILE *) throw () ; + + + + +} + + + + + + + + + +typedef _G_fpos_t fpos_t; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern FILE *stdin; +extern FILE *stdout; +extern FILE *stderr; + + + + + + +extern int remove (__const char *__filename) throw () ; + +extern int rename (__const char *__old, __const char *__new) throw () ; + + + + +extern FILE *tmpfile (void) throw () ; + + + +extern char *tmpnam (char *__s) throw () ; + + + + +extern char *tmpnam_r (char *__s) throw () ; + + + + + + + + + + + +extern char *tempnam (__const char *__dir, __const char *__pfx) + throw () ; + + + + +extern int fclose (FILE *__stream) throw () ; + +extern int fflush (FILE *__stream) throw () ; + + + +extern int fflush_unlocked (FILE *__stream) throw () ; + + + + + + + +extern FILE *fopen (__const char *__restrict __filename, + __const char *__restrict __modes) throw () ; + +extern FILE *freopen (__const char *__restrict __filename, + __const char *__restrict __modes, + FILE *__restrict __stream) throw () ; + + + + + +extern FILE *fdopen (int __fd, __const char *__modes) throw () ; + + + + + + + +extern void setbuf (FILE *__restrict __stream, char *__restrict __buf) throw () ; + + + +extern int setvbuf (FILE *__restrict __stream, char *__restrict __buf, + int __modes, size_t __n) throw () ; + + + + +extern void setbuffer (FILE *__restrict __stream, char *__restrict __buf, + size_t __size) throw () ; + + +extern void setlinebuf (FILE *__stream) throw () ; + + + + +extern int fprintf (FILE *__restrict __stream, + __const char *__restrict __format, ...) throw () ; + +extern int printf (__const char *__restrict __format, ...) throw () ; + +extern int sprintf (char *__restrict __s, + __const char *__restrict __format, ...) throw () ; + + +extern int vfprintf (FILE *__restrict __s, __const char *__restrict __format, + __gnuc_va_list __arg) throw () ; + +extern int vprintf (__const char *__restrict __format, __gnuc_va_list __arg) + throw () ; + +extern int vsprintf (char *__restrict __s, __const char *__restrict __format, + __gnuc_va_list __arg) throw () ; + + + +extern int snprintf (char *__restrict __s, size_t __maxlen, + __const char *__restrict __format, ...) + throw () __attribute__ ((__format__ (__printf__, 3, 4))); + +extern int vsnprintf (char *__restrict __s, size_t __maxlen, + __const char *__restrict __format, __gnuc_va_list __arg) + throw () __attribute__ ((__format__ (__printf__, 3, 0))); + + + + + + +extern int fscanf (FILE *__restrict __stream, + __const char *__restrict __format, ...) throw () ; + +extern int scanf (__const char *__restrict __format, ...) throw () ; + +extern int sscanf (__const char *__restrict __s, + __const char *__restrict __format, ...) throw () ; + + + + + +extern int fgetc (FILE *__stream) throw () ; +extern int getc (FILE *__stream) throw () ; + + +extern int getchar (void) throw () ; + + + + + + + +extern int getc_unlocked (FILE *__stream) throw () ; +extern int getchar_unlocked (void) throw () ; + + + + +extern int fgetc_unlocked (FILE *__stream) throw () ; + + + + +extern int fputc (int __c, FILE *__stream) throw () ; +extern int putc (int __c, FILE *__stream) throw () ; + + +extern int putchar (int __c) throw () ; + + + + + + + +extern int fputc_unlocked (int __c, FILE *__stream) throw () ; + + + + +extern int putc_unlocked (int __c, FILE *__stream) throw () ; +extern int putchar_unlocked (int __c) throw () ; + + + + + +extern int getw (FILE *__stream) throw () ; + + +extern int putw (int __w, FILE *__stream) throw () ; + + + + +extern char *fgets (char *__restrict __s, int __n, FILE *__restrict __stream) + throw () ; + + + + + +extern char *gets (char *__s) throw () ; + + + + + + +extern int fputs (__const char *__restrict __s, FILE *__restrict __stream) + throw () ; + + + + +extern int puts (__const char *__s) throw () ; + + + +extern int ungetc (int __c, FILE *__stream) throw () ; + + + +extern size_t fread (void *__restrict __ptr, size_t __size, + size_t __n, FILE *__restrict __stream) throw () ; + +extern size_t fwrite (__const void *__restrict __ptr, size_t __size, + size_t __n, FILE *__restrict __s) throw () ; + + + +extern size_t fread_unlocked (void *__restrict __ptr, size_t __size, + size_t __n, FILE *__restrict __stream) throw () ; +extern size_t fwrite_unlocked (__const void *__restrict __ptr, size_t __size, + size_t __n, FILE *__restrict __stream) throw () ; + + + + +extern int fseek (FILE *__stream, long int __off, int __whence) throw () ; + +extern long int ftell (FILE *__stream) throw () ; + +extern void rewind (FILE *__stream) throw () ; + + + + + + + + + + +extern int fgetpos (FILE *__restrict __stream, fpos_t *__restrict __pos) + throw () ; + +extern int fsetpos (FILE *__stream, __const fpos_t *__pos) throw () ; + + + + + +extern void clearerr (FILE *__stream) throw () ; + +extern int feof (FILE *__stream) throw () ; + +extern int ferror (FILE *__stream) throw () ; + + + +extern void clearerr_unlocked (FILE *__stream) throw () ; +extern int feof_unlocked (FILE *__stream) throw () ; +extern int ferror_unlocked (FILE *__stream) throw () ; + + + + +extern void perror (__const char *__s) throw () ; + + + + +extern int sys_nerr; +extern __const char *__const sys_errlist[]; + + + + + + +extern int fileno (FILE *__stream) throw () ; + + + + +extern int fileno_unlocked (FILE *__stream) throw () ; + + + + + +extern FILE *popen (__const char *__command, __const char *__modes) throw () ; + + +extern int pclose (FILE *__stream) throw () ; + + + + + +extern char *ctermid (char *__s) throw () ; + + + + + + + + + + + + + +extern void flockfile (FILE *__stream) throw () ; + + + +extern int ftrylockfile (FILE *__stream) throw () ; + + +extern void funlockfile (FILE *__stream) throw () ; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +inline int +vprintf (__const char *__restrict __fmt, __gnuc_va_list __arg) throw () +{ + return vfprintf (stdout , __fmt, __arg); +} + + +inline int +getchar (void) throw () +{ + return _IO_getc (stdin ); +} + + + + +inline int +getc_unlocked (FILE *__fp) throw () +{ + return (( __fp )->_IO_read_ptr >= ( __fp )->_IO_read_end ? __uflow ( __fp ) : *(unsigned char *) ( __fp )->_IO_read_ptr++) ; +} + + +inline int +getchar_unlocked (void) throw () +{ + return (( stdin )->_IO_read_ptr >= ( stdin )->_IO_read_end ? __uflow ( stdin ) : *(unsigned char *) ( stdin )->_IO_read_ptr++) ; +} + + + + +inline int +putchar (int __c) throw () +{ + return _IO_putc (__c, stdout ); +} + + + + +inline int +fputc_unlocked (int __c, FILE *__stream) throw () +{ + return ((( __stream )->_IO_write_ptr >= ( __stream )->_IO_write_end) ? __overflow ( __stream , (unsigned char) ( __c )) : (unsigned char) (*( __stream )->_IO_write_ptr++ = ( __c ))) ; +} + + + + + +inline int +putc_unlocked (int __c, FILE *__stream) throw () +{ + return ((( __stream )->_IO_write_ptr >= ( __stream )->_IO_write_end) ? __overflow ( __stream , (unsigned char) ( __c )) : (unsigned char) (*( __stream )->_IO_write_ptr++ = ( __c ))) ; +} + + +inline int +putchar_unlocked (int __c) throw () +{ + return ((( stdout )->_IO_write_ptr >= ( stdout )->_IO_write_end) ? __overflow ( stdout , (unsigned char) ( __c )) : (unsigned char) (*( stdout )->_IO_write_ptr++ = ( __c ))) ; +} + + + + + + + + +inline int +feof_unlocked (FILE *__stream) throw () +{ + return ((( __stream )->_flags & 0x10 ) != 0) ; +} + + +inline int +ferror_unlocked (FILE *__stream) throw () +{ + return ((( __stream )->_flags & 0x20 ) != 0) ; +} + + + + + + + + + + + + + + + + + +} + + + + + + +InodeList::InodeList() +{ + list = __null ; +} + +InodeList::~InodeList() +{ + Inode *next; + + for(next = list; next != __null ; next = next->next) + next->cleanup(); + + for(; list != __null ; list = next) + { + next = list->next; + delete list; + } +} + +void +InodeList::add(Inode *ino) +{ + if (ino->onlist) + { + fprintf(stderr , "Adding %p onto list again\n", ino); + return; + } + ino->next = list; + ino->prev = __null ; + if (ino->next) + ino->next->prev = ino; + list = ino; + ino->onlist = 1; +} + +void +InodeList::del(Inode *ino) +{ + if (!ino->onlist) + return; + if (ino->prev) + ino->prev->next = ino->next; + else + list = ino->next; + if (ino->next) + ino->next->prev = ino->prev; + ino->onlist = 0; +} + +Inode * +InodeList::find(Handle hand) +{ + Inode *ino; + + for(ino = list; ino != __null ; ino = ino->next) + if (ino->handle == hand) + break; + + if (ino == __null ) + return __null ; + + + del(ino); + add(ino); + + return ino; +} + +Inode::Inode(Filesystem &fs, Handle hand) + :next(__null ),prev(__null ),nlink(0),handle(hand),filesys(fs) +{ + alive = 1; + onlist = 0; + filesys.inodes.add(this); +} + +Inode::~Inode() +{ + if (!alive) + fprintf(stderr , "Inode %p already dead!\n", this); + filesys.inodes.del(this); + alive = 0; +} + +Inode * +Inode::findino(Handle h) +{ + return filesys.inodes.find(h); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +int Inode::do_create (const up_preamble &, upp_repl &, const upp_create_s &, upp_create_r &) { return 38 ; } ; +int Inode::do_lookup (const up_preamble &, upp_repl &, const upp_lookup_s &, upp_lookup_r &) { return 38 ; } ; +int Inode::do_link (const up_preamble &, upp_repl &, const upp_link_s &) { return 38 ; } ; +int Inode::do_unlink (const up_preamble &, upp_repl &, const upp_unlink_s &) { return 38 ; } ; +int Inode::do_symlink (const up_preamble &, upp_repl &, const upp_symlink_s &) { return 38 ; } ; +int Inode::do_rename (const up_preamble &, upp_repl &, const upp_rename_s &) { return 38 ; } ; +int Inode::do_readlink (const up_preamble &, upp_repl &, const upp_readlink_s &, upp_readlink_r &) { return 38 ; } ; +int Inode::do_followlink (const up_preamble &, upp_repl &, const upp_followlink_s &, upp_followlink_r &) { return 38 ; } ; +int Inode::do_permission (const up_preamble &, upp_repl &, const upp_permission_s &) { return 38 ; } ; +int Inode::do_iwrite (const up_preamble &, upp_repl &, const upp_iwrite_s &) { return 38 ; } ; +int Inode::do_iread (const up_preamble &, upp_repl &, const upp_iread_s &, upp_iread_r &) { return 38 ; } ; +int Inode::do_iput (const up_preamble &, upp_repl &, const upp_iput_s &) { return 38 ; } ; +int Inode::do_notify_change (const up_preamble &, upp_repl &, const upp_notify_change_s &) { return 38 ; } ; +int Inode::do_truncate (const up_preamble &, upp_repl &, const upp_truncate_s &) { return 38 ; } ; +int Inode::do_inode_valid (const up_preamble &, upp_repl &, const upp_inode_valid_s &, upp_inode_valid_r &) { return 38 ; } ; + + + + + + + +int Inode::do_read (const up_preamble &, upp_repl &, const upp_read_s &, upp_read_r &) { return 38 ; } ; +int Inode::do_write (const up_preamble &, upp_repl &, const upp_write_s &, upp_write_r &) { return 38 ; } ; +int Inode::do_readdir (const up_preamble &, upp_repl &, const upp_readdir_s &, upp_readdir_r &) { return 38 ; } ; +int Inode::do_multireaddir (const up_preamble &, upp_repl &, const upp_multireaddir_s &, upp_multireaddir_r &) { return 38 ; } ; +int Inode::do_open (const up_preamble &, upp_repl &, const upp_open_s &, upp_open_r &) { return 38 ; } ; +int Inode::do_close (const up_preamble &, upp_repl &, const upp_close_s &) { return 38 ; } ; + + + + + + + + + + + Added: trunk/lib/README ============================================================================== --- trunk/lib/README 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/lib/README 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,54 @@ +This library is still very rudimentary. It handles the basic +filesystem operations, but still lacks most higher-level +functionality. The basic classes are: + +Filesystem A whole filesystem, consisting of a collection + of Inodes. This class is passed a block of data + repesenting a request and decodes it. There is a + method for each userfs protocol operation. For + operations involving inodes it finds the appropriate + inode (if any) and dispatches it. + +Inode A generic inode base class, with methods for + each operation. + +SimpleInode A simple class derived from Inode which implements + a simple constructor, and default behaviour for + upp_permission, upp_iread, upp_open, upp_close + and so on. + +DirInode Derived from SimpleInode: this implements most of the + functionality needed for a directory. For + simple cases all a class derived from this + needs is a special constructor: see homer.cc + +Comm This performs the comms between the kernel + streams and the filesystem itself. + +DeferComm This is like Comm, except it allows some replies + to be deferred - that is, the filesystem goes on + to process more input while a separate process + handles the outstanding requests. + +ThreadComm This creates a new light-weight process for each + request (using the library in ../lwp), and + terminates the thread when the request is done. + The LWP library is not pre-emptive, so care + must be taken with blocking system calls. + The filedescriptor dispatch service in CommBase + is useful for this. + +CommBase The base comms class. This is not useful by itself, + but it does provide some useful services to derived + classes, through the DispatchFD table. Its main + method is Run(), which does a select() syscall on + the set of fds in the dispatch table, and calls the + dispatch() method of each class in the table when its + filedescriptor event arrives. This is used for waiting + for kernel input, but arbitary fds can be selected on, + for reads, writes or exceptions. FD dispatch table + entries can be added and removed with addDispatch() + and delDispatch(). + + + Jeremy Fitzhardinge Added: trunk/lib/SimpleInode.h ============================================================================== --- trunk/lib/SimpleInode.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/lib/SimpleInode.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,36 @@ +// -*- C++ -*- + +// A simple inode with some very basic operations implemented + +#ifndef _SIMPLEINODE_H_ +#define _SIMPLEINODE_H_ + +#pragma interface + +#include + +class SimpleInode: public Inode +{ +public: + virtual void iread(up_inode &); + virtual void iwrite(const up_inode &); + + int do_iwrite(const up_preamble &, upp_repl &, + const upp_iwrite_s &arg); + int do_iread(const up_preamble &, upp_repl &, + const upp_iread_s &, upp_iread_r &); + int do_notify_change(const up_preamble &, upp_repl &, + const upp_notify_change_s &); + int do_open(const up_preamble &, upp_repl &, + const upp_open_s &, upp_open_r &); + int do_close(const up_preamble &, upp_repl &, + const upp_close_s &); + int do_permission(const up_preamble &, upp_repl &, + const upp_permission_s &); + int do_iput(const up_preamble &, upp_repl &, + const upp_iput_s &); + + SimpleInode(Filesystem &, Handle); +}; + +#endif /* _SIMPLEINODE_H_ */ Added: trunk/lib/ThreadComm.cc ============================================================================== --- trunk/lib/ThreadComm.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/lib/ThreadComm.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,173 @@ +// -*- C++ -*- + +// Threaded Comms class + +// This class sets up a LWP for each request + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#include +#include +#include +#include +#include +#include + +class Thread_doreq: public Comm_doreq +{ + friend void op_proc(int, char **, void *); + friend class ThreadComm; + + // Argument for thread + int fd; + int stksz, threadpri; + + // Associated dispatch list and comm struct pointers + struct disp_fd *disp; + ThreadComm *comm; + + // Do the read work in a thread + void doop(); + + // Virtual from Comm_doreq + int dispatch(int fd, int flags); + + void remself() { comm->delDispatch(disp); } + +public: + Thread_doreq(ThreadComm *, Filesystem &, int pri, int stk); +}; + +class EOF_handler: public DispatchFD +{ + int dispatch(int fd, int flags); +}; + +int +EOF_handler::dispatch(int fd, int) +{ + return 0; +} + +ThreadComm::ThreadComm(Filesystem &fs, unsigned to, unsigned from, + int stk, int pri, int tpri) + : CommBase(fs, to, from) +{ + main = new LWP(pri); + + Thread_doreq *tdr = new Thread_doreq(this, filesys, stk, tpri); + req = tdr; + + tdr->disp = addDispatch(from, tdr, DISP_R, NDISP_PRI); + EOF_handler *eof = new EOF_handler(); + addDispatch(from, eof, DISP_E); +} + +ThreadComm::~ThreadComm() +{ + delete main; +} + +Thread_doreq::Thread_doreq(ThreadComm *tc, Filesystem &fs, int stk, int pri) + : Comm_doreq(tc, fs), stksz(stk), threadpri(pri), comm(tc) +{ +} + +// Hop-through funtion to do casting +void op_proc(int, char **, void *p) +{ + ((Thread_doreq *)p)->doop(); + suicide(); + abort(); // NOTREACHED + +} + +// Process a request from the kernel +// Returns 0 on EOF, -1 on error and 1 for OK +int +Thread_doreq::dispatch(int infd, int) +{ + fd = infd; + LWP *lwp = new LWP(threadpri, op_proc, stksz, 0, NULL, this); + + return 1; // Always OK (no way of returning error) +} + +void +Thread_doreq::doop() +{ + up_preamble pre; + size_t presize = sizeof_up_preamble(&pre); + Uchar hbuf[256]; + int ret; + + ret = fullread(fd, hbuf, presize); + if (ret == 0) + { + remself(); + return; + } + + if (ret != (int)presize) + { + fprintf(stderr, "Thread_doreq::dispatch failed to get whole header (%d wanted, %d got)\n", + presize, ret); + remself(); + return; + } + + upp_repl repl; + size_t replsize = sizeof_upp_repl(&repl); + + assert(sizeof(hbuf) > replsize); + + decode_up_preamble(&pre, hbuf); + + Data *buf = new Data[USERFS_MAX_XFER]; + + if (pre.size != 0 && (ret = fullread(fd, buf, pre.size)) != (int)pre.size) + { + fprintf(stderr, "Thread_doreq::dispatch: failed to get whole body (%li wanted, %d got)\n", + pre.size, ret); + remself(); + delete buf; + return; + } + + ret = filesys.DoOp(pre, repl, buf); + + if (ret != 1) + { + remself(); + delete buf; + return; // -1 + } + +#ifdef DEBUG + if (repl.errno != 0) + { + fprintf(stderr, "Request %d failing with %d %s\n", + pre.op, repl.errno, strerror(repl.errno)); + } +#endif + + encode_upp_repl(&repl, hbuf); + + int err = 0; + + if (fullwrite(tokern, hbuf, replsize) != replsize) + err = 1; + else + if (repl.size != 0 && + fullwrite(tokern, buf, repl.size) != repl.size) + err = 1; + + if (err) + remself(); + + delete buf; + return; +} + Added: trunk/lib/DeferFilesys.cc ============================================================================== --- trunk/lib/DeferFilesys.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/lib/DeferFilesys.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,7 @@ +// -*- C++ -*- + +// Implementation file for DeferFilesys + +#pragma implementation + +#include Added: trunk/lib/ThreadComm.h ============================================================================== --- trunk/lib/ThreadComm.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/lib/ThreadComm.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,25 @@ +// -*- C++ -*- + +// Threaded Comm class + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + + +#ifndef _THREADCOMM_H_ +#define _THREADCOMM_H_ + +#include "Comm.h" + +class ThreadComm : public CommBase +{ + class LWP *main; + const int stksize, threadpri; + +public: + ThreadComm(Filesystem &, unsigned int, unsigned int, int stk, int mpri, int tpri); + ~ThreadComm(); +}; + +#endif /* _THREADCOMM_H_ */ Added: trunk/lib/operations.h ============================================================================== --- trunk/lib/operations.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/lib/operations.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,81 @@ +/* + * This contains references to all the userfs protocol operations this + * library supports. For each operation there is a macro which says + * whether it is a filesystem, inode or file operation, and whether it + * has arguments or return values. + * + * This is used for automatically generating prototypes in class + * definitions, and implementations of stub versions of these functions. + * + * For inode and file operations it also should really have macros for + * extracting the handle from the arguments. + * + * Copyright (C) 1995 Jeremy Fitzhardinge + * + * 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. + */ + +#if !defined(DO) || !defined(DOa) || !defined(DOr) || !defined(DOar) +#error "Need DOxx macros defined" +#endif + +#if !defined(opSUPER) && !defined(opINODE) && !defined(opFILE) +#define opSUPER +#define opINODE +#define opFILE +#endif + +/* Super operations */ +#ifdef opSUPER +#undef opSUPER + +DOr(mount); +DO(umount); +DOr(statfs); + +#endif /* opSUPER */ + +/* Inode operations */ +#ifdef opINODE +#undef opINODE + +DOar(create); +DOar(lookup); +DOa(link); +DOa(unlink); +DOa(symlink); +DOa(rename); +DOar(readlink); +DOar(followlink); +DOa(permission); +DOa(iwrite); +DOar(iread); +DOa(iput); +DOa(notify_change); +DOa(truncate); +DOar(inode_valid); + +#endif /* opINODE */ + +/* File operations */ +#ifdef opFILE +#undef opFILE + +DOar(read); +DOar(write); +DOar(readdir); +DOar(multireaddir); +DOar(open); +DOa(close); + +#endif /* opFILE */ + +#undef DO +#undef DOa +#undef DOr +#undef DOar + + Added: trunk/lib/DeferFilesys.h ============================================================================== --- trunk/lib/DeferFilesys.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/lib/DeferFilesys.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,23 @@ +// -*- C++ -*- + +// Filesystem which knows about DeferComm + +#ifndef _DEFERFILESYS_H_ +#define _DEFERFILESYS_H_ + +#pragma interface + +#include + +class DeferFilesys: public Filesystem +{ + friend class DeferComm; + + DeferComm *comm_p; + void setcomm(DeferComm *c) { comm_p = c; } +public: + DeferFilesys(const char *mpoint):Filesystem(mpoint) {} + DeferComm *comm() const { return comm_p; } +}; + +#endif /* _DEFERFILESYS_H_ */ Added: trunk/lib/CommBase.cc ============================================================================== --- trunk/lib/CommBase.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/lib/CommBase.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,217 @@ +// -*- C++ -*- +// Communications class +// +// This class copes with all the communication to and from the +// kernel for a userfs filesystem. +// The implementation of the base class is purely synchronous. +// +// This program is distributed under the terms of the +// Free Software Foundation General Public Licence. +// Copyright Jeremy Fitzhardinge 1993 + +#include +#include +#include +#include + +#pragma implementation + +#include "CommBase.h" +#include "Filesystem.h" + +#define _SYS_SELECT_H 1 +#include + +CommBase::CommBase(Filesystem &fs, unsigned int to, unsigned int from) + :tokern(to),filesys(fs) +{ + req = NULL; + for(int i=0; i < NDISP_PRI; i++) + dispqs[i].h = dispqs[i].t = NULL; + dispatches = 0; + fs.setcomm(this); +} + +CommBase::~CommBase() +{ + close(tokern); + tokern = (unsigned)-1; + CloseFDs(1); +} + +struct disp_fd +{ + disp_fd *next, *prev; + int fd; + DispatchFD *dfd; + int what; + int pri; + + ~disp_fd(); +}; + +disp_fd::~disp_fd() +{ + delete dfd; +} + +DispatchFD::~DispatchFD() +{ +} + +// Queue things on the end of the list to get round-robin type scheduling +// In a multithreaded filesystem this is important to allow multiple access +// to the filesystem +disp_fd * +CommBase::addDispatch(int fd, DispatchFD *dfd, int what, int pri) +{ + disp_fd *fdl = new disp_fd; + + if (pri >= NDISP_PRI) + pri = NDISP_PRI-1; + + fdl->prev = dispqs[pri].t; + fdl->next = NULL; + if (fdl->prev != NULL) + fdl->prev->next = fdl; + + dispqs[pri].t = fdl; + if (dispqs[pri].h == NULL) + dispqs[pri].h = fdl; + + fdl->fd = fd; + fdl->dfd = dfd; + fdl->what = what; + fdl->pri = pri; + + dispatches++; + return fdl; +} + +void +CommBase::delDispatch(disp_fd *fdl) +{ + if (fdl->dfd == req) + req = NULL; + + if (fdl->next != NULL) + fdl->next->prev = fdl->prev; + else + dispqs[fdl->pri].t = fdl->prev; + + if (fdl->prev != NULL) + fdl->prev->next = fdl->next; + else + dispqs[fdl->pri].h = fdl->next; + + fdl->next = fdl->prev = NULL; + + dispatches--; + delete fdl; +} + +// Wait on input filedescriptors for something to happen. +// Things which want to know about file descriptors (for read only) +// can register themselves. When select() returns, each +// matching dispatch routine is called so it can do what it likes. +// If a dispatch routine returns 0, it means it wants to be removed +// from the list; -1 indicates error and 1 means OK. If there +// are no routines on the list then CommBase::Run returns. +int +CommBase::Run() +{ + int ret; + + while(dispatches > 0) + { + int i; + + fd_set r_set, w_set, e_set; + FD_ZERO(&r_set); + FD_ZERO(&w_set); + FD_ZERO(&e_set); + + disp_fd *dfd; + int topfd = 0; + + for(i = NDISP_PRI-1; i >= 0; i--) + for(dfd = dispqs[i].h; dfd != NULL; dfd = dfd->next) + { + if (dfd->what & DISP_R) + FD_SET(dfd->fd, &r_set); + if (dfd->what & DISP_W) + FD_SET(dfd->fd, &w_set); + if (dfd->what & DISP_E) + FD_SET(dfd->fd, &e_set); + if (dfd->fd > topfd) + topfd = dfd->fd; + } + + ret = select(topfd+1, &r_set, &w_set, &e_set, NULL); + + if (ret == -1) + { + if (errno == EINTR) + continue; + else + { + perror("select failed"); + return ret; + } + } + if (ret == 0) + { + fprintf(stderr, "Comm::Run ret == 0\n"); + continue; + } + + disp_fd *next; + for (i = NDISP_PRI-1; i >= 0; i--) + for(dfd = dispqs[i].h; dfd != NULL; dfd = next) + { + int what = 0; + + next = dfd->next; + if (dfd->what & DISP_R && FD_ISSET(dfd->fd, &r_set)) + what |= DISP_R; + if (dfd->what & DISP_W && FD_ISSET(dfd->fd, &w_set)) + what |= DISP_W; + if (dfd->what & DISP_E && FD_ISSET(dfd->fd, &e_set)) + what |= DISP_E; + + if (what == 0) + continue; + + ret = dfd->dfd->dispatch(dfd->fd, what); + + if (ret == 1) + continue; + delDispatch(dfd); + if (ret != 0) + return ret; + } + } + + return 0; +} + +// Close filedescriptors we really don't need +void +CommBase::CloseFDs(int all) +{ + disp_fd *fdlp, *next; + + for(int i = 0; i < NDISP_PRI; i++) + for(fdlp = dispqs[i].h; fdlp != NULL; fdlp = next) + { + next = fdlp->next; + + if (all || fdlp->dfd != req) + delDispatch(fdlp); + } +} + +DispToKern::DispToKern(const CommBase *comm) +{ + tokern = comm->tokern; +} Added: trunk/lib/Filesystem.h ============================================================================== --- trunk/lib/Filesystem.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/lib/Filesystem.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,61 @@ +// -*- c++ -*- +// +// C++ classes for making user level filesystems easier +// +// This program is distributed under the terms of the +// Free Software Foundation General Public Licence. +// Copyright Jeremy Fitzhardinge 1993 + +#ifndef __FILESYSTEM_H_SEEN__ +#define __FILESYSTEM_H_SEEN__ + +#include + +#include +#include + +#include +#include + +#pragma interface + +typedef unsigned char Data; +class Comm; + +class Filesystem +{ + friend CommBase; + friend Inode; + + const char *mpoint; + + CommBase *comm_p; + void setcomm(CommBase *c) { comm_p = c; } + +protected: + InodeList inodes; + virtual int Enquire(up_ops op); + + Handle rootdir; + + // generate prototypes for operations methods +#define DO(op) virtual int do_##op(const up_preamble &, upp_repl &) +#define DOa(op) virtual int do_##op(const up_preamble &, upp_repl &, const upp_##op##_s &) +#define DOr(op) virtual int do_##op(const up_preamble &, upp_repl &, upp_##op##_r &) +#define DOar(op) virtual int do_##op(const up_preamble &, upp_repl &, const upp_##op##_s &, upp_##op##_r &) +#include "operations.h" + +public: + Filesystem(const char *mpoint); + virtual ~Filesystem(); + + Inode *findino(Handle h) { return inodes.find(h); } + + // Data contains the encoded reply on non-error return + // It should point to at least 4k of data. + int DoOp(const up_preamble &, upp_repl &, Data *data); + + CommBase *comm() const { return comm_p; } +}; + +#endif // __FILESYSTEM_H_SEEN__ Added: trunk/lib/CommBase.h ============================================================================== --- trunk/lib/CommBase.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/lib/CommBase.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,86 @@ +// -*- C++ -*- +// +// Class for kernel to process communications +// +// This program is distributed under the terms of the +// Free Software Foundation General Public Licence. +// Copyright Jeremy Fitzhardinge 1993 + +#ifndef __COMMBASE_H_SEEN__ +#define __COMMBASE_H_SEEN__ + +#include +#include + +#pragma interface + +class Filesystem; +class DispatchFD; +class DispToKern; + +// Flags for selecting type of select +#define DISP_R 1 +#define DISP_W 2 +#define DISP_E 4 + +// Number select dispatch priorities +#define NDISP_PRI 4 + +// Filesystem communications +class CommBase +{ + friend Filesystem; + friend DispToKern; + + // List of fd dispatch handers + struct dispq_t + { + struct disp_fd *h, *t; + } dispqs[NDISP_PRI]; + int dispatches; + + // fd to kernel + unsigned int tokern; + +protected: + // The filesystem we're part of. + Filesystem &filesys; + // Set up kernel fd dispatch handler + DispatchFD *req; + +public: + CommBase(Filesystem &, unsigned int to, unsigned int from); + virtual ~CommBase(); + + struct disp_fd *addDispatch(int fd, DispatchFD *dfd, int what=DISP_R, int pri = 2); + void delDispatch(struct disp_fd *); + + // This doesn't return until there is an IO error or EOF + int Run(); + + // Defer a reply for a child process to do + int DeferRepl(); + + // Close all fds we have open, and remove handlers + // all==1 means even the kernel connection + void CloseFDs(int all = 0); +}; + +// Dispatch class for FDs +class DispatchFD +{ +public: + virtual int dispatch(int fd, int what) = 0; + virtual ~DispatchFD(); +}; + +// A dispatcher which sends needs to send to the kernel +class DispToKern : public DispatchFD +{ +protected: + int tokern; +public: + DispToKern(const CommBase *); +}; + +#endif /* __COMMBASE_H_SEEN__ */ Added: trunk/lib/Makefile ============================================================================== --- trunk/lib/Makefile 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/lib/Makefile 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,58 @@ +# Makefile for library +TOP=.. +CPP=$(CC) +CPPFLAGS=-I. -I$(TOP)/lwp -I$(TOP)/utils -I$(TOP)/kernel -I$(TOP)/genser #-DDEBUG +CFLAGS=$(CPPFLAGS) +CXXFLAGS=$(CFLAGS) +LIB=libuserfs.a + +include $(TOP)/rules + +LIBOBJ = userfs_types.o Filesystem.o Inode.o SimpleInode.o DirInode.o \ + DeferFilesys.o CommBase.o Comm.o DeferComm.o ThreadComm.o \ + $(TOP)/utils/io.o + +all $(LIB):: $(LIB)($(LIBOBJ)) + +.SUFFIXES: .ty + +.ty.cc: $(GENCODE) + $(GENCODE) $(CPPFLAGS) -Csed $< > $@ || rm -f $@ + +.ty.h: $(GENHDR) + $(GENHDR) $(CPPFLAGS) -C $< > $@ || rm -f $@ + +TYPEFILE=$(TOP)/kernel/linux/userfs_types.ty + +userfs_types.o: userfs_types.cc userfs_types.h + +userfs_types.h: $(TYPEFILE) $(GENHDR) + $(GENHDR) $(CPPFLAGS) -C $< > $@ || rm -f $@ + +#userfs_types.cc: $(TYPEFILE) $(GENCODE) +# $(GENCODE) $(CPPFLAGS) -Csed $< > $@ + +# Generate only code we want +userfs_types.cc: $(TYPEFILE) $(GENCODE) + rm -rf types + mkdir types + $(GENCODE) $(CPPFLAGS) -Csed -l types $< + rm -f types/encode_*_s.cc types/decode_*_r.cc + cat types/* | awk ' \ + /^#(include.*)|pragma implementation/ { \ + if (!($$0 in seen)) { \ + seen[$$0] = 1; \ + } else next \ + } \ + { print $$0; }' > $@ + rm -fr types + +depend dep:: userfs_types.h coder.h + $(CPP) $(CPPFLAGS) -M *.cc *.c> .depend + +coder.h: + @-ln -s $(GENDIR)/coder.h . + +clean:: + rm -f *.[ao] *~ userfs_types.cc userfs_types.h + Added: trunk/ANNOUNCE ============================================================================== --- trunk/ANNOUNCE 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/ANNOUNCE 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,83 @@ + Announcing: userfs ALPHA version 0.9 + +Userfs is a mechanism by which normal user processes can be a Linux +filesystem, similar to Plan 9 filesystems or The Hurd's translators. +There are many uses for this, including: + +* Completely virtual filesystems and new interfaces * + +Add a filesystem-type interface to an existing mechanism, or a +filesystem interface as a new way of representing data. Sick of FTP? +How about: + + $ mkdir /ftp/tsx-11.mit.edu + $ cd /ftp/tsx-11.mit.edu/pub/Linux + $ cp README $HOME + +* Prototype filesystems * + +Prototype new block allocation algorithms in a user process and debug +with gdb before going into the compile-crash-reboot cycle of kernel +development. + +* Infrequent use filesystems * + +You want to mount "FooBaz 0X" filesystems under Linux, but you don't +want it that often, and you don't need it to be maximum speed. Rather +than trying to get the kernel itself to understand, or write +specialised tools, write a filesystem program. + +This release has some actual implementations of filesystems doing +things that I've been promising for the last few versions. It will +probably be much more interesting for non-programmers. + +This version is a loadable kernel module. There is no need to patch +the kernel source. + +There are no significant functional changes. The kernel code has been +updated to work in 1.2 and 1.3 kernels (tested only in 1.3.10). +There are a few minor bug fixes in the demo filesystems, but no +new functionality. I haven't tested the contrib stuff lately, so +it probably doesn't work. + +The release comes with six complete filesystems: + - ftpfs, a filesystem for FTP access. This allows multilple FTP + sites to be accessed as a filesystem, with a persistent cache of + data. + - homer, which simply creates a directory containing symlinks + to every user's home directory. Mounted on /u, it makes a + passible replacement for '~' expansion in your shell which + works for everything. + - intfs, an experimental filesystem in which file contents can + be generated by arbitary shell scripts on the fly as they are + read. + - egfs, a very simple example/tutorial filesystem + +And the contributed filesystems: + - arcfs which allows a compressed tar + file to be mounted readonly and browsed as a filesystem. + (Dave Gymer) + - mailfs, a simple mail-reading filesystem + (Davor Jadrijevic) + +Thanks also to Ulrich Dessauer for his C library interface and various +filesystems using it, including an OS/9 filesystem. + +This release is available from: + sunsite.unc.edu:pub/Linux/ALPHA/userfs/userfs-0.9.tar.gz + tsx-11.mit.edu:pub/linux/ALPHA/userfs/userfs-0.9.tar.gz +(as a last resort, since we have a slow link) + ftp.softway.com.au:pub/jeremy/linux/userfs-0.9.tar.gz + +* Mailing List * + +There is a USERFS channel on the linux activists list server. +To subscribe, send mail with + X-Mn-Admin: join USERFS +as the first line to linux-activists-request@niksula.hut.fi +(I'm not sure what the status of the linux-activist list manager +is, so I may set up a new mailing list) + +Please send bugs and comments to Jeremy Fitzhardinge +or to the mailing list. Send me mail if you find userfs interesting +and intend doing something with it. Added: trunk/filesystems/tarfs/tarfs.c ============================================================================== --- trunk/filesystems/tarfs/tarfs.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/tarfs/tarfs.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,477 @@ +/* (Read-only) archive filesystem. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include + +#include "tarfs.h" + +static char *mpoint; +static TAR_DIRENT *root; + +/* No point in this being in a seperate file. */ +#include + +static int +myread (int fd, void *buf, int sz) +{ + int rd = 0; + int ret; + + while (sz > 0) + { + ret = read (fd, buf, sz); + + if (ret == -1) + { + if (errno == EINTR) + continue; + + perror ("myread"); + exit (1); + } + + if (ret == 0) + break; + + sz -= ret; + buf += ret; + rd += ret; + } + + return rd; +} + +static int +mywrite (int fd, const void *buf, int sz) +{ + int wr = 0; + int ret; + + while (sz > 0) + { + ret = write (fd, buf, sz); + + if (ret == -1) + { + if (errno == EINTR) + continue; + FAIL ("write"); + exit (1); + } + + if (ret == 0) + { + fprintf (stderr, "write wrote 0 bytes\n"); + break; + } + + sz -= ret; + buf += ret; + wr += ret; + } + + return wr; +} + +static int +readpkt (int fd, up_preamble *pre, unsigned char *buf) +{ + int presz = sizeof_up_preamble (pre); + unsigned int rd; + unsigned char pbuf[presz]; + + memset (pbuf, 0, sizeof (pbuf)); + + rd = myread (fd, pbuf, presz); + if (rd != presz) + { + if (rd == 0) + return 0; + if (rd > 0) + fprintf (stderr, "readpkt, incomplete read (%d, not %d)\n", + rd, presz); + perror ("readpkt, header read"); + return -1; + } + + decode_up_preamble (pre, pbuf); + + if (pre->isreq != UP_ENQ && pre->isreq != UP_REQ) + fprintf (stderr, "pre->isreq = %d\n", pre->isreq); + + if (pre->version != UP_VERSION) + { + fprintf (stderr, "Version mismatch: us=%d them=%d\n", + UP_VERSION, pre->version); + return -1; + } + + if (pre->size != 0) + { + if (myread (fd, buf, pre->size) != pre->size) + { + perror ("readpkt, body read"); + return -1; + } + } + + return 1; +} + +static int +writepkt (int fd, upp_repl *repl, const unsigned char *buf) +{ + int replsz = sizeof_upp_repl (repl); + unsigned char pbuf[replsz]; + unsigned int wr; + unsigned char *p; + + assert (repl->version == UP_VERSION); + assert (repl->isreq == UP_REPL); + + p = encode_upp_repl (repl, pbuf); + + assert (replsz == p - pbuf); + + wr = mywrite (fd, pbuf, replsz); + if (wr != replsz) + { + perror ("writepkt, header write"); + return -1; + } + + if (repl->size > 0 && repl->err_no == 0) + { + if ( mywrite(fd, buf, repl->size) != repl->size) + { + perror ("writepkt, body write"); + return -1; + } + } + + return 1; +} + +static void +genpkt (upp_repl *repl, int seq, up_ops op) +{ + repl->version = UP_VERSION; + repl->seq = seq; + repl->op = op; + repl->isreq = 0; + repl->size = 0; + repl->err_no = 0; +} + +#define DIRINO 1 + +static int +do_iread (unsigned char *buf, upp_repl *repl) +{ + upp_iread_s rcv; + upp_iread_r snd; + + decode_upp_iread_s(&rcv, buf); + + memset(&snd, 0, sizeof(snd)); + + snd.ino.mode = 0444; + snd.handle = rcv.handle; + snd.ino.nlink = 1; + + if (rcv.handle.handle == DIRINO) + { + snd.ino.mode |= S_IFDIR | 0111; + snd.ino.mtime = 0; + snd.ino.ctime = 0; + snd.ino.atime = 0; + } + else + { + TAR_DIRENT *ent = (TAR_DIRENT *) rcv.handle.handle; + + if (ent->size != -1) + { + snd.ino.mode = ent->attr; + snd.ino.size = ent->size; + /* These numbers seem to be magic for Linux. */ + snd.ino.blksize = 512; + snd.ino.blocks = (ent->size + 511) / 512; + } + else + { + snd.ino.mode |= S_IFDIR | 0111; + snd.ino.size = 0; + } + snd.ino.gid = ent->gid; + snd.ino.uid = ent->uid; + snd.ino.mtime = ent->time; + snd.ino.ctime = ent->time; + snd.ino.atime = ent->time; + } + + + repl->size = encode_upp_iread_r(&snd, buf) - buf; + + return 0; +} + +static int +do_lookup (unsigned char *buf, upp_repl *repl) +{ + upp_lookup_s rcv; + upp_lookup_r snd; + TAR_DIRENT *ent; + + decode_upp_lookup_s(&rcv, buf); + + ent = (TAR_DIRENT *) rcv.dir.handle; + if (ent->size != -1) + return ENOTDIR; + + if (rcv.name.nelem == 2 + && rcv.name.elems[0] == '.' && rcv.name.elems[1] == '.') + { + ent = ent->pdir; + } + else if (rcv.name.nelem != 1 || rcv.name.elems[0] != '.') + { + ent = ent->data.dir.first; + while (ent) + { + /* Probably bombs out on prefixes... */ + if (!strncmp(ent->name, rcv.name.elems, rcv.name.nelem)) + break; + ent = ent->next; + } + } + FREE(rcv.name.elems); + if (!ent) + return ENOENT; + snd.handle.handle = (Ulong) ent; + + repl->size = encode_upp_lookup_r (&snd, buf) - buf; + + return 0; +} + +static int +do_readdir (unsigned char *buf, upp_repl *repl) +{ + upp_readdir_s rcv; + upp_readdir_r snd; + TAR_DIRENT *ent; + + decode_upp_readdir_s(&rcv, buf); + + ent = (TAR_DIRENT *) rcv.dir.handle; + if (ent->size != -1) + return ENOTDIR; + + snd.off = 0; + snd.name.nelem = 0; + + if (!rcv.off--) + { + snd.name.elems = "."; + } + else if (!rcv.off--) + { + snd.name.elems = ".."; + ent = ent->pdir; + } + else + { + ent = ent->data.dir.first; + while (ent && rcv.off--) + ent = ent->next; + if (ent) + { + snd.name.elems = ent->name; + } + } + + if (ent) + { + snd.off = 1; + snd.name.nelem = strlen (snd.name.elems); + snd.file.handle = (Ulong) ent; + } + + repl->size = encode_upp_readdir_r(&snd, buf) - buf; + + return 0; +} + +static int +do_open (unsigned char *buf, upp_repl *repl) +{ + upp_open_s rcv; + TAR_DIRENT *ent; + + decode_upp_open_s (&rcv, buf); + + ent = (TAR_DIRENT *) rcv.file.handle; + /* Directories are opened here, but read using _readdir instead of _read, + so all we do is return success! */ + if (ent->size == -1) + return 0; + + return a_open (ent); +} + +static int +do_close (unsigned char *buf, upp_repl *repl) +{ + upp_close_s rcv; + TAR_DIRENT *ent; + + decode_upp_close_s (&rcv, buf); + + ent = (TAR_DIRENT *) rcv.file.handle; + if (ent->size == -1) + return 0; + + return a_close (ent); +} + +static int +do_read (unsigned char *mbuf, upp_repl *repl) +{ + upp_read_s rcv; + upp_read_r snd; + TAR_DIRENT *ent; + int rc; + + snd.data.nelem = 0; + + decode_upp_read_s (&rcv, mbuf); + + ent = (TAR_DIRENT *) rcv.file.handle; + if (ent->size == -1) + return EISDIR; + + /* a_read will allocate its own buffer, so remember to free it */ + snd.data.elems = NULL; + rc = a_read (ent, rcv.off, rcv.size, &snd.data.nelem, &snd.data.elems); + if (rc) + return rc; + repl->size = encode_upp_read_r (&snd, mbuf) - mbuf; + + /* if(snd.data.elems) + free(snd.data.elems); */ + + return 0; +} + +static int +do_mount (unsigned char *buf, upp_repl *repl) +{ + upp_mount_r snd; + + snd.root.handle = (Ulong) root; + repl->size = encode_upp_mount_r(&snd, buf) - buf; + /* INIT */ + repl->size = encode_upp_mount_r(&snd, buf) - buf; + return 0; +} + +static void +run (int wr, int rd) +{ + up_preamble pre; + upp_repl repl; + /* Ah! The bogey man's a-coming to get me! */ + unsigned char buf[4096]; + int error; + + while(readpkt(rd, &pre, buf) == 1) + { + genpkt(&repl, pre.seq, pre.op); + + switch(pre.op) + { +#define DO(op, b, r) case userfs_up_##op: \ + error = (pre.isreq == UP_ENQ ? 0 : do_##op(b, r)); \ + break; + DO(mount, buf, &repl); + DO(iread, buf, &repl); + DO(lookup, buf, &repl); + DO(readdir, buf, &repl); + DO(open, buf, &repl); + DO(close, buf, &repl); + DO(read, buf, &repl); +#undef DO + default: + error = ENOSYS; + break; + } + + repl.err_no = error; + if (error != 0) + repl.size = 0; + + if (writepkt(wr, &repl, buf) != 1) + break; + } +} + +int +main (int argc, char **argv) +{ + int infd = 0; + int outfd = 1; + int c; + + while ((c = getopt (argc, argv, "i:o:m:")) != EOF) + switch(c) + { + case 'i': + infd = atoi(optarg); + break; + case 'o': + outfd = atoi(optarg); + break; + case 'm': + mpoint = optarg; + break; + default: + fprintf (stderr, "%s: bad option\n", argv[0]); + return 1; + } + + if (optind != argc - 1) + { + fprintf (stderr, "%s: no zipfile named\n", argv[0]); + return 1; + } + + root = arc_read (argv[optind++]); + if (!root) + return 1; + + signal (SIGCHLD, SIG_IGN); + + run(outfd, infd); + + return 0; +} Added: trunk/filesystems/tarfs/tarfs.h ============================================================================== --- trunk/filesystems/tarfs/tarfs.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/tarfs/tarfs.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,47 @@ +#ifndef _TARFS_H +#define _TARFS_H + +#define FAIL(str) fprintf(stderr, "%s:%d %s failed with errno = %s (%d)\n", __FILE__, __LINE__, str, strerror(errno), errno) +#ifdef DEBUG +#include +#include +#define DB(x) {x;} +#else +#define DB(x) /**/ +#endif + +typedef struct tagDIRENT TAR_DIRENT; + +struct tagDIRENT { + TAR_DIRENT *next; + /* The directory to which this belongs (or itself if this is the root + directory). */ + TAR_DIRENT *pdir; + /* -1 for a directory. */ + long size; + int attr; + time_t time; + gid_t gid; + uid_t uid; + union { + struct { + /* long csize; */ + unsigned long offset; + unsigned int refc; /* PRIVATE to `unzip.c'. */ + } file; + struct { + TAR_DIRENT *first; + FILE *fd; + } dir; + } data; + char *name; + /* Structure is then expanded to whatever... */ + char fullname[1]; /* PRIVATE to `zip.c'. */ +}; + +int a_open (TAR_DIRENT *); +int a_close (TAR_DIRENT *); +int a_read (TAR_DIRENT *, long, long, unsigned long *, unsigned char **); +TAR_DIRENT *arc_read (const char *); + +#endif /* _TARFS_H */ Added: trunk/filesystems/tarfs/rt.c ============================================================================== --- trunk/filesystems/tarfs/rt.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/tarfs/rt.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,94 @@ +#include +#include + +#define TARBLOCK 512 + +#define TARLEN(x) (((x)+TARBLOCK-1)&~(TARBLOCK-1)) + +typedef struct _tarinfo +{ + long offset; + char *filename; + int attr; + int uid; + int gid; + int length; + int time; + int date; +} tarinfo; + +char *savestring(unsigned char **p) +{ + char *str ; + int len = strlen(*p)+1; + + str = (char *)malloc(len); + strcpy(str,*p); + (*p) += len; + + return str; +} + +int read_octal(unsigned char **p) +{ + int x=0; + + while((**p==0) || (**p==' ')) (*p)++; + + while(('0' <= (**p)) && ('7' >= (**p))) + { + x<<=3; + x+=(**p-'0'); + (*p)++; + } + + return x; +} + +int read_tarindex(FILE *tar, tarinfo *head) +{ + static unsigned char tmp[TARBLOCK]; + unsigned char *p = tmp; + + head->offset = ftell(tar); + if(1 != fread(tmp, TARBLOCK, 1, tar)) + return 1; + + if(!p[0]) + return 1; + + head->filename = savestring(&p); + head->attr = read_octal(&p); + head->uid = read_octal(&p); + head->gid = read_octal(&p); + head->length = read_octal(&p); + head->time = read_octal(&p); + head->date = read_octal(&p); + + return 0; +} + +main(int argc, char ** argv) +{ + FILE *tar = fopen(argv[1],"rb"); + tarinfo tar_entry; + + if(!tar) + { + fprintf(stderr,"Can't open tar file\n"); + return 1; + } + + while(0==read_tarindex(tar,&tar_entry)) + { + printf("%s\n",tar_entry.filename); + printf("attr\t= %x\n",tar_entry.attr); + printf("len\t= %x\n",tar_entry.length); + if(0>fseek(tar,TARLEN(tar_entry.length),SEEK_CUR)) + break; + } + + fclose(tar); + + return 0; +} Added: trunk/filesystems/tarfs/tarvfs.c ============================================================================== --- trunk/filesystems/tarfs/tarvfs.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/tarfs/tarvfs.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,288 @@ +/* TAR Archive VFS layer. */ + +/* +** Derived from arcvfs.c originally by David P. Gymer +** Modified by Michael McCormack to read tar files directly. +*/ + +#include +#include +#include +#include +#include +#include + +#include "tarvfs.h" + +#define TARBLOCK 512 +#define TARDIR 0x400 + +#define TARLEN(x) (((x)+TARBLOCK-1)&~(TARBLOCK-1)) + +typedef struct _tarinfo +{ + long offset; + char *filename; + int attr; + int uid; + int gid; + int length; + int time; + int date; +} tarinfo; + +TAR_DIRENT * +create_entry (const char *fname, const char *name, TAR_DIRENT *dir) +{ + TAR_DIRENT *ent; + + ent = malloc (sizeof (TAR_DIRENT) + strlen (fname)); + if (ent) + { + strcpy (ent->fullname, fname); + ent->name = ent->fullname + (name - fname); + ent->pdir = dir; + ent->next = 0; + } + return ent; +} + +TAR_DIRENT * +create_dirent (char *fname, char *name, TAR_DIRENT **p_ent, TAR_DIRENT *dir) +{ + char *s; + + if (!p_ent) + return 0; + + while ((s = strchr (name, '/')) != 0) + { + *s = '\0'; + while (*p_ent && strcmp (name, (*p_ent)->name)) + p_ent = &(*p_ent)->next; + if (!*p_ent) + { + *p_ent = create_entry (fname, name, dir); + if (!*p_ent) + return 0; + (*p_ent)->size = -1; + (*p_ent)->data.dir.first = 0; + } + /* Check for directory/file clash. */ + if ((*p_ent)->size != -1) + return 0; + dir = *p_ent; + p_ent = &(*p_ent)->data.dir.first; + *s++ = '/'; + name = s; + } + + while (*p_ent) + p_ent = &(*p_ent)->next; + + *p_ent = create_entry (fname, name, dir); + return *p_ent; +} + +static TAR_DIRENT * +root_ent (TAR_DIRENT *ent) +{ + while (ent->pdir != ent) + ent = ent->pdir; + return ent; +} + +/* The generic read/write code. */ + +int +a_open (TAR_DIRENT *ent) +{ + if(ent->size == -1) + return EIO; + ++ent->data.file.refc; + return 0; +} + +int +a_close (TAR_DIRENT *ent) +{ + if (!ent->data.file.refc) + return EBADF; + --ent->data.file.refc; + return 0; +} + +/* +** This function needs to read data into a buffer of some +** arbitary size, which is not provided. Make sure the calling +** function frees the data in *elems when it is done with it. +*/ +int a_read (TAR_DIRENT *ent, long off, long size, + unsigned long *nelem, unsigned char **elems) +{ + TAR_DIRENT *root = root_ent (ent); + + if(!root) + { + fprintf(stderr,"couldn't get the root directory\n"); + return EINVAL; + } + + if (!ent->data.file.refc) + { + fprintf(stderr,"tried to read an unopened file\n"); + return EINVAL; + } + + if (ent->size == -1) + { + fprintf(stderr,"tried to read a directory\n"); + return EINVAL; + } + + *elems = NULL; + *nelem = 0; + + if(size > (ent->size - off)) + size = ent->size - off; + + if(size) + *elems = (unsigned char *) malloc(size); + + if(*elems) + { + fseek(root->data.dir.fd, ent->data.file.offset, SEEK_SET); + *nelem = fread(*elems, 1, size, root->data.dir.fd); + if(*nelem < 0) + return EIO; + if(*nelem != size) + fprintf(stderr,"couldn't read all the data.\n"); + } + + return 0; +} + +char *savestring(unsigned char **p) +{ + char *str ; + int len = strlen(*p)+1; + + str = (char *)malloc(len); + strcpy(str,*p); + (*p) += len; + + return str; +} + +int read_octal(unsigned char **p) +{ + int x=0; + + while((**p==0) || (**p==' ')) (*p)++; + + while(('0' <= (**p)) && ('7' >= (**p))) + { + x<<=3; + x+=(**p-'0'); + (*p)++; + } + + return x; +} + +int read_tarindex(FILE *tar, tarinfo *head) +{ + static unsigned char tmp[TARBLOCK]; + unsigned char *p = tmp; + + head->offset = ftell(tar); + if(1 != fread(tmp, TARBLOCK, 1, tar)) + return 1; + + if(!p[0]) + return 1; + + head->filename = savestring(&p); + head->attr = read_octal(&p); + head->uid = read_octal(&p); + head->gid = read_octal(&p); + head->length = read_octal(&p); + head->time = read_octal(&p); + head->date = read_octal(&p); + + return 0; +} + +/* The VFS code itself. */ + +TAR_DIRENT * +arc_read (const char *tarfile) +{ + TAR_DIRENT *first = NULL, *ent = NULL; + FILE *tar = fopen(tarfile,"rb"); + tarinfo tar_entry; + struct stat st; + + if(!tar) + { + fprintf(stderr,"Can't open tar file\n"); + return NULL; + } + + stat(tarfile,&st); + + first = create_entry (tarfile, tarfile, 0); + if (!first) + return NULL; + + first->pdir = first; + first->size = -1; + first->data.dir.first = 0; + first->name = NULL; + first->data.dir.fd = tar; + first->gid = st.st_gid; + first->uid = st.st_uid; + first->time = st.st_mtime; + + while(0==read_tarindex(tar,&tar_entry)) + { + ent = create_dirent (tar_entry.filename, + tar_entry.filename, + &first->data.dir.first, + first); + if(!ent) + break; + + if(tar_entry.attr & TARDIR) + { + /* create dirent */ + ent->size = -1; + ent->data.dir.first = 0; + } + else + { + /* create normal file */ + ent->size = tar_entry.length; + ent->data.file.refc = 0; + ent->data.file.offset = tar_entry.offset + TARBLOCK; + } + ent->gid = tar_entry.gid; + ent->uid = tar_entry.uid; + ent->attr = tar_entry.attr; + ent->time = tar_entry.time; + ent->next = NULL; + if(0>fseek(tar,TARLEN(tar_entry.length),SEEK_CUR)) + break; + } + + if(!ent) + { + free(first); + first=NULL; + fclose(tar); + fprintf (stderr, "%s: not a tar archive!\n", tarfile); + } + + return first; +} + Added: trunk/filesystems/tarfs/tarvfs.h ============================================================================== --- trunk/filesystems/tarfs/tarvfs.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/tarfs/tarvfs.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,9 @@ +#ifndef _TARVFS_H +#define _TARVFS_H + +#include "tarfs.h" + +TAR_DIRENT *create_entry (const char *, const char *, TAR_DIRENT *); +TAR_DIRENT *create_dirent (char *, char *, TAR_DIRENT **, TAR_DIRENT *); + +#endif /* _TARVFS_H */ Added: trunk/filesystems/tarfs/Makefile ============================================================================== --- trunk/filesystems/tarfs/Makefile 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/tarfs/Makefile 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,37 @@ +CC = gcc +CFLAGS = -O2 -Wall -I../../kernel +CPPFLAGS = #-DDEBUG +LDFLAGS = -s + +NAME = tarfs +SRCS = tarfs.c tarvfs.c +INC = tarvfs.h tarfs.h +DISTS = $(SRCS) $(INC) README Makefile + +$(NAME) : $(SRCS:%.o=%.c) + +.PHONY : dist dep clean realclean spotless + +dep : .depend +.depend : $(SRCS) $(INC) + $(CC) $(CFLAGS) -MM *.c > .depend + +dist : $(DISTS) + rm -rf /tmp/$(NAME) + mkdir /tmp/$(NAME) + cp -a $(DISTS) /tmp/$(NAME) + (cd /tmp; tar cfvz - $(NAME)) > $(NAME).tar.gz + rm -rf /tmp/$(NAME) + +clean : + rm -f *.o core *~ *.orig *.rej tarfs + +realclean : clean + rm -rf $(NAME) + +spotless : realclean + rm -f .depend + +ifeq (.depend,$(wildcard .depend)) +include .depend +endif Added: trunk/filesystems/tarfs/README ============================================================================== --- trunk/filesystems/tarfs/README 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/tarfs/README 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,12 @@ +TARFS - transparent read-only TAR file access for Linux + +Copyright (C) 1999 Michael J McCormack + +Derived in part from code written by Jeremy Fitzhardinge + and David P Gymer + +The idea of using a command line to read the tar file's data irked me a little +and for some practice in userfs, i decided to rewrite the arcfs code to +access a tar file directly. This code will only access a tar file, not a +gzipped tar file! (might try to do that a little later...) + Added: trunk/filesystems/yfs/yfs.c ============================================================================== --- trunk/filesystems/yfs/yfs.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/yfs/yfs.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,705 @@ +/* (Read-only) archive filesystem. */ + +#define CVS + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#define Y_MAGIC 0x005D595D + +typedef struct Y_DIRENT { + int magic; + int fd; + int ref_count; + struct Y_DIRENT *parent; + struct Y_DIRENT *next; + struct Y_DIRENT *child; + char name[1]; +} Y_DIRENT; + +static char *mpoint; +static Y_DIRENT *root; + +unsigned char *delete_me = NULL; + +/* No point in this being in a seperate file. */ +#include + +#define FAIL(str) fprintf(stderr, "%s:%d %s failed with errno = %s (%d)\n", \ + __FILE__, __LINE__, str, strerror(errno), errno) + +static int +myread (int fd, void *buf, int sz) +{ + int rd = 0; + int ret; + + while (sz > 0) + { + ret = read (fd, buf, sz); + + if (ret == -1) + { + if (errno == EINTR) + continue; + + perror ("myread"); + exit (1); + } + + if (ret == 0) + break; + + sz -= ret; + buf += ret; + rd += ret; + } + + return rd; +} + +static int +mywrite (int fd, const void *buf, int sz) +{ + int wr = 0; + int ret; + + while (sz > 0) + { + ret = write (fd, buf, sz); + + if (ret == -1) + { + if (errno == EINTR) + continue; + FAIL ("write"); + exit (1); + } + + if (ret == 0) + { + fprintf (stderr, "write wrote 0 bytes\n"); + break; + } + + sz -= ret; + buf += ret; + wr += ret; + } + + return wr; +} + +static int +readpkt (int fd, up_preamble *pre, unsigned char *buf) +{ + int presz = sizeof_up_preamble (pre); + unsigned int rd; + unsigned char pbuf[presz]; + + memset (pbuf, 0, sizeof (pbuf)); + + rd = myread (fd, pbuf, presz); + if (rd != presz) + { + if (rd == 0) + return 0; + if (rd > 0) + fprintf (stderr, "readpkt, incomplete read (%d, not %d)\n", + rd, presz); + perror ("readpkt, header read"); + return -1; + } + + decode_up_preamble (pre, pbuf); + + if (pre->isreq != UP_ENQ && pre->isreq != UP_REQ) + fprintf (stderr, "pre->isreq = %d\n", pre->isreq); + + if (pre->version != UP_VERSION) + { + fprintf (stderr, "Version mismatch: us=%d them=%d\n", + UP_VERSION, pre->version); + return -1; + } + + if (pre->size != 0) + { + if (myread (fd, buf, pre->size) != pre->size) + { + perror ("readpkt, body read"); + return -1; + } + } + + return 1; +} + +static int +writepkt (int fd, upp_repl *repl, const unsigned char *buf) +{ + int replsz = sizeof_upp_repl (repl); + unsigned char pbuf[replsz]; + unsigned int wr; + unsigned char *p; + + assert (repl->version == UP_VERSION); + assert (repl->isreq == UP_REPL); + + p = encode_upp_repl (repl, pbuf); + + assert (replsz == p - pbuf); + + wr = mywrite (fd, pbuf, replsz); + if (wr != replsz) + { + perror ("writepkt, header write"); + return -1; + } + + if (repl->size > 0 && repl->err_no == 0) + { + if ( mywrite(fd, buf, repl->size) != repl->size) + { + perror ("writepkt, body write"); + return -1; + } + } + + return 1; +} + +static void +genpkt (upp_repl *repl, int seq, up_ops op) +{ + repl->version = UP_VERSION; + repl->seq = seq; + repl->op = op; + repl->isreq = 0; + repl->size = 0; + repl->err_no = 0; +} + +/* construct path name without trailing slash */ +static int +get_path(char *name, int size, Y_DIRENT *t) +{ + int len,plen; + + if(!t) + return ENOENT; + len = strlen(t->name)+1; /* include trailing zero byte */ + if(len>size) + return ENOENT; + if(t->parent != t) { + len++; /* include slash */ + if(0>(plen=get_path(name, size - len, t->parent))) + return ENOENT; + strcat(name,"/"); + strcat(name,t->name); + } + else + { + plen=0; + strcpy(name,t->name); + } + return plen+len; +} + +int ReadChildren(Y_DIRENT *ent) +{ + /* read the directory into memory */ + Y_DIRENT *t; + char buffer[1024],filename[1024],*p; + struct dirent *de=(struct dirent *)buffer; + int len,n,fd; + + if(0>get_path(filename, sizeof filename, ent)) + return ENOTDIR; + + fprintf(stderr,"reading dir: %s\n",buffer); + + fd = open(filename,O_RDONLY); + if(!fd) + return ENOTDIR; + +#ifdef CVS + /* ok, now prepare to stat each file by adding it to the buffer */ + p = &filename[strlen(filename)]; + *p++ = '/'; +#endif + + while(1) { + de=(struct dirent *)&buffer[0]; + n=0; + len=getdents(fd, de, sizeof buffer); + if(!len) + break; + while(nd_name,".") && strcmp(de->d_name,"..")) + { + int add_file = 1; + +#ifdef CVS + /* check that the file is a CVS version or a directory */ + if(strcmp(&de->d_name[strlen(de->d_name)-2],",v")) + { + struct stat st; + + /* stat the file */ + strcpy(p,de->d_name); + if(0>stat(filename,&st)) + add_file = 0; + if(!S_ISDIR(st.st_mode)) + add_file = 0; + } + else + { + /* remove the ,v */ + de->d_name[strlen(de->d_name)-2]=0; + add_file = 1; + } +#endif + + if(add_file) + { + t = malloc(sizeof (Y_DIRENT) + strlen(de->d_name)); + strcpy(t->name,de->d_name); + t->magic = Y_MAGIC; + t->fd = 0; + t->ref_count=0; + t->parent = ent; + t->child = NULL; + + fprintf(stderr,"adding entry: %s\n",t->name); + + /* add this to the head of the parent's child list */ + t->next = ent->child; + ent->child = t; + } + } + n+=de->d_reclen; + de = (struct dirent *)&buffer[n]; + } + } + close(fd); + + return 0; +} + +#define DIRINO 1 + +static int +do_iread (unsigned char *buf, upp_repl *repl) +{ + upp_iread_s rcv; + upp_iread_r snd; + struct stat st; + Y_DIRENT *ent ; + char name[1024]; + + decode_upp_iread_s(&rcv, buf); + + memset(&snd, 0, sizeof(snd)); + + ent = (Y_DIRENT *) rcv.handle.handle; + snd.handle = rcv.handle; + + if(0 > get_path(name,sizeof name, ent)) + return ENOENT; + + fprintf(stderr,"stat on file: %s\n",name); + + /* if the file exists, add it to our tree */ + if(0>lstat(name,&st)) + { +#ifdef CVS + strcat(name,",v"); + if(0>lstat(name,&st)) +#endif + return ENOENT; + } + + /* copy from one filesystem to the other */ + snd.ino.mode = st.st_mode; + snd.ino.size = st.st_size; + snd.ino.uid = st.st_uid; + snd.ino.gid = st.st_gid; + snd.ino.nlink = st.st_nlink; + snd.ino.blksize = st.st_blksize; + snd.ino.blocks = st.st_blocks; + snd.ino.mtime = st.st_mtime; + snd.ino.atime = st.st_atime; + snd.ino.ctime = st.st_ctime; + snd.ino.rdev = st.st_rdev; + + repl->size = encode_upp_iread_r(&snd, buf) - buf; + + return 0; +} + +static int +do_lookup (unsigned char *buf, upp_repl *repl) +{ + upp_lookup_s rcv; + upp_lookup_r snd; + Y_DIRENT *ent; + Y_DIRENT *t; + + decode_upp_lookup_s(&rcv, buf); + + ent = (Y_DIRENT *) rcv.dir.handle; + + if (rcv.name.nelem == 2 + && rcv.name.elems[0] == '.' && rcv.name.elems[1] == '.') + { + t = ent->parent; + } + else if (rcv.name.nelem == 1 && rcv.name.elems[0] == '.') + { + t = ent; + } + else + { + if(!ent->child) + ReadChildren(ent); + for(t = ent->child; t; t=t->next) + { + /* check the length */ + if(t->name[rcv.name.nelem]) + continue; + if (!strncmp(t->name, rcv.name.elems, rcv.name.nelem)) + break; + } + if(!t) + { + char name[1024]; + struct stat st; + int len; + + /* construct a path name to the file */ + len = get_path(name,sizeof name, ent); + if((len+rcv.name.nelem+1) > sizeof name) + return ENOENT; + strcat(name,"/"); + strncat(name,rcv.name.elems,rcv.name.nelem); + name[len+rcv.name.nelem]=0; + + fprintf(stderr,"looking up: %s\n",name); + + /* if the file exists, add it to our tree */ + if(0>stat(name,&st)) + return ENOENT; + + /* make the new entry */ + t = (Y_DIRENT *) malloc(sizeof(Y_DIRENT)+rcv.name.nelem); + strncpy(t->name,rcv.name.elems,rcv.name.nelem); + name[rcv.name.nelem]=0; + t->magic = Y_MAGIC; + t->fd = 0; + t->ref_count=0; + t->parent = ent; + t->child = NULL; + + /* add it to the head of the child list */ + t->next = ent->child; + ent->child = t; + } + } + FREE(rcv.name.elems); + if (!t) + return ENOENT; + snd.handle.handle = (Ulong) t; + + repl->size = encode_upp_lookup_r (&snd, buf) - buf; + + return 0; +} + +/* read the elements in a directory */ +static int +do_readdir (unsigned char *buf, upp_repl *repl) +{ + upp_readdir_s rcv; + upp_readdir_r snd; + Y_DIRENT *ent; + Y_DIRENT *t; + + decode_upp_readdir_s(&rcv, buf); + + ent = (Y_DIRENT *) rcv.dir.handle; + + snd.off = 0; + snd.name.nelem = 0; + + /* if there are no children, try and read some */ + if(!ent->child) + ReadChildren(ent); + + /* now just look up the appropriate offset */ + switch(rcv.off) { + case 0: + snd.name.elems = "."; + t = ent; + break; + case 1: + snd.name.elems = ".."; + t = ent->parent; + break; + default: + rcv.off-=2; + for(t=ent->child; t && rcv.off--; t=t->next); + if (t) + snd.name.elems = t->name; + } + + if(t) { + snd.off = 1; + snd.name.nelem = strlen (snd.name.elems); + snd.file.handle = (Ulong) t; + } + + repl->size = encode_upp_readdir_r(&snd, buf) - buf; + + return 0; +} + +static int +do_open (unsigned char *buf, upp_repl *repl) +{ + upp_open_s rcv; + Y_DIRENT *ent; + char filename[1024]; + + decode_upp_open_s (&rcv, buf); + + ent = (Y_DIRENT *) rcv.file.handle; + + if(ent->magic != Y_MAGIC) + return EPERM; + + if(!ent->ref_count) + { + if(0>get_path(filename,sizeof filename,ent)) + return EPERM; + ent->fd = open ( filename, O_RDONLY); + if(ent->fd<0) + return -ent->fd; + } + ent->ref_count++; + + return 0; +} + +static int +do_close (unsigned char *buf, upp_repl *repl) +{ + upp_close_s rcv; + Y_DIRENT *ent; + + decode_upp_close_s (&rcv, buf); + + ent = (Y_DIRENT *) rcv.file.handle; + + if(!ent->ref_count) + return EPERM; + + ent->ref_count--; + if(!ent->ref_count) + { + close(ent->fd); + ent->fd = 0; + } + + return 0; +} + +static int +do_read (unsigned char *mbuf, upp_repl *repl) +{ + upp_read_s rcv; + upp_read_r snd; + Y_DIRENT *ent; + int rc; + long size; + + snd.data.nelem = 0; + snd.data.elems = NULL; + + decode_upp_read_s (&rcv, mbuf); + + ent = (Y_DIRENT *) rcv.file.handle; + + /* check that the file is actually open */ + if(!ent->ref_count) + return EPERM; + + size = lseek(ent->fd,0,SEEK_END); + if(0>lseek(ent->fd,rcv.off,SEEK_SET)) + return EPERM; + + if( (size - rcv.off) < rcv.size ) + size = (size - rcv.off); + else + size = rcv.size; + + /* where is this going to be free'd ? */ + if(size) + snd.data.elems = (unsigned char *)malloc(size); + + if(snd.data.elems) + { + rc = read(ent->fd,snd.data.elems,size); + if(rc < 0) + return rc; + snd.data.nelem = rc; + } + + repl->size = encode_upp_read_r (&snd, mbuf) - mbuf; + + /* hack alert! */ + delete_me = snd.data.elems; + + return 0; +} + +static int +do_mount (unsigned char *buf, upp_repl *repl) +{ + upp_mount_r snd; + + snd.root.handle = (Ulong) root; + repl->size = encode_upp_mount_r(&snd, buf) - buf; + /* INIT */ + repl->size = encode_upp_mount_r(&snd, buf) - buf; + return 0; +} + +static void +run (int wr, int rd) +{ + up_preamble pre; + upp_repl repl; + /* Ah! The bogey man's a-coming to get me! */ + unsigned char buf[4096]; + int error; + + while(readpkt(rd, &pre, buf) == 1) + { + genpkt(&repl, pre.seq, pre.op); + + switch(pre.op) + { +#define DO(op, b, r) case up_##op: \ + error = (pre.isreq == UP_ENQ ? 0 : do_##op(b, r)); \ + break; + DO(mount, buf, &repl); + DO(iread, buf, &repl); + DO(lookup, buf, &repl); + DO(readdir, buf, &repl); + DO(open, buf, &repl); + DO(close, buf, &repl); + DO(read, buf, &repl); +#undef DO + default: + error = ENOSYS; + break; + } + + repl.err_no = error; + if (error != 0) + repl.size = 0; + + if (writepkt(wr, &repl, buf) != 1) + break; + + /* this is a terrible hack! */ + if(delete_me) + { + free(delete_me); + delete_me = NULL; + } + } +} + +Y_DIRENT *y_read(char *rootname) +{ + Y_DIRENT *root; + + root = (Y_DIRENT*)malloc(sizeof(Y_DIRENT)+strlen(rootname)); + + root->magic = Y_MAGIC; + root->fd = 0; + root->ref_count = 1; + root->parent = root; + root->next = NULL; + root->child = NULL; + strcpy(root->name,rootname); + + fprintf(stderr,"mounting mirror file system of %s\n",root->name); + + return root; +} + +int +main (int argc, char **argv) +{ + int infd = 0; + int outfd = 1; + int c; + + while ((c = getopt (argc, argv, "i:o:m:")) != EOF) + switch(c) + { + case 'i': + infd = atoi(optarg); + break; + case 'o': + outfd = atoi(optarg); + break; + case 'm': + mpoint = optarg; + break; + default: + fprintf (stderr, "%s: bad option\n", argv[0]); + return 1; + } + + if (optind != argc - 1) + { + fprintf (stderr, "%s: no zipfile named\n", argv[0]); + return 1; + } + + root = y_read (argv[optind++]); + if (!root) + return 1; + + signal (SIGCHLD, SIG_IGN); + + run(outfd, infd); + + return 0; +} Added: trunk/filesystems/yfs/Makefile ============================================================================== --- trunk/filesystems/yfs/Makefile 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/yfs/Makefile 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,35 @@ +CC = gcc +CFLAGS = -O2 -Wall -I../../kernel +CPPFLAGS = #-DDEBUG +LDFLAGS = -s + +SRCS = yfs.c +DISTS = $(SRCS) README Makefile + +yfs : yfs.o + +.PHONY : dist dep clean realclean spotless + +dep : .depend +.depend : $(SRCS) + $(CC) $(CFLAGS) -MM *.c > .depend + +dist : $(DISTS) + rm -rf /tmp/yfs + mkdir /tmp/yfs + cp -a $(DISTS) /tmp/yfs + (cd /tmp; tar cfvz - yfs) >yfs.tar.gz + rm -rf /tmp/yfs + +clean : + rm -f *.o core *~ *.orig *.rej + +realclean : clean + rm -rf yfs + +spotless : realclean + rm -f .depend + +ifeq (.depend,$(wildcard .depend)) +include .depend +endif Added: trunk/filesystems/ftpfs/ftpfile.h ============================================================================== --- trunk/filesystems/ftpfs/ftpfile.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/ftpfile.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,53 @@ +// -*- C++ -*- + +#ifndef _FTPFILE_H_ +#define _FTPFILE_H_ + +#pragma interface + +#include "ino.h" +#include +#include +#include + +class ftpfile : public ino +{ + friend class docopy; + + class ftpdir *dir; + class ftpconn *conn; + string name; + + int do_read(const up_preamble &, upp_repl &, + const upp_read_s &, upp_read_r &); + int do_iput(const up_preamble &, upp_repl &, + const upp_iput_s &); + + int updatefile(); + int updating; + class LWP *upd_thread; + + struct waiting *wlist; + struct waiting *addwlist(off_t off); + void delwlist(struct waiting *); + + int open(int=0,int=0666); // Open cache file + void close(); // Close it + int fd; // fd of cache file + + void decref(); + + int read(unsigned char *, size_t, off_t); +public: + ftpfile(class ftpfs &, const string &name, class ftpdir *dir, class ftpconn *conn); + ~ftpfile(); + + int is_uptodate() const; + void setstats(size_t size, time_t time); + void getstats(size_t &sz, time_t &time) const + { + sz = size; + time = mtime; + } +}; +#endif /* _FTPFILE_H_ */ Added: trunk/filesystems/ftpfs/Path.cc ============================================================================== --- trunk/filesystems/ftpfs/Path.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/Path.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,76 @@ +// -*- C++ -*- + +// Pathname handling + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#pragma implementation + +#include "Path.h" +#include +#include +#include +#include +#include + +Path::Path(const string &elem, const Path *parent) + :_parent(parent) +{ + p_rep = new _PathRep(elem, parent ? parent->p_rep : (const _PathRep *)NULL); +} + +Path::Path(const Path &p) +{ + memcpy(this, &p, sizeof(*this)); + p_rep->incref(); +} + +Path & +Path::operator = (const Path &p) +{ + if (this != &p) + { + p_rep->decref(); + *this = p; + p_rep->incref(); + } + return *this; +} + +Path::~Path() +{ + p_rep->decref(); +} + +_PathRep::_PathRep(const string &elem, const _PathRep *p) + :_path(elem), _parent(p) +{ + count = 1; + if (p) + ((_PathRep *)p)->incref(); // XXX +} + +_PathRep::~_PathRep() +{ + assert(count == 0); + if (_parent != NULL) + ((_PathRep *)_parent)->decref(); // XXX +} + +string +_PathRep::path() const +{ + string p; + + if (_parent != NULL) + { + p = _parent->path(); + cat(p, "/", _path, p); + } + else + p = _path; + + return p; +} Added: trunk/filesystems/ftpfs/topdir.cc ============================================================================== --- trunk/filesystems/ftpfs/topdir.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/topdir.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,188 @@ +// -*- C++ -*- + +// Top directory +// This is initialized from the cache directory, but users can +// create directories with the names of hostnames. Directories +// are always created with the official hostname of a machine, +// with all the alises appearing as symlinks. + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#pragma implementation + +#include +#include +#include +#include + +#include +#include +#include + +#include "ftpfs.h" +#include "topdir.h" +#include "sitetopdir.h" +#include "ftpconn.h" +#include "ftplink.h" + +int +topdir::do_create(const up_preamble &, upp_repl &, + const upp_create_s &arg, upp_create_r &ret) +{ + if (!S_ISDIR(arg.mode)) + return EPERM; + + string name((char *)arg.name.elems, (int)arg.name.nelem); + + return create(name, ret.file); +} + +int +topdir::create(const string &name, up_handle &handle) +{ + struct hostent *he = gethostbyname((const char *)name.data()); + + if (!he) + { + cerr << "Hostname lookup for " << name << " failed:", + herror(""); + return ENOENT; + } + + struct hostent *rhe = NULL; + string hostname = he->h_name; // First guess + + if (!he->h_addr_list[0] || he->h_addrtype != AF_INET) + { + cerr << name << ": no address associated with name\n"; + return ENOENT; + } + + cout << "IP for " << name << " is " + << (unsigned)(unsigned char)(he->h_addr_list[0][0]) << '.' + << (unsigned)(unsigned char)(he->h_addr_list[0][1]) << '.' + << (unsigned)(unsigned char)(he->h_addr_list[0][2]) << '.' + << (unsigned)(unsigned char)(he->h_addr_list[0][3]) << ".\n"; + + char *xaddr = new char[he->h_length]; + if (xaddr) + { + // Avoid stepping on buffers + + memcpy(xaddr, he->h_addr_list[0], he->h_length); + + rhe = gethostbyaddr(xaddr, he->h_length, he->h_addrtype); + delete xaddr; + } + + cout << "Reverse lookup " << (rhe ? "succeeded\n" : "failed\n"); + + if (rhe) + hostname = rhe->h_name; // Reverse lookup is better + + cout << "Official name of " << name << " is " << hostname << '\n'; + + if (lookup(name)) // Already exists? + return EEXIST; + else + { + DirEntry *de = lookup(hostname); + + if (!de) + { + Inode *ino = new sitetopdir(filesys, hostname, this); + link(hostname, ino); + handle.handle = ino->gethandle(); + } + if (name != hostname) + { + Inode *ino = new ftplink(filesys, hostname, this, name); + if (link(name, ino)) + delete ino; + } + if (de) + return EEXIST; // We just needed a new link + } + + for (char **aliaspp = he->h_aliases; aliaspp && *aliaspp; aliaspp++) + { + string alias(*aliaspp); + + cout << "aliasing to " << *aliaspp << '\n'; + + Inode *ino = new ftplink(filesys, hostname, this, alias); + if (link(alias, ino)) + delete ino; + } + + return 0; +} + +topdir::topdir(ftpfs &fs, const string &cache) + :dir(fs, cache, NULL) +{ + mode = S_IFDIR | 0777; + init(); +} + +Inode * +topdir::newinode(dir *d, const struct stat *st, const string &name) +{ + Inode *ino = NULL; + + if (S_ISDIR(st->st_mode)) + { + if (name == "." || name == "..") + return NULL; + ino = new sitetopdir(filesys, name, this); + } + else if (S_ISLNK(st->st_mode)) + { + char buf[1024]; + int len = readlink(name.data(), buf, sizeof(buf)); + if (len == -1) + return NULL; + + ino = new ftplink(filesys, string(buf, len), this, name); + } + + return ino; +} + +// +// hpa 951118: topdir::do_lookup is overloaded in order to provide an +// "automounter" effect -- if we are looking for a specific +// filename, and it doesn't exist, attempt to create it +// +// Curious note: the obvious way to do this would be to re-define +// topdir::lookup (it would save a lot of duplicate work), but the +// lookup function is not virtual, so do_lookup would call +// DirInode::lookup and not topdir::lookup. Having a non-virtual +// lookup seems to defeat the purpose, somehow... +// +int +topdir::do_lookup(const up_preamble &pre, upp_repl &rep, + const upp_lookup_s &arg, upp_lookup_r &ret) +{ + string name((char *)arg.name.elems, (int)arg.name.nelem); + + // First check if we have already come across this site... + if ( !dir::lookup(name) ) + { + // Not found. Attempt to create. + + cout << name << " not found, attempting to connect to site.\n"; + + up_handle bogus; // We don't really need this information + create(name, bogus); // (at least not right now) + + // We don't check the result of "create", since if it failed, + // dir::do_lookup will fail and handle all the paperwork for us. + } + + return dir::do_lookup(pre,rep,arg,ret); +} + + Added: trunk/filesystems/ftpfs/topdir.h ============================================================================== --- trunk/filesystems/ftpfs/topdir.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/topdir.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,34 @@ +// -*- C++ -*- + +// This is the top directory in the filesystem +// Each entry in this directory is a hostname of a machine +// for which either cached information exists or an open +// connection exists. + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#ifndef _TOPDIR_H_ +#define _TOPDIR_H_ + +#pragma interface + +#include "dir.h" +#include + +class topdir : public dir +{ + Inode *newinode(dir *, const struct stat *, const string &); + + int do_create(const up_preamble &, upp_repl &, + const upp_create_s &, upp_create_r &); + int create(const string &, up_handle &); + int do_lookup(const up_preamble &, upp_repl &, + const upp_lookup_s &, upp_lookup_r &); + +public: + topdir(ftpfs &fs, const string &); +}; + +#endif /* _TOPDIR_H_ */ Added: trunk/filesystems/ftpfs/vms_host.h ============================================================================== --- trunk/filesystems/ftpfs/vms_host.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/vms_host.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,23 @@ +// -*- C++ -*- + +// VMS host specific information. Not implemented + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +/* + Pathname format: drive:[dir.dir.dir]file;ver + ^^^^^^ ^^^^ optional + Dir listing: + FTP_SERVER.LOG;1824 %RMS-E-PRV, insufficient privilege or file protection violation + KERMIT.DIR;1 1 16-JUL-1993 13:39 [1,1] (RWE,RWE,RE,RE) + MITCHELL.DIR;1 1 20-MAY-1994 08:32 [1,1] (RWE,RWE,RE,RE) + RISKS_V12.LIS;1 %RMS-E-PRV, insufficient privilege or file protection violation + MSKERMIT.INI_ALTPS;1 + %RMS-E-PRV, insufficient privilege or file protection violation + + Result from daytime service: + Tuesday, June 7, 1994 7:32:48PM-EDT + + */ Added: trunk/filesystems/ftpfs/ftplink.cc ============================================================================== --- trunk/filesystems/ftpfs/ftplink.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/ftplink.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,80 @@ +// -*- C++ -*- + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#pragma implementation + +#include "ftplink.h" +#include "ftpfs.h" +#include "pushd.h" +#include "dir.h" + +#include +#include +#include +#include + +#include +#include +#include + +ftplink::ftplink(ftpfs &fs, string lnk, dir *d, string name) + : ino(fs), link(lnk), d(d), name(name) +{ + if (link[0] == '/') + { + int dp = d->depth(); + string pre = "./"; + + if (dp > 0) + { + pre = ""; + for ( ; dp>0; dp--) + pre += "../"; + } + + link = link.substr(1,link.length()-1); + link.insert(0, pre); + } + + int fd = d->open(); + + if (fd != -1) + { + pushd here(fd); + symlink(link.data(), name.data()); + } + + ctime = mtime = time(0); + mode = S_IFLNK | 0777; + size = link.length(); +} + +void +ftplink::decref() +{ + if (nlink-- > 0) + return; + + int fd = d->open(); + + if (fd != -1) + { + pushd here(fd); + ::unlink(name.data()); + } + delete this; +} + +int +ftplink::do_readlink(const up_preamble &, upp_repl &, + const upp_readlink_s &arg, upp_readlink_r &ret) +{ + ret.name.nelem = link.length(); + link.copy((char *)ret.name.elems, ret.name.nelem, 0); +/* ret.name.elems = (signed char *)link.chars(); */ + + return 0; +} Added: trunk/filesystems/ftpfs/ftplink.h ============================================================================== --- trunk/filesystems/ftpfs/ftplink.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/ftplink.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,32 @@ +// -*- C++ -*- + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#ifndef _FTPLINK_H_ +#define _FTPLINK_H_ + +#pragma interface + +#include +#include "ino.h" + +class ftpfs; + +class ftplink: public ino +{ + string link; + class dir *d; + string name; + + int do_readlink(const up_preamble &, upp_repl &, + const upp_readlink_s &, upp_readlink_r &); + void decref(); +public: + ftplink(ftpfs &fs, string link, class dir *, string name); + + const string &getlink() const { return link; } +}; + +#endif /* _FTPDIR_H_ */ Added: trunk/filesystems/ftpfs/nonblk_io.cc ============================================================================== --- trunk/filesystems/ftpfs/nonblk_io.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/nonblk_io.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,369 @@ +// -*- C++ -*- + +// Non-blocking threaded IO +// This sets the fd for the operation into nonblocking mode. +// If the IO would have blocked, it's put onto the dispatch +// list and another thread is scheduled. When the fd is ready +// for IO, this thread is rescheduled and the IO is completed. + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#include +#include +#include +#include +#include +#include + +#include +#include + +CommBase *selector = NULL; +int do_nonblock = 0; + +class reio : public DispatchFD +{ + int dispatch(int, int); + + Semaphore sem; + + CommBase *comm; + +public: + reio(); + + void wait(int fd, int what); + +}; + +reio::reio() + : sem(0), comm(selector) +{ + assert(selector != NULL); +} + +void +reio::wait(int fd, int what) +{ + comm->addDispatch(fd, this, what); + sem.wait(); +} + +int +reio::dispatch(int, int) +{ + sem.signal(); + return 0; +} + +extern "C" +ssize_t read(int fd, void *buf, size_t sz) +{ + int flags; + ssize_t ret; + + if ((flags = fcntl(fd, F_GETFL, 0)) == -1) + return -1; + + again: + if (do_nonblock && fcntl(fd, F_SETFL, flags|O_NONBLOCK) == -1) + return -1; + + if ((ret = __read(fd, buf, sz)) == -1) + { + int err = errno; + + fcntl(fd, F_SETFL, flags); + + if (err == EINTR) + goto again; + + if (err == EAGAIN) + { + reio *rio = new reio(); + + rio->wait(fd, DISP_R); + goto again; + } + errno = err; + return ret; + } + fcntl(fd, F_SETFL, flags); + + return ret; +} + +extern "C" +ssize_t write(int fd, const void *buf, size_t sz) +{ + int flags; + ssize_t ret; + + if ((flags = fcntl(fd, F_GETFL, 0)) == -1) + return -1; + + again: + if (do_nonblock && fcntl(fd, F_SETFL, flags|O_NONBLOCK) == -1) + return -1; + + if ((ret = __write(fd, buf, sz)) == -1) + { + int err = errno; + + fcntl(fd, F_SETFL, flags); + + if (err == EINTR) + goto again; + + if (err == EAGAIN) + { + reio *rio = new reio(); + rio->wait(fd, DISP_W); + goto again; + } + errno = err; + return ret; + } + fcntl(fd, F_SETFL, flags); + + return ret; +} + +#if 0 +extern "C" +int select(int width, fd_set *read_fd, fd_set *write_fd, fd_set *except_fd, + struct timeval *timeout) +{ + int i; + + for(i = 0; i < width; i++) + { + int what = 0; + if (FD_ISSET(i, read_fd)) + what |= DISP_R; + if (FD_ISSET(i, write_fd)) + what |= DISP_W; + if (FD_ISSET(i, execpt_fd)) + what |= DISP_E; + if (what != 0) + { + } + } +} +#endif + +#include "netsys.h" + +extern "C" +int send(int fd, const void *buf, int len, unsigned sndfl) +{ + int flags; + int ret; + + if ((flags = fcntl(fd, F_GETFL, 0)) == -1) + return -1; + + again: + if (do_nonblock && fcntl(fd, F_SETFL, flags|O_NONBLOCK) == -1) + return -1; + + if ((ret = __send(fd, buf, len, sndfl)) == -1) + { + int err = errno; + fcntl(fd, F_SETFL, flags); + + if (err == EAGAIN) + { + reio *rio = new reio(); + + rio->wait(fd, DISP_W); + goto again; + } + errno = err; + return ret; + } + fcntl(fd, F_SETFL, flags); + + return ret; +} + +extern "C" +int sendto(int fd, const void *buf, int len, unsigned sndfl, + const struct sockaddr *to, int tolen) +{ + int flags; + int ret; + + if ((flags = fcntl(fd, F_GETFL, 0)) == -1) + return -1; + + again: + if (do_nonblock && fcntl(fd, F_SETFL, flags|O_NONBLOCK) == -1) + return -1; + + if ((ret = __sendto(fd, buf, len, sndfl, to, tolen)) == -1) + { + int err = errno; + + fcntl(fd, F_SETFL, flags); + + if (err == EAGAIN) + { + reio *rio = new reio(); + + rio->wait(fd, DISP_W); + goto again; + } + errno = err; + return ret; + } + fcntl(fd, F_SETFL, flags); + + return ret; +} + +extern "C" +int recv(int fd, void *buf, int len, unsigned rcvfl) +{ + int flags; + ssize_t ret; + + if ((flags = fcntl(fd, F_GETFL, 0)) == -1) + return -1; + + again: + if (do_nonblock && fcntl(fd, F_SETFL, flags|O_NONBLOCK) == -1) + return -1; + + if ((ret = __recv(fd, buf, len, rcvfl)) == -1) + { + int err = errno; + + fcntl(fd, F_SETFL, flags); + + if (err == EAGAIN) + { + reio *rio = new reio(); + + rio->wait(fd, DISP_R); + goto again; + } + errno = err; + return ret; + } + fcntl(fd, F_SETFL, flags); + return ret; +} + +extern "C" +int recvfrom(int fd, void *buf, int len, unsigned rcvfl, + struct sockaddr *from, int *fromlen) +{ + int flags; + ssize_t ret; + + if ((flags = fcntl(fd, F_GETFL, 0)) == -1) + return -1; + + again: + if (do_nonblock && fcntl(fd, F_SETFL, flags|O_NONBLOCK) == -1) + return -1; + + if ((ret = __recvfrom(fd, buf, len, rcvfl, from, fromlen)) == -1) + { + int err = errno; + + fcntl(fd, F_SETFL, flags); + + if (err == EAGAIN) + { + reio *rio = new reio(); + + rio->wait(fd, DISP_R); + goto again; + } + errno = err; + return ret; + } + fcntl(fd, F_SETFL, flags); + + return ret; +} + +extern "C" +int connect(int fd, struct sockaddr *addr, int addrlen) +{ + int flags; + ssize_t ret; + + if ((flags = fcntl(fd, F_GETFL, 0)) == -1) + return -1; + + again: + if (do_nonblock && fcntl(fd, F_SETFL, flags|O_NONBLOCK) == -1) + return -1; + + if ((ret = __connect(fd, addr, addrlen)) == -1) + { + int err = errno; + + fcntl(fd, F_SETFL, flags); + +#if 0 + // Hack around Linux kernel bug + // If we get EALREADY back, it means we have connected, + // are in the process of disconnecting again. There is + // received data ready for us to read + if (err == EALREADY) + return 0; +#endif + if (err == EALREADY || err == EINPROGRESS) + { + reio *rio = new reio(); + + rio->wait(fd, DISP_R); + goto again; + } + errno = err; + return ret; + } + fcntl(fd, F_SETFL, flags); + + return ret; +} + +extern "C" +int accept(int fd, struct sockaddr *addr, int *addrlen) +{ + int flags; + ssize_t ret; + + if ((flags = fcntl(fd, F_GETFL, 0)) == -1) + return -1; + + again: + if (do_nonblock && fcntl(fd, F_SETFL, flags|O_NONBLOCK) == -1) + return -1; + + if ((ret = __accept(fd, addr, addrlen)) == -1) + { + int err = errno; + + fcntl(fd, F_SETFL, flags); + + if (err == EAGAIN) + { + reio *rio = new reio(); + + rio->wait(fd, DISP_R); + goto again; + } + errno = err; + return ret; + } + + fcntl(fd, F_SETFL, flags); + return ret; +} Added: trunk/filesystems/ftpfs/reap.pl ============================================================================== --- trunk/filesystems/ftpfs/reap.pl 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/reap.pl 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,60 @@ +#!/usr/bin/perl -- +# +# Cache reaper. This script keeps the cache size at or below +# a set point, keeping files most reciently used. +# +# (C) Copyright 1994 Jeremy Fitzhardinge +# This code is distributed under the terms of the +# GNU General Public Licence. See COPYING for more details. + +eval 'exec /usr/bin/perl -S $0 ${1+"$@"}' + if $running_under_some_shell; + +$#ARGV == 1 || die("Usage: $0 cache-dir max-size\n"); + +require "find.pl"; + +# Traverse desired filesystems + +&find($ARGV[0]); + +$ARGV[1] =~ tr/KMG/kmg/; +$ARGV[1] =~ /^([0-9]+)([kmg]?)$/; + +$scale{"k"} = 1024; +$scale{"m"} = 1024*1024; +$scale{"g"} = 1024*1024*1024; + +die("$0: $ARGV[1]: Bad scale factor\n") + if (!defined($1) || ($2 != "" && !defined($scale{$2}))); + +$max = $1*$scale{$2}; +$total = 0; +$delsz = 0; +$delfiles = 0; + +foreach $key (reverse sort keys %sizes) { + $sz = $sizes{$key}; + $total += $sz; + + if ($total > $max) { + ($atime, $name) = split(" ", $key, 2); + unlink($name); + $delsz += $sz; + $delfiles++; + } +} + +print "$delsz bytes in $delfiles deleted\n"; + +exit; + +sub wanted { + if ((($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$sizemm,$atime) = lstat($_)) && + -f _ && $_ !~ /\.ftpfs_.*/) + { + $key = "$atime $name"; + $sizes{$key} = $sizemm; + } +} + Added: trunk/filesystems/ftpfs/dir.cc ============================================================================== --- trunk/filesystems/ftpfs/dir.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/dir.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,113 @@ +// -*- C++ -*- + +// Base directory class + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#pragma implementation + +#include "dir.h" +#include "ftpfs.h" +#include "ftpdir.h" +#include "ftplink.h" +#include "ftpconn.h" +#include "pushd.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +dir::dir(ftpfs &fs, const string &name, dir *up) + :DirInode(fs, fs.genhand(), up), sem(1), + name(name, up ? &up->name : (Path *)NULL), filesys(fs), parent(up) +{ + mode = S_IFDIR | 0555; + atime = ctime = mtime = time(0); + uid = fs.uid; + gid = fs.gid; +} + +void +dir::init() +{ + int dfd = open(); + + if (dfd == -1) + return; + + pushd here(dfd); + + DIR *dir; + if ((dir = opendir(".")) == NULL) + { + perror("topdir::topdir opendir of cache failed"); + return; + } + + struct dirent *de; + + while((de = readdir(dir)) != NULL) + { + struct stat st; + + if (lstat(de->d_name, &st) == -1) + { + fprintf(stderr, "stat of %s failed: %s\n", + de->d_name, strerror(errno)); + continue; + } + + Inode *ino; + string name(de->d_name); + + if ((ino = newinode(this, &st, name)) == NULL) + continue; + + link(name, ino); + } + closedir(dir); +} + +int +dir::open() +{ + string p = path(); + + int ret = ::open(p.data(), O_RDONLY); + + if (ret == -1) + { + int err = errno; + fprintf(stderr, "open of %s failed: %s\n", + (const char *)p.data(), strerror(errno)); + errno = err; + } + return ret; +} + +int +dir::do_iput(const up_preamble &, upp_repl &, const upp_iput_s &) +{ + if (nlink == 0) + delete this; + return 0; +} + +void +dir::beforeop(up_ops) +{ + sem.wait(); +} + +void +dir::afterop(up_ops) +{ + sem.signal(); +} Added: trunk/filesystems/ftpfs/getdate.h ============================================================================== --- trunk/filesystems/ftpfs/getdate.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/getdate.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,39 @@ +/* -*- C -*- */ + +#ifndef _GETDATE_H_ +#define _GETDATE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/* +** Daylight-savings mode: on, off, or not yet known. +*/ +typedef enum _DSTMODE { + DSTon, DSToff, DSTmaybe +} DSTMODE; + +/* +** Meridian: am, pm, or 24-hour style. +*/ +typedef enum _MERIDIAN { + MERam, MERpm, MER24 +} MERIDIAN; + + +time_t get_date(char *p, struct timeb *now); +time_t +Convert(time_t Month, time_t Day, time_t Year, + time_t Hours, time_t Minutes, time_t Seconds, + MERIDIAN Meridian, DSTMODE DSTmode, + time_t timezone); + +#ifdef __cplusplus +} +#endif + +#endif /* _GETDATE_H_ */ Added: trunk/filesystems/ftpfs/ftpfs.cc ============================================================================== --- trunk/filesystems/ftpfs/ftpfs.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/ftpfs.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,118 @@ +// -*- C++ -*- + +// FTP filesystem + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#pragma implementation + +#include +#include + +#include +#include "ftpfs.h" +#include "topdir.h" + +#include +#include + +ftpfs::ftpfs(const char *mpoint, const string &cache) + : cache(cache), Filesystem(mpoint), uid(0), gid(0) +{ + hcount = 0; + root = new topdir(*this, cache); +} + +int +ftpfs::do_mount(const up_preamble &, upp_repl &, + upp_mount_r &ret) +{ + ret.root.handle = root->gethandle(); + return 0; +} + +ftpfs::~ftpfs() +{ +} + +int +ftpfs::Enquire(up_ops op) +{ + switch(op) + { + case up_mount: + case up_iread: + case up_multireaddir: + case up_lookup: + case up_notify_change: + case up_readlink: + case up_create: + case up_read: + case up_iput: + return 0; + default: + break; + } + + return Filesystem::Enquire(op); +} + +// Globals for controlling nonblocking IO (nonblk_io.cc) +extern CommBase *selector; +extern int do_nonblock; + +// Parse the arguments from muserfs and construct the filesystem +// and communications. +int +main(int argc, char **argv) +{ + int optch, err = 0; + int infd, outfd; + const char *mpoint = ""; + + extern char *optarg; + extern int optind, opterr, optopt; + + + infd = outfd = -1; + while((optch = getopt(argc, argv, "i:o:m:c:")) != EOF) + switch(optch) + { + case 'i': + infd = atoi(optarg); + break; + case 'o': + outfd = atoi(optarg); + break; + case 'm': + mpoint = optarg; + break; + default: + err++; + } + + if (err || infd == -1 || outfd == -1 || optind == argc) + { + cerr << "Usage: " << argv[0] << " -i infd -o outfd -m mpoint cachedir\n"; + exit(1); + } + + char path[MAXPATHLEN]; + char *full = realpath(argv[optind], path); + string cache(full ? full : argv[optind]); + +#if 0 && DEBUG + printf("pid=%d, return to cont\n", getpid()); + getchar(); +#endif + ftpfs ftp(mpoint, cache); + ThreadComm comm(ftp, outfd, infd, 32*1024, COM_TPRI, OPS_TPRI); + selector = &comm; + do_nonblock = 1; + if (comm.Run() == -1) + cerr << argv[0] << ": Comm.Run() failed!\n"; + do_nonblock = 0; + return 0; +} Added: trunk/filesystems/ftpfs/dos_host.cc ============================================================================== --- trunk/filesystems/ftpfs/dos_host.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/dos_host.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,170 @@ +// -*- C++ -*- + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +// Dos ftp server support by marcus@ee.pdx.edu (Marcus Daniels) + +#pragma implementation + +#include "dos_host.h" +#include "serv_port.h" +#include "ftpconn.h" +#include "getdate.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +int +dos_host::pathsteps(const string &path, string *ret[]) +{ + static const Regex deldot("\\(^\\./\\)\\|\\(/\\.\\/\\)\\|\\(/\\.$\\)\\|\\(//\\)\\|\\(^\\.$\\)"); + static const Regex deldotdot("\\(^|/\\)[^/]+/\\.\\./"); + + *ret = new string[1]; + (*ret)[0] = path; + (*ret)[0].gsub(deldot, ""); + (*ret)[0].gsub(deldotdot, "/"); + + if ((*ret)[0] == "") + return 0; + + return 1; +} + +// Get local time at remote machine with the "time" service +time_t +dos_host::localtime(struct sockaddr_in addr) +{ + return time(0); +} + +#define EPOCH 1970 +#define HOUR(x) ((time_t)(x) * 60) +#define SECSPERDAY (24L * 60L * 60L) + +// Parse a date from "dir" +static time_t +parsedate(const string &date, time_t timezone) +{ + string parts[2]; + static const Regex rx_date_time_delim(" +"); + string date_parts[3]; + static const Regex rx_date_delim("-"); + + if (split(date, parts, 2, rx_date_time_delim) != 2) + return -1; + if (split(parts[0], date_parts, 3, rx_date_delim) != 3) + return -1; + + static const Regex rx_time("[012]?[0-9]:[0-5][0-9]"); + static const Regex rx_year("[0-9][0-9]"); + static const Regex rx_month("[0-1][0-9]"); + static const Regex rx_day("[0-9][0-9]"); + + int month = -1; + int day = -1; + int year = -1; + int hours = -1; + int mins = -1; + + if (!date_parts[0].matches(rx_month)) + return 0; + month = atoi(date_parts[0]); + if (!date_parts[1].matches(rx_day)) + return 0; + day = atoi(date_parts[1]); + if (!date_parts[2].matches(rx_year)) + return 0; + year = atoi(date_parts[2]); + + { + string hm[2]; + if (!parts[1].matches(rx_time)) + return 0; + if (split(parts[1], hm, 2, string(":")) != 2) + return 0; + hours = atoi(hm[0]); + mins = atoi(hm[1]); + } + return Convert(month, day, + year,hours,mins,0,MER24,DSToff,timezone); +} + +struct ftp_filelist * +dos_host::parse_filelist(const string &ro_line, time_t timezone) +{ + string line = ro_line; + + // Match a line of "dir" output + static const Regex dir_line_1("^\\([^ /]+\\) *\\([0-9]+\\) \\([0-1][0-9]-[0-3][0-9]-[0-9][0-9] [012][0-9]:[0-5][0-9]\\).*"); + static const Regex dir_line_2("^.*/\\([^ /]+\\) *\\([0-9]+\\) \\([0-1][0-9]-[0-3][0-9]-[0-9][0-9] [012][0-9]:[0-5][0-9]\\).*"); + + const Regex *dir_rx = &dir_line_1; + + if (!line.matches(dir_line_1)) + { + if (!line.matches(dir_line_2)) + { + cout << "Failed to match dir line [" << line << "]\n"; + return NULL; + } + dir_rx=&dir_line_2; + } + + int start, len; + + ftp_filelist *nf = new ftp_filelist; + dir_rx->match_info(start, len, 1); + nf->name = string(line.at(start,len)); + + dir_rx->match_info(start, len, 2); + + string sz_str(line.at(start, len)); + nf->size = strtol(sz_str, NULL, 10); + switch(sz_str[0]) + { + case '<': + nf->type = FT_Directory; + break; + default: + nf->type = FT_File; + break; + } + + dir_rx->match_info(start, len, 3); + string date_str(line.at(start, len)); + cout << "Date_str:[" << date_str << "]\n"; + nf->time = parsedate(date_str, timezone); + nf->next = NULL; + + struct tm *tm = gmtime(&nf->time); + cout << "Name " << nf->name << " size " << nf->size << + " date " << asctime(tm); + + return nf; +} + +const string & +dos_host::hosttype() const +{ + static const string dos("dos"); + + return dos; +} + +const string & +dos_host::wildcard() const +{ + static const string wild("/*"); + + return wild; +} Added: trunk/filesystems/ftpfs/unix_host.h ============================================================================== --- trunk/filesystems/ftpfs/unix_host.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/unix_host.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,27 @@ +// -*- C++ -*- + +// Unix host information + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#ifndef _UNIX_HOST_H_ +#define _UNIX_HOST_H_ + +#pragma interface + +#include "host.h" +#include +#include +#include + +class unix_host: public host +{ + int pathsteps(const string &, string *steps[]); + time_t localtime(struct sockaddr_in); + struct ftp_filelist *parse_filelist(const string &, time_t); + const string &hosttype() const; +}; + +#endif /* _UNIX_HOST_H_ */ Added: trunk/filesystems/ftpfs/pushd.cc ============================================================================== --- trunk/filesystems/ftpfs/pushd.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/pushd.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,37 @@ +// -*- C++ -*- + +// PushD/PopD operations + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#include "pushd.h" + +#include +#include +#include +#include + +pushd::pushd(int dir) + :dir(dir) +{ + int fd = open(".", O_RDONLY); + + if (fd == -1 || fchdir(dir) == -1) + { + perror("pushd::pushd() open or fchdir failed"); + return; + } + + old = fd; +} + +pushd::~pushd() +{ + fchdir(old); + close(old); + close(dir); +} + + Added: trunk/filesystems/ftpfs/serv_port.cc ============================================================================== --- trunk/filesystems/ftpfs/serv_port.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/serv_port.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,24 @@ +// -*- C++ -*- + +// Service port things + +#pragma implementation + +#include "serv_port.h" + +#include +#include + +serv_port::serv_port(const char *srv, const char *trans) +{ + struct servent *se = getservbyname(srv, trans); + + if (se == NULL) + { + fprintf(stderr, "Can't find service %s/%s\n", + srv, trans); + return; + } + + port = se->s_port; +} Added: trunk/filesystems/ftpfs/serv_port.h ============================================================================== --- trunk/filesystems/ftpfs/serv_port.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/serv_port.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,17 @@ +// -*- C++ -*- + +// Little utility struct for getting service ports + +#ifndef _SERV_PORT_H_ +#define _SERV_PORT_H_ + +#pragma interface + +struct serv_port +{ + int port; + + serv_port(const char *, const char *); +}; + +#endif /* _SERV_PORT_H_ */ Added: trunk/filesystems/ftpfs/ino.cc ============================================================================== --- trunk/filesystems/ftpfs/ino.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/ino.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,47 @@ +// -*- C++ -*- + +// Base inode class (apart from directories) + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#pragma implementation + +#include "ftpfs.h" +#include "ino.h" + +ino::ino(ftpfs &fs) + :SimpleInode(fs, fs.genhand()), sem(1) +{ + uid = fs.uid; + gid = fs.gid; +} + +void +ino::beforeop(up_ops) +{ + sem.wait(); +} + +void +ino::afterop(up_ops) +{ + sem.signal(); +} + +int +ino::do_iput(const up_preamble &, upp_repl &, const upp_iput_s &) +{ + if (nlink == 0) + delete this; + return 0; +} + +void +ino::decref() +{ + nlink--; + if (nlink == 0) + delete this; +} Added: trunk/filesystems/ftpfs/pushd.h ============================================================================== --- trunk/filesystems/ftpfs/pushd.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/pushd.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,20 @@ +// -*- C++ -*- + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#ifndef _PUSHD_H_ +#define _PUSHD_H_ + +class pushd +{ + int old; + int dir; + +public: + pushd(int fd); + ~pushd(); +}; + +#endif /* _PUSHD_H_ */ Added: trunk/filesystems/ftpfs/ino.h ============================================================================== --- trunk/filesystems/ftpfs/ino.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/ino.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,34 @@ +// -*- C++ -*- + +// Base non-dir inode +// This just exists to serialize thread access to an inode + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#ifndef _INO_H_ +#define _INO_H_ + +#pragma interface + +#include +#include + +class ftpfs; + +class ino : public SimpleInode +{ + Semaphore sem; + + void beforeop(up_ops); + void afterop(up_ops); + + int do_iput(const up_preamble &, upp_repl &, const upp_iput_s &); + + void decref(); +public: + ino(ftpfs &); +}; + +#endif /* _INO_H_ */ Added: trunk/filesystems/ftpfs/netsys.h ============================================================================== --- trunk/filesystems/ftpfs/netsys.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/netsys.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,29 @@ +/* -*- C -*- */ + +/* Hooks to get in before the library functions */ +/* + * (C) Copyright 1994 Jeremy Fitzhardinge + * This code is distributed under the terms of the + * GNU General Public Licence. See COPYING for more details. + */ + +#ifndef _NETSYS_H_ +#define _NETSYS_H_ + +#ifdef __cplusplus +extern "C" { +#endif +int __recv(int fd, void *buf, int len, unsigned flags); +int __recvfrom(int fd, void *buf, int len, unsigned flags, + struct sockaddr *from, int *fromlen); +int __send(int fd, const void *buf, int len, unsigned flags); +int __sendto(int sockfd, const void *buffer, int len, unsigned flags, + const struct sockaddr *to, int tolen); +int __connect(int sockfd, struct sockaddr *saddr, int addrlen); +int __accept(int sockfd, struct sockaddr *peer, int *paddrlen); + +#ifdef __cplusplus +} +#endif + +#endif /* _NETSYS_H_ */ Added: trunk/filesystems/ftpfs/sitetopdir.h ============================================================================== --- trunk/filesystems/ftpfs/sitetopdir.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/sitetopdir.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,21 @@ +// -*- C++ -*- + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#ifndef _SITETOPDIR_H_ +#define _SITETOPDIR_H_ + +#pragma interface + +#include "ftpdir.h" + +class sitetopdir: public ftpdir +{ + int depth() const { return 0; } +public: + sitetopdir(ftpfs &fs, string name, dir *up); +}; + +#endif /* _SITETOPDIR_H_ */ Added: trunk/filesystems/ftpfs/ftpdir.cc ============================================================================== --- trunk/filesystems/ftpfs/ftpdir.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/ftpdir.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,435 @@ +// -*- C++ -*- + +// Directories cached from an ftp site + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#pragma implementation + +#include +#include +#include + +#include + +#include +#include +#include + +#include "ftpdir.h" +#include "ftpconn.h" +#include "ftplink.h" +#include "ftpfile.h" +#include "pushd.h" +#include "ConfFile.h" +#include + +static regex_t ignore_pat; +static regmatch_t matches[2]; + + +ftpdir::ftpdir(ftpfs &fs, const string &elem, dir *up, + ftpdir *ftpup, const string &cfname) + : dir(fs, elem, up), ftpup(ftpup) +{ + conn = new ftpconn(Path(cfname, &name), elem); + construct(); +} + +ftpdir::ftpdir(ftpfs &fs, const string &name, dir *up, + ftpdir *ftpup, ftpconn *conn) + : dir(fs, name, up), ftpup(ftpup), conn(conn) +{ + construct(); +} + +void +ftpdir::construct() +{ + + regcomp(&ignore_pat, "^\\.ftpfs_.*$", 0); + + + int fd = parent->open(); + + conf = NULL; + + if (fd != -1) + { + pushd here(fd); + string dir=name.path(); + mkdir(dir.data(), mode|0700); + conf = new ConfFile(Path(".ftpfs_dir", &name)); + } + else + cout << "name=" << name.elem() << + " failed to open parent " << + parent->getname().path() << "\n"; + + mode |= 0777; + + getparams(); + init_done = 0; + conn->incref(); +} + +void +ftpdir::init() +{ + dir::init(); + + int dfd = open(); + pushd here(dfd); + + ifstream dinfo(".ftpfs_dirinfo"); + + if (!dinfo.bad()) + { + mode_t mode; + size_t size; + time_t time; + string name; + string symlink; + + for(;;) + { + dinfo >> mode; + dinfo >> size; + dinfo >> time; + dinfo >> name; + if (S_ISLNK(mode)) + dinfo >> symlink; + + if (dinfo.eof() || dinfo.fail()) + break; + + if (lookup(name) != NULL) + continue; + + Inode *ino = NULL; + + if (S_ISREG(mode)) + { + ftpfile *f = new ftpfile(filesys, name, + this, conn); + f->setstats(size, time); + ino = f; + } + else if (S_ISDIR(mode)) + { + ftpdir *d = new ftpdir(filesys, name, this, + this, conn); + d->mtime = time; + ino = d; + } + else if (S_ISLNK(mode)) + ino = new ftplink(filesys, symlink, this, name); + + if (ino == NULL) + continue; + link(name, ino); + } + } +} + +void +ftpdir::cleanup() +{ + int fd = open(); + pushd here(fd); + + + ::unlink(".ftpfs_dirinfo"); + ofstream dinfo(".ftpfs_dirinfo", ios::out|ios::trunc, 0444); + + if (!dinfo.bad()) + { + DirEntry *de=NULL; + + for(de = scan(de); de != NULL; scan(de)) + { + string name = de->getname(); + + if (name == "." || name == ".." || + regexec(&ignore_pat, name.data(), 2, matches, 0)==REG_NOMATCH) + continue; + + up_inode ino; + + ((SimpleInode *)de->geti())->iread(ino); // XXX + + dinfo << oct << ' ' << ino.mode << ' ' + << dec << ' ' << ino.size << ' ' + << ino.mtime << ' ' << name; + if (S_ISLNK(ino.mode)) + dinfo << ' ' << + ((ftplink *)de->geti())->getlink(); // XXX + dinfo << '\n'; + } + } +} + +ftpdir::~ftpdir() +{ + regfree(&ignore_pat); + setparams(); + conn->decref(); + if (conf) + delete conf; +} + +void +ftpdir::getparams() +{ + if (conf == NULL) + return; + + if (!conf->getnum("last_update", last_upd)) + last_upd = 0; + if (!conf->getnum("last_failure", last_failure)) + last_failure = 0; +} + +void +ftpdir::setparams() +{ + if (conf == NULL) + return; + conf->setnum("last_update", last_upd); + conf->setnum("last_failure", last_failure); +} + +Inode * +ftpdir::newinode(dir *d, const struct stat *st, const string &name) +{ + Inode *ino = NULL; + + if (S_ISDIR(st->st_mode)) + { + if (name == "." || name == "..") + return NULL; + ino = new ftpdir(filesys, name, this, this, conn); + } + else if (S_ISLNK(st->st_mode)) + { + char buf[1024]; + int len = readlink(name.data(), buf, sizeof(buf)); + if (len == -1) + return NULL; + + ino = new ftplink(filesys, string(buf, len), this, name); + } + else if (S_ISREG(st->st_mode) && + regexec(&ignore_pat, name.data(), 2, matches, 0)==REG_NOMATCH) + ino = new ftpfile(filesys, name, this, conn); + + return ino; +} + +int +ftpdir::updatedir(int force) +{ + time_t now = time(0); + if (!init_done) + { + init_done = 1; + init(); + } + + if (!force) + { + if (last_upd > (now - conn->get_upd_timeout())) + return 0; + if ((last_failure > last_upd) && + last_failure > (now - conn->get_fail_timeout())) + return 0; + } + string p = ftppath(); + + cout << "Updating directory at path \"" << p << "\"\n"; + + ftp_filelist *fl, *flist; + + fl = flist = conn->getfilelist(p); + + if (fl == NULL) + { + last_failure = now; + return ENOENT; + } + + // Check to see if a file has changed type + for(; fl != NULL; fl = fl->next) + { + DirEntry *de; + + if ((de = lookup(fl->name)) != NULL) + { + int bad = 0; + up_inode i; + + ((SimpleInode *)de->geti())->iread(i); // XXX + + switch(fl->type) + { + case FT_Directory: + if (!S_ISDIR(i.mode)) + bad = 1; + break; + case FT_File: + if (!S_ISREG(i.mode)) + bad = 1; + else + ((ftpfile *)de->geti())->setstats(fl->size, fl->time); // XXX + break; + case FT_Link: + if (!S_ISLNK(i.mode)) + bad = 1; + break; + default: + break; + } + + if (!bad) + continue; + unlink(fl->name); + } + + Inode *ino = NULL; + + switch(fl->type) + { + case FT_Directory: + ino = new ftpdir(filesys, fl->name, this, this, conn); + break; + case FT_File: + { + ftpfile *file = new ftpfile(filesys, fl->name, this, conn); + file->setstats(fl->size, fl->time); + ino = file; + break; + } + case FT_Link: + ino = new ftplink(filesys, fl->link, this, fl->name); + break; + default: + break; + } + + if (ino != NULL && link(fl->name, ino)) + delete ino; + } + + DirEntry *de=NULL; + pushd here(open()); + + for(de = scan(de); de != NULL; scan(de)) + { + string name = de->getname(); + + if (name == "." || name == ".." || + regexec(&ignore_pat, name.data(), 2, matches, 0)==REG_NOMATCH) + continue; + + int match = 0; + for(fl = flist; fl != NULL; fl = fl->next) + if (fl->name == name) + { + match = 1; + break; + } + if (!match) + { + unlink(name); + ::unlink(name.data()); + } + } + + for(; flist != NULL; flist = fl) + { + fl = flist->next; + delete flist; + } + + last_upd = now; + return 0; +} + +int +ftpdir::do_readdir(const up_preamble &pre, upp_repl &rep, + const upp_readdir_s &arg, upp_readdir_r &ret) +{ + updatedir(); + + return dir::do_readdir(pre, rep, arg, ret); +} + +int +ftpdir::do_multireaddir(const up_preamble &pre, upp_repl &rep, + const upp_multireaddir_s &arg, upp_multireaddir_r &ret) +{ + updatedir(); + + return dir::do_multireaddir(pre, rep, arg, ret); +} + +int +ftpdir::do_lookup(const up_preamble &pre, upp_repl &rep, + const upp_lookup_s &arg, upp_lookup_r &ret) +{ + string name((char *)arg.name.elems, (int)arg.name.nelem); + if (name == ".ftpfs_update") + { + updatedir(1); + return ENOENT; + } + + int r = dir::do_lookup(pre, rep, arg, ret); + + if (r == ENOENT) + { + updatedir(); + r = dir::do_lookup(pre, rep, arg, ret); + } + + return r; +} + +int +ftpdir::do_create(const up_preamble &, upp_repl &, + const upp_create_s &arg, upp_create_r &ret) +{ + if (!S_ISDIR(arg.mode)) + return EPERM; + + string name((char *)arg.name.elems, (int)arg.name.nelem); + string fullname(ftppath()); + fullname += "/"; + fullname += name; + + if (conn->makedir(fullname)) + return EPERM; + + Inode *ino = new ftpdir(filesys, name, this, this, conn); + link(name, ino); + + return 0; +} + +string +ftpdir::ftppath() const +{ + string p; + + if (ftpup) + { + p = string(ftpup->ftppath()); + p += "/"; + p += name.elem(); + } + else + p = "."; + return p; +} Added: trunk/filesystems/ftpfs/Makefile ============================================================================== --- trunk/filesystems/ftpfs/Makefile 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/Makefile 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,33 @@ +TOP=../.. +include $(TOP)/rules + +DEBUG=-ggdb3 -DDEBUG -O +FLAGS=-I$(TOP)/lwp -I$(TOP)/kernel -I$(TOP)/lib -I$(TOP)/genser -I${TOP}/utils -I/usr/include/g++ +CXXFLAGS = $(FLAGS) +CFLAGS = $(FLAGS) + +LDFLAGS = $(DEBUG) $(PROF) + +DEPLIBS= $(DEPLIBUSERFS) $(DEPLIBLWP) +LIBS= $(LIBUSERFS) $(LIBLWP) #-lmcheck + +PROGS=ftpfs + +OBJ=ftpfs.o ino.o dir.o topdir.o sitetopdir.o ftpdir.o ftplink.o \ + ftpfile.o ftpconn.o nonblk_io.o pushd.o netsys.o \ + ConfFile.o serv_port.o host.o dos_host.o unix_host.o \ + getdate.o Path.o conninfo.o + +all:: $(PROGS) + +ftpfs: $(OBJ) $(DEPLIBS) + $(CXX) $(LDFLAGS) -o $@ $(OBJ) $(LIBS) + +getdate.c: getdate.y + +clean:: dummy + rm -f getdate.c *.o *~ core $(PROGS) + +dep depend:: getdate.c + $(CC) $(FLAGS) -M *.c *.cc > .depend + Added: trunk/filesystems/ftpfs/Path.h ============================================================================== --- trunk/filesystems/ftpfs/Path.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/Path.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,49 @@ +// -*- C++ -*- + +// Pathnames + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#ifndef _PATH_H_ +#define _PATH_H_ + +#pragma interface + +#include + +class _PathRep +{ + friend class Path; + + string _path; + const _PathRep *_parent; + int count; + + void decref() { if (--count == 0) delete this; } + void incref() { count++; } + + string path() const; + _PathRep(const string &, const _PathRep *parent); + ~_PathRep(); +}; + +class Path +{ + _PathRep *p_rep; + const Path *_parent; + +public: + Path(const string &elem, const Path *parent=NULL); + Path(const Path &); + ~Path(); + + Path &operator =(const Path &); + + const string &elem() const { return p_rep->_path; } + string path() const { return p_rep->path(); } + const Path *parent() const { return _parent; } +}; + +#endif /* _PATH_H_ */ Added: trunk/filesystems/ftpfs/getdate.y ============================================================================== --- trunk/filesystems/ftpfs/getdate.y 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/getdate.y 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,842 @@ +%{ +/* 1.8 +** @(#)getdate.y 1.8 92/03/03 +** +** Originally written by Steven M. Bellovin while +** at the University of North Carolina at Chapel Hill. Later tweaked by +** a couple of people on Usenet. Completely overhauled by Rich $alz +** and Jim Berets in August, 1990; +** send any email to Rich. +** +** This grammar has eight shift/reduce conflicts. +** +** This code is in the public domain and has no copyright. +*/ +/* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */ +/* SUPPRESS 288 on yyerrlab *//* Label unused */ + +#include +#include +#include +#include +#include +#include +#include "getdate.h" + +#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) +#ifdef __GNUC__ +#undef alloca /* might get redefined below */ +#endif +#endif + +#define yyparse getdate_yyparse +#define yylex getdate_yylex +#define yyerror getdate_yyerror + +#if !defined(lint) && !defined(SABER) +static char RCS[] = "@(#)getdate.y 1.8 92/03/03"; +#endif /* !defined(lint) && !defined(SABER) */ + + +#define EPOCH 1970 +#define HOUR(x) ((time_t)(x) * 60) +#define SECSPERDAY (24L * 60L * 60L) + + +/* +** An entry in the lexical lookup table. +*/ +typedef struct _TABLE { + char *name; + int type; + time_t value; +} TABLE; + + + +/* +** Global variables. We could get rid of most of these by using a good +** union as the yacc stack. (This routine was originally written before +** yacc had the %union construct.) Maybe someday; right now we only use +** the %union very rarely. +*/ +static char *yyInput; +static DSTMODE yyDSTmode; +static time_t yyDayOrdinal; +static time_t yyDayNumber; +static int yyHaveDate; +static int yyHaveDay; +static int yyHaveRel; +static int yyHaveTime; +static int yyHaveZone; +static time_t yyTimezone; +static time_t yyDay; +static time_t yyHour; +static time_t yyMinutes; +static time_t yyMonth; +static time_t yySeconds; +static time_t yyYear; +static MERIDIAN yyMeridian; +static time_t yyRelMonth; +static time_t yyRelSeconds; + +%} + +%union { + time_t Number; + enum _MERIDIAN Meridian; +} + +%token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT +%token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST + +%type tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT +%type tSEC_UNIT tSNUMBER tUNUMBER tZONE +%type tMERIDIAN o_merid + +%% + +spec : /* NULL */ + | spec item + ; + +item : time { + yyHaveTime++; + } + | zone { + yyHaveZone++; + } + | date { + yyHaveDate++; + } + | day { + yyHaveDay++; + } + | rel { + yyHaveRel++; + } + | number + ; + +time : tUNUMBER tMERIDIAN { + yyHour = $1; + yyMinutes = 0; + yySeconds = 0; + yyMeridian = $2; + } + | tUNUMBER ':' tUNUMBER o_merid { + yyHour = $1; + yyMinutes = $3; + yySeconds = 0; + yyMeridian = $4; + } + | tUNUMBER ':' tUNUMBER tSNUMBER { + yyHour = $1; + yyMinutes = $3; + yyMeridian = MER24; + yyDSTmode = DSToff; + yyTimezone = - ($4 % 100 + ($4 / 100) * 60); + } + | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid { + yyHour = $1; + yyMinutes = $3; + yySeconds = $5; + yyMeridian = $6; + } + | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER { + yyHour = $1; + yyMinutes = $3; + yySeconds = $5; + yyMeridian = MER24; + yyDSTmode = DSToff; + yyTimezone = - ($6 % 100 + ($6 / 100) * 60); + } + ; + +zone : tZONE { + yyTimezone = $1; + yyDSTmode = DSToff; + } + | tDAYZONE { + yyTimezone = $1; + yyDSTmode = DSTon; + } + | + tZONE tDST { + yyTimezone = $1; + yyDSTmode = DSTon; + } + ; + +day : tDAY { + yyDayOrdinal = 1; + yyDayNumber = $1; + } + | tDAY ',' { + yyDayOrdinal = 1; + yyDayNumber = $1; + } + | tUNUMBER tDAY { + yyDayOrdinal = $1; + yyDayNumber = $2; + } + ; + +date : tUNUMBER '/' tUNUMBER { + yyMonth = $1; + yyDay = $3; + } + | tUNUMBER '/' tUNUMBER '/' tUNUMBER { + yyMonth = $1; + yyDay = $3; + yyYear = $5; + } + | tMONTH tUNUMBER { + yyMonth = $1; + yyDay = $2; + } + | tMONTH tUNUMBER ',' tUNUMBER { + yyMonth = $1; + yyDay = $2; + yyYear = $4; + } + | tUNUMBER tMONTH { + yyMonth = $2; + yyDay = $1; + } + | tUNUMBER tMONTH tUNUMBER { + yyMonth = $2; + yyDay = $1; + yyYear = $3; + } + | tUNUMBER '-' tMONTH '-' tUNUMBER { + yyMonth = $3; + yyDay = $1; + yyYear = $5; + } + ; + +rel : relunit tAGO { + yyRelSeconds = -yyRelSeconds; + yyRelMonth = -yyRelMonth; + } + | relunit + ; + +relunit : tUNUMBER tMINUTE_UNIT { + yyRelSeconds += $1 * $2 * 60L; + } + | tSNUMBER tMINUTE_UNIT { + yyRelSeconds += $1 * $2 * 60L; + } + | tMINUTE_UNIT { + yyRelSeconds += $1 * 60L; + } + | tSNUMBER tSEC_UNIT { + yyRelSeconds += $1; + } + | tUNUMBER tSEC_UNIT { + yyRelSeconds += $1; + } + | tSEC_UNIT { + yyRelSeconds++; + } + | tSNUMBER tMONTH_UNIT { + yyRelMonth += $1 * $2; + } + | tUNUMBER tMONTH_UNIT { + yyRelMonth += $1 * $2; + } + | tMONTH_UNIT { + yyRelMonth += $1; + } + ; + +number : tUNUMBER { + if (yyHaveTime && yyHaveDate && !yyHaveRel) + yyYear = $1; + else { + if($1>10000) { + time_t date_part; + + date_part= $1/10000; + yyHaveDate++; + yyDay= (date_part)%100; + yyMonth= (date_part/100)%100; + yyYear = date_part/10000; + } + yyHaveTime++; + if ($1 < 100) { + yyHour = $1; + yyMinutes = 0; + } + else { + yyHour = $1 / 100; + yyMinutes = $1 % 100; + } + yySeconds = 0; + yyMeridian = MER24; + } + } + ; + +o_merid : /* NULL */ { + $$ = MER24; + } + | tMERIDIAN { + $$ = $1; + } + ; + +%% + +/* Month and day table. */ +static TABLE MonthDayTable[] = { + { "january", tMONTH, 1 }, + { "february", tMONTH, 2 }, + { "march", tMONTH, 3 }, + { "april", tMONTH, 4 }, + { "may", tMONTH, 5 }, + { "june", tMONTH, 6 }, + { "july", tMONTH, 7 }, + { "august", tMONTH, 8 }, + { "september", tMONTH, 9 }, + { "sept", tMONTH, 9 }, + { "october", tMONTH, 10 }, + { "november", tMONTH, 11 }, + { "december", tMONTH, 12 }, + { "sunday", tDAY, 0 }, + { "monday", tDAY, 1 }, + { "tuesday", tDAY, 2 }, + { "tues", tDAY, 2 }, + { "wednesday", tDAY, 3 }, + { "wednes", tDAY, 3 }, + { "thursday", tDAY, 4 }, + { "thur", tDAY, 4 }, + { "thurs", tDAY, 4 }, + { "friday", tDAY, 5 }, + { "saturday", tDAY, 6 }, + { NULL } +}; + +/* Time units table. */ +static TABLE UnitsTable[] = { + { "year", tMONTH_UNIT, 12 }, + { "month", tMONTH_UNIT, 1 }, + { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 }, + { "week", tMINUTE_UNIT, 7 * 24 * 60 }, + { "day", tMINUTE_UNIT, 1 * 24 * 60 }, + { "hour", tMINUTE_UNIT, 60 }, + { "minute", tMINUTE_UNIT, 1 }, + { "min", tMINUTE_UNIT, 1 }, + { "second", tSEC_UNIT, 1 }, + { "sec", tSEC_UNIT, 1 }, + { NULL } +}; + +/* Assorted relative-time words. */ +static TABLE OtherTable[] = { + { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 }, + { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 }, + { "today", tMINUTE_UNIT, 0 }, + { "now", tMINUTE_UNIT, 0 }, + { "last", tUNUMBER, -1 }, + { "this", tMINUTE_UNIT, 0 }, + { "next", tUNUMBER, 2 }, + { "first", tUNUMBER, 1 }, +/* { "second", tUNUMBER, 2 }, */ + { "third", tUNUMBER, 3 }, + { "fourth", tUNUMBER, 4 }, + { "fifth", tUNUMBER, 5 }, + { "sixth", tUNUMBER, 6 }, + { "seventh", tUNUMBER, 7 }, + { "eighth", tUNUMBER, 8 }, + { "ninth", tUNUMBER, 9 }, + { "tenth", tUNUMBER, 10 }, + { "eleventh", tUNUMBER, 11 }, + { "twelfth", tUNUMBER, 12 }, + { "ago", tAGO, 1 }, + { NULL } +}; + +/* The timezone table. */ +/* Some of these are commented out because a time_t can't store a float. */ +static TABLE TimezoneTable[] = { + { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */ + { "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */ + { "utc", tZONE, HOUR( 0) }, + { "wet", tZONE, HOUR( 0) }, /* Western European */ + { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */ + { "wat", tZONE, HOUR( 1) }, /* West Africa */ + { "at", tZONE, HOUR( 2) }, /* Azores */ +#if 0 + /* For completeness. BST is also British Summer, and GST is + * also Guam Standard. */ + { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */ + { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */ +#endif +#if 0 + { "nft", tZONE, HOUR(3.5) }, /* Newfoundland */ + { "nst", tZONE, HOUR(3.5) }, /* Newfoundland Standard */ + { "ndt", tDAYZONE, HOUR(3.5) }, /* Newfoundland Daylight */ +#endif + { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */ + { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */ + { "est", tZONE, HOUR( 5) }, /* Eastern Standard */ + { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */ + { "cst", tZONE, HOUR( 6) }, /* Central Standard */ + { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */ + { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */ + { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */ + { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */ + { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */ + { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */ + { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */ + { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */ + { "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */ + { "cat", tZONE, HOUR(10) }, /* Central Alaska */ + { "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */ + { "nt", tZONE, HOUR(11) }, /* Nome */ + { "idlw", tZONE, HOUR(12) }, /* International Date Line West */ + { "cet", tZONE, -HOUR(1) }, /* Central European */ + { "met", tZONE, -HOUR(1) }, /* Middle European */ + { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */ + { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ + { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */ + { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */ + { "fwt", tZONE, -HOUR(1) }, /* French Winter */ + { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */ + { "eet", tZONE, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */ + { "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */ +#if 0 + { "it", tZONE, -HOUR(3.5) },/* Iran */ +#endif + { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */ + { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */ +#if 0 + { "ist", tZONE, -HOUR(5.5) },/* Indian Standard */ +#endif + { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */ +#if 0 + /* For completeness. NST is also Newfoundland Stanard, and SST is + * also Swedish Summer. */ + { "nst", tZONE, -HOUR(6.5) },/* North Sumatra */ + { "sst", tZONE, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */ +#endif /* 0 */ + { "wast", tZONE, -HOUR(7) }, /* West Australian Standard */ + { "wadt", tDAYZONE, -HOUR(7) }, /* West Australian Daylight */ +#if 0 + { "jt", tZONE, -HOUR(7.5) },/* Java (3pm in Cronusland!) */ +#endif + { "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */ + { "jst", tZONE, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */ +#if 0 + { "cast", tZONE, -HOUR(9.5) },/* Central Australian Standard */ + { "cadt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */ +#endif + { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */ + { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */ + { "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */ + { "nzt", tZONE, -HOUR(12) }, /* New Zealand */ + { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */ + { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */ + { "idle", tZONE, -HOUR(12) }, /* International Date Line East */ + { NULL } +}; + +/* Military timezone table. */ +static TABLE MilitaryTable[] = { + { "a", tZONE, HOUR( 1) }, + { "b", tZONE, HOUR( 2) }, + { "c", tZONE, HOUR( 3) }, + { "d", tZONE, HOUR( 4) }, + { "e", tZONE, HOUR( 5) }, + { "f", tZONE, HOUR( 6) }, + { "g", tZONE, HOUR( 7) }, + { "h", tZONE, HOUR( 8) }, + { "i", tZONE, HOUR( 9) }, + { "k", tZONE, HOUR( 10) }, + { "l", tZONE, HOUR( 11) }, + { "m", tZONE, HOUR( 12) }, + { "n", tZONE, HOUR(- 1) }, + { "o", tZONE, HOUR(- 2) }, + { "p", tZONE, HOUR(- 3) }, + { "q", tZONE, HOUR(- 4) }, + { "r", tZONE, HOUR(- 5) }, + { "s", tZONE, HOUR(- 6) }, + { "t", tZONE, HOUR(- 7) }, + { "u", tZONE, HOUR(- 8) }, + { "v", tZONE, HOUR(- 9) }, + { "w", tZONE, HOUR(-10) }, + { "x", tZONE, HOUR(-11) }, + { "y", tZONE, HOUR(-12) }, + { "z", tZONE, HOUR( 0) }, + { NULL } +}; + + + + +/* ARGSUSED */ +int +yyerror(s) + char *s; +{ + return 0; +} + + +static time_t +ToSeconds(time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian) +{ + time_t ret = -1; + + if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59) + return -1; + switch (Meridian) { + case MER24: + if (Hours < 0 || Hours > 23) + return -1; + ret = (Hours * 60L + Minutes) * 60L + Seconds; + break; + case MERam: + if (Hours < 1 || Hours > 12) + return -1; + ret = (Hours * 60L + Minutes) * 60L + Seconds; + break; + case MERpm: + if (Hours < 1 || Hours > 12) + return -1; + ret = ((Hours + 12) * 60L + Minutes) * 60L + Seconds; + break; + } + return ret; +} + +time_t +Convert(time_t Month, time_t Day, time_t Year, + time_t Hours, time_t Minutes, time_t Seconds, + MERIDIAN Meridian, DSTMODE DSTmode, + time_t timezone) +{ + time_t now = time(0); + struct tm *tm = localtime(&now); + time_t timeval; + + if (Year >= 1900) + Year -= 1900; + + tm->tm_year = Year; + tm->tm_mon = Month-1; + tm->tm_mday = Day; + tm->tm_hour = Hours; + tm->tm_min = Minutes; + tm->tm_sec = Seconds; + + timeval = mktime(tm); + + timeval += timezone * 60L; + if (DSTmode == DSTon || + (DSTmode == DSTmaybe && localtime(&now)->tm_isdst)) + timeval -= 60*60; + + return timeval; +} + +static time_t +DSTcorrect(time_t Start, time_t Future) +{ + time_t StartDay; + time_t FutureDay; + + StartDay = (localtime(&Start)->tm_hour + 1) % 24; + FutureDay = (localtime(&Future)->tm_hour + 1) % 24; + return (Future - Start) + (StartDay - FutureDay) * 60L * 60L; +} + + +static time_t +RelativeDate(time_t Start, time_t DayOrdinal, time_t DayNumber) +{ + struct tm *tm; + time_t now; + + now = Start; + tm = localtime(&now); + now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7); + now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1); + return DSTcorrect(Start, now); +} + + +static time_t +RelativeMonth(time_t Start, time_t RelMonth) +{ + struct tm *tm; + time_t Month; + time_t Year; + + if (RelMonth == 0) + return 0; + tm = localtime(&Start); + Month = 12 * tm->tm_year + tm->tm_mon + RelMonth; + Year = Month / 12; + Month = Month % 12 + 1; + return DSTcorrect(Start, + Convert(Month, (time_t)tm->tm_mday, Year, + (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec, + MER24, DSTmaybe, yyTimezone)); +} + + +static int +LookupWord(char *buff) +{ + register char *p; + register char *q; + register TABLE *tp; + int i; + int abbrev; + + /* Make it lowercase. */ + for (p = buff; *p; p++) + if (isupper(*p)) + *p = tolower(*p); + + if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) { + yylval.Meridian = MERam; + return tMERIDIAN; + } + if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) { + yylval.Meridian = MERpm; + return tMERIDIAN; + } + + /* See if we have an abbreviation for a month. */ + if (strlen(buff) == 3) + abbrev = 1; + else if (strlen(buff) == 4 && buff[3] == '.') { + abbrev = 1; + buff[3] = '\0'; + } + else + abbrev = 0; + + for (tp = MonthDayTable; tp->name; tp++) { + if (abbrev) { + if (strncmp(buff, tp->name, 3) == 0) { + yylval.Number = tp->value; + return tp->type; + } + } + else if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + } + + for (tp = TimezoneTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + if (strcmp(buff, "dst") == 0) + return tDST; + + for (tp = UnitsTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + /* Strip off any plural and try the units table again. */ + i = strlen(buff) - 1; + if (buff[i] == 's') { + buff[i] = '\0'; + for (tp = UnitsTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + buff[i] = 's'; /* Put back for "this" in OtherTable. */ + } + + for (tp = OtherTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + /* Military timezones. */ + if (buff[1] == '\0' && isalpha(*buff)) { + for (tp = MilitaryTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + } + + /* Drop out any periods and try the timezone table again. */ + for (i = 0, p = q = buff; *q; q++) + if (*q != '.') + *p++ = *q; + else + i++; + *p = '\0'; + if (i) + for (tp = TimezoneTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + return tID; +} + + +int +yylex() +{ + register char c; + register char *p; + char buff[20]; + int Count; + int sign; + + for ( ; ; ) { + while (isspace(*yyInput)) + yyInput++; + + if (isdigit(c = *yyInput) || c == '-' || c == '+') { + if (c == '-' || c == '+') { + sign = c == '-' ? -1 : 1; + if (!isdigit(*++yyInput)) + /* skip the '-' sign */ + continue; + } + else + sign = 0; + for (yylval.Number = 0; isdigit(c = *yyInput++); ) + yylval.Number = 10 * yylval.Number + c - '0'; + yyInput--; + if (sign < 0) + yylval.Number = -yylval.Number; + return sign ? tSNUMBER : tUNUMBER; + } + if (isalpha(c)) { + for (p = buff; isalpha(c = *yyInput++) || c == '.'; ) + if (p < &buff[sizeof buff - 1]) + *p++ = c; + *p = '\0'; + yyInput--; + return LookupWord(buff); + } + if (c != '(') + return *yyInput++; + Count = 0; + do { + c = *yyInput++; + if (c == '\0') + return c; + if (c == '(') + Count++; + else if (c == ')') + Count--; + } while (Count > 0); + } +} + + +time_t +get_date(char *p, struct timeb *now) +{ + struct tm *tm; + struct timeb ftz; + time_t Start; + time_t tod; + + yyInput = p; + if (now == NULL) { + now = &ftz; + (void)ftime(&ftz); + } + + tm = gmtime(&now->time); + yyYear = tm->tm_year; + yyMonth = tm->tm_mon + 1; + yyDay = tm->tm_mday; +#if defined(timezone) + yyTimezone = now->tzone; +#else + yyTimezone = now->timezone; +#endif /* defined(timezone) */ + yyDSTmode = DSTmaybe; + yyHour = 0; + yyMinutes = 0; + yySeconds = 0; + yyMeridian = MER24; + yyRelSeconds = 0; + yyRelMonth = 0; + yyHaveDate = 0; + yyHaveDay = 0; + yyHaveRel = 0; + yyHaveTime = 0; + yyHaveZone = 0; + + if (yyparse() + || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1) + return -1; + + if (yyHaveDate || yyHaveTime || yyHaveDay) { + Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds, + yyMeridian, yyDSTmode, yyTimezone); + if (Start < 0) + return -1; + } + else { + Start = now->time; + if (!yyHaveRel) + Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec; + } + + Start += yyRelSeconds; + Start += RelativeMonth(Start, yyRelMonth); + + if (yyHaveDay && !yyHaveDate) { + tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber); + Start += tod; + } + + /* Have to do *something* with a legitimate -1 so it's distinguishable + * from the error return value. (Alternately could set errno on error.) */ + return Start == -1 ? 0 : Start; +} + + +#if defined(TEST) + +#include +/* ARGSUSED */ +main(ac, av) + int ac; + char *av[]; +{ + char buff[128]; + time_t d; + + (void)printf("Enter date, or blank line to exit.\n\t> "); + (void)fflush(stdout); + while (gets(buff) && buff[0]) { + d = get_date(buff, (struct timeb *)NULL); + if (d == -1) + (void)printf("Bad format - couldn't convert.\n"); + else + (void)printf("%s", ctime(&d)); + (void)printf("\t> "); + (void)fflush(stdout); + } + exit(0); + /* NOTREACHED */ +} +#endif /* defined(TEST) */ Added: trunk/filesystems/ftpfs/ftpconn.cc ============================================================================== --- trunk/filesystems/ftpfs/ftpconn.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/ftpconn.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,923 @@ +// -*- C++ -*- + +// Handle FTP connections + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#pragma implementation + +#include "ftpconn.h" +#include "LWP.h" +#include "ConfFile.h" +#include "serv_port.h" +#include "io.h" + +// Host types +#include "unix_host.h" +#include "dos_host.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define obstack_chunk_alloc malloc +#define obstack_chunk_free free + +static const serv_port ftp_port("ftp", "tcp"); + +class semlock +{ + Semaphore &sem; +public: + semlock(Semaphore &sem):sem(sem) { sem.wait(); } + ~semlock() { sem.signal(); } +}; + +ftpconn::ftpconn(const Path &conffile, const string &host) + :hostname(host), conf(conffile), sem(1) +{ + struct hostent *he = gethostbyname((const char *)hostname.data()); + + if (he == NULL) + { + cerr << "Hostname lookup for " << host << " failed: " << flush; + herror(""); + } + + init(he); +} + +ftpconn::ftpconn(const Path &conffile, const string &host, + const struct hostent *he) + :hostname(host), conf(conffile), sem(1) +{ + init(he); +} + +void +ftpconn::init(const struct hostent *he) +{ + lastreply = NULL; + ref = 0; + need_tz = 1; + need_siteroot = 1; + timezone = 0; + ctlsock = datasock = -1; + inbuf = NULL; + memset(&addr, 0, sizeof(addr)); + memset(&myaddr, 0, sizeof(myaddr)); + state = Unresolved; + + getparams(); + + if (state == Unresolved) + { + if (resolve_name(he) != 0) + return; + + state = Resolved; + } +} + +static unix_host unix_host_type; +static dos_host dos_host_type; + +host *host_types[] = +{ + &unix_host_type, + &dos_host_type, +}; + +// Various parameters for this site/connection +void +ftpconn::getparams() +{ + if (!conf.get("username", username)) + username="anonymous"; + if (!conf.get("password", passwd)) + passwd="ftpfs@"; // '@' makes some sites more agreeable + if (!conf.getnum("update_timeout", upd_timeout)) + upd_timeout = 60*60; + if (!conf.getnum("fail_timeout", fail_timeout)) + fail_timeout = 120; + if (conf.get("site_root", site_root)) + need_siteroot = 0; + + if (conf.getnum("timezone", timezone)) + need_tz = 0; + + string hosttype; + site_host = NULL; + if (conf.get("hosttype", hosttype)) + { + for (unsigned i = 0; + i < sizeof(host_types)/sizeof(*host_types); + i++) + if (hosttype == host_types[i]->hosttype()) + site_host = host_types[i]; + } + if (site_host == NULL) + site_host = &unix_host_type; + + string dotaddr; + if (conf.get("ip_address", dotaddr)) + if ((addr.sin_addr.s_addr = inet_addr(dotaddr.data())) != -1) + { + addr.sin_port = ftp_port.port; + addr.sin_family = AF_INET; + state = Resolved; + } +} + +void +ftpconn::setparams() +{ + if (state >= Resolved) + { + string dotaddr(inet_ntoa(addr.sin_addr)); + + conf.set("ip_address", dotaddr); + } + if (!need_tz) + conf.setnum("timezone", timezone); + if (!need_siteroot) + conf.set("site_root", site_root); + + conf.set("hosttype", site_host->hosttype()); +} + +ftpconn::~ftpconn() +{ + setparams(); + if (state > Resolved) + goto_state(Resolved); + if (inbuf) + delete inbuf; + cout << "FTP connection to " << hostname << " closed\n"; +} + +ftpstate_t +ftpconn::resolve(ftpstate_t) +{ + assert(state == Unresolved); + + struct hostent *he = gethostbyname(hostname.data()); + + if (resolve_name(he)) + return Bad; + return Resolved; +} + +int +ftpconn::resolve_name(const struct hostent *he) +{ + if (he == NULL) + return -1; + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = he->h_addrtype; + memcpy(&addr.sin_addr, he->h_addr_list[0], sizeof(he->h_length)); + addr.sin_port = ftp_port.port; + + return 0; +} + +ftpstate_t +ftpconn::connect(ftpstate_t) +{ + if (need_tz) + { + time_t now = time(0); // UTC + time_t there = site_host->localtime(addr); + + if (there == (time_t)-1) + there = now; // Fake it + + time_t diff = (now-there)/60; + + time_t d = diff; + cout << "Time diff = "<unsetf(ios::skipws); + + if (getreply() != 220) + { + cerr << "Failed to connect properly\n"; + ::close(ctlsock); + delete inbuf; + inbuf = NULL; + return Bad; + } + + cout << "Connected OK to " << hostname << '\n'; + + return Connected; +} + +ftpstate_t +ftpconn::close(ftpstate_t) +{ + ::close(ctlsock); + ::close(datasock); + + ctlsock = datasock = -1; + + return Resolved; +} + +ftpstate_t +ftpconn::login(ftpstate_t) +{ + int ret = 0; + + if (sendcmd("USER "+username) != 331) + return Bad; + + if (sendcmd("PASS "+passwd) != 230) + return Bad; + + if (need_siteroot && ftpcwd(site_root)/100 != 2) + { + cout << "Failed to get CWD\n"; + site_root = "."; + } + else + need_siteroot = 0; + + if (ftpsetcwd(site_root) != 250) + { + goto_state(Resolved); + return Bad; + } + + if (ret != 0) + cout << "Login as " << username << + ", passwd " << passwd << " failed\n"; + else + { + sendcmd("SYST"); + sendcmd("STAT"); + } + + return LoggedIn; +} + +ftpstate_t +ftpconn::logout(ftpstate_t) +{ + sendcmd("QUIT"); + return Connected; +} + +ftpstate_t +ftpconn::listen(ftpstate_t) +{ + dataaddr = myaddr; // Our address + dataaddr.sin_port = 0; // System port + + closedata(LoggedIn); + + if ((datasock = socket(AF_INET, SOCK_STREAM, 0)) == -1) + { + perror("creation of data socket failed"); + return Bad; + } + + if (::bind(datasock, (struct sockaddr *)&dataaddr, sizeof(dataaddr)) == -1) + { + perror("bind of data socket"); + closedata(LoggedIn); + return Bad; + } + + int len = sizeof (dataaddr); + if (getsockname(datasock, (struct sockaddr *)&dataaddr, (socklen_t *)&len) == -1) + { + perror("data socket getsockname"); + closedata(LoggedIn); + return Bad; + } + + if (::listen(datasock, 1) == -1) + { + perror("listen on data socket"); + closedata(LoggedIn); + return Bad; + } + + char *addr = (char *)&dataaddr.sin_addr; + char *port = (char *)&dataaddr.sin_port; + char buf[128]; + +#define UC(b) (((int)b)&0xff) + sprintf(buf, "PORT %d,%d,%d,%d,%d,%d", + UC(addr[0]), UC(addr[1]), UC(addr[2]), UC(addr[3]), + UC(port[0]), UC(port[1])); +#undef UC + if (sendcmd(buf)/100 != 2) + { + cerr << "Send of \"" << buf << "\" failed\n"; + return Bad; + } + + return Listening; +} + +ftpstate_t +ftpconn::closedata(ftpstate_t nst) +{ + ::close(datasock); + datasock = -1; + return nst; +} + + +ftpstate_t +ftpconn::abort(ftpstate_t nst) +{ + if (state == Transfer) + sendcmd("ABOR"); + return nst; +} + +static const char *st_name[] = +{ + "Unresolved", + "Resolved", + "Connected", + "LoggedIn", + "Listening", + "Transfer", + "Bad" +}; + +int +ftpconn::goto_state(ftpstate_t newstate) +{ + typedef enum + { + tr_NONE, tr_RESOLVE, tr_CONNECT, + tr_CLOSE, tr_LOGIN, tr_LOGOUT, + tr_LISTEN, tr_CLOSEDATA, tr_ABORT + } trfunc; + + static trfunc trtab[6][6] = + { + { tr_NONE, tr_RESOLVE, tr_RESOLVE, tr_RESOLVE, tr_RESOLVE, tr_NONE }, + { tr_NONE, tr_NONE, tr_CONNECT, tr_CONNECT, tr_CONNECT, tr_NONE }, + { tr_NONE, tr_CLOSE, tr_NONE, tr_LOGIN, tr_LOGIN, tr_NONE }, + { tr_NONE, tr_LOGOUT, tr_LOGOUT, tr_NONE, tr_LISTEN, tr_NONE }, + { tr_NONE, tr_CLOSEDATA, tr_CLOSEDATA, tr_CLOSEDATA, tr_NONE, tr_CLOSEDATA }, + { tr_NONE, tr_ABORT, tr_ABORT, tr_ABORT, tr_ABORT, tr_NONE }, + }; + + while(state != newstate) + { + ftpstate_t next; + assert(state < Bad); + assert(newstate < Bad); + trfunc tr = trtab[state][newstate]; + switch (tr) + { + case tr_RESOLVE: + next = ftpconn::resolve(newstate); + break; + case tr_CONNECT: + next = ftpconn::connect(newstate); + break; + case tr_CLOSE: + next = ftpconn::close(newstate); + break; + case tr_LOGIN: + next = ftpconn::login(newstate); + break; + case tr_LOGOUT: + next = ftpconn::logout(newstate); + break; + case tr_LISTEN: + next = ftpconn::listen(newstate); + break; + case tr_CLOSEDATA: + next = ftpconn::closedata(newstate); + break; + case tr_ABORT: + next = ftpconn::abort(newstate); + break; + case tr_NONE: + default: + cerr << "No transition from " << st_name[state] + << " to " << st_name[newstate] << '\n'; + return -1; + break; + } + + + if (next == Bad) + { + cerr << "Transition from " << st_name[state] + << " to " << st_name[newstate] << " failed\n"; + return -1; + } + state = next; + } + + return 0; +} + +/* + * Send a command to the ftp server. + * + * All we do is pack the command off to the other server, and call getreply() + * to deal with the response. We just return the code from getreply(). + * + * It returns either the code from getreply() or return with -1 and errno + * set if there is a syscall failure. + */ +int +ftpconn::sendcmd(string command, string *repl) +{ + int ret; + int retry = 0; + + cout << "Sending command \"" << command << "\"\n"; + command += "\r\n"; + + if (fullwrite(ctlsock, (const unsigned char *)command.data(), + command.length()) != command.length()) + { + perror("fullwrite of command failed"); + return -1; + } + + ret = getreply(repl); + + return ret; +} + +/* + * Get a reply from the ftp daemon, and deal with it. + * + * This is all dealing with the FTP protocol - see Internet RFC 959 + * to find out what all this really means. + * + * These are the RFC 959 return codes, attached to the beginning of each + * reply from the remote machine. + * + * FTP Code Meaning + * 1xx success (positive preliminary reply) + * 2xx success (positive completion reply) + * 3xx success (positive intermediate reply) + * 4xx failure (transiant negative completion reply) + * 5xx failure (permanent negative completion reply) + * + * + * The code returned is either '-1' if some system call failure happens, + * or the code number attached to the reply. + */ +int +ftpconn::getreply(string *str) +{ + unsigned char ch; + int digit; // Which digit we're processing + int code; // Numeric code + static struct obstack reply; +// Obstack reply; // Reply in string form + + obstack_init (&reply); + digit = 0; + code = 0; + + while((*inbuf >> ch) && ch != '\n') + { + if (ch == IAC) + { + char telcode[4]; + + /* + * Deal with telnet protocol commands by ignoring them + */ + *inbuf >> ch; + switch (ch) + { + case WILL: + case WONT: + *inbuf >> ch; + sprintf(telcode, "%c%c%c", IAC, DONT, ch); + fullwrite(ctlsock, (unsigned char *)telcode, 3); + break; + case DO: + case DONT: + *inbuf >> ch; + sprintf(telcode, "%c%c%c", IAC, WONT, ch); + fullwrite(ctlsock, (unsigned char *)telcode, 3); + break; + default: + break; + } + continue; + } + + if (ch == '\r') + continue; + + obstack_1grow(&reply, ch); + + if (digit < 3 && isdigit(ch)) + code = code*10 + ch-'0'; + + /* + * Handle multi-line messages + * These have the form: + * xyz-message + * message contents + * multiple lines + * xyz end message + */ + if (digit == 3 && ch == '-') + { + string line; + char codebuf[5]; /* string at end of message */ + char dat[200]; + unsigned int pos; + + sprintf(codebuf, "%3.03d ", code); + do + { + inbuf->getline(dat, 200); + line = dat; + if ((pos=line.find('\r', 0)) != string::npos) + line = line.substr(0, pos); + obstack_grow(&reply, (void *)line.data(), line.length()); + obstack_1grow(&reply, '\n'); + } + while(inbuf->good() && codebuf != line.substr(0,4)); + + if (!inbuf->good()) + { + perror("inbuf->readline failed"); + state = Resolved; + close(Resolved); + return -1; + } + break; + } + else if (digit == 3 && ch != ' ') + fprintf(stderr, "RFC 959 violation: Unexpected character after digits - 0x%02x, not ' '\n", ch); + digit++; + } + + if (inbuf->eof() || inbuf->bad()) + { + // If we get an EOF, then just go straight to Resolved state + close(Resolved); + state = Resolved; + return -1; + } + char *buf = (char *)obstack_finish(&reply); + if (str != NULL) + *str = string(buf); + + if (lastreply) + delete lastreply; + lastreply = new string(buf); + + cout << "Message \"" << *lastreply << "\"\n" << + "getreply() returning " << code << '\n'; + + return code; +} + +class ftp_return +{ + const string &p; + ftpconn &ftp; + + public: + ftp_return(ftpconn &ftp, const string &p) + :p(p),ftp(ftp) + { + } + ~ftp_return() + { + ftp.ftpsetcwd(p, 1); + } +}; + +// Get a file list from an ftp server +// Calls host-specific code to parse the directory listing +ftp_filelist * +ftpconn::getfilelist(const string &dname) +{ + string dirname = dname; + unsigned int l; + + string path,dir; + string + const string &wildcard = site_host->wildcard(); + path = dirname.substr(0, + dir = dirname.after('/', -1); + l=dirname.rfind('/',0); + if (dir == "") + dir = dname; + + semlock lock(sem); + + cout << "ftpconn::getfilelist getting dir on host " << hostname + << ", dirname=" << dirname << ", basedir=" << path + << ", subdir=" << dir << "\n"; + + if (goto_state(LoggedIn)) + { + fprintf(stderr, "Failed to log in\n"); + return NULL; + } + + if (sendcmd("TYPE A") != 200) + { + fprintf(stderr, "Failed to set TYPE A\n"); + return NULL; + } + + ftp_return ftp_here(*this, site_root); + if (path != "" && ftpsetcwd(path) != 250) + { + cerr << "Failed to change to \"" << path << "\"\n"; + return NULL; + } + + if (goto_state(Listening)) + { + fprintf(stderr, "Failed to listen\n"); + return NULL; + } + + if (sendcmd("LIST "+dir+wildcard)/100 != 1) + { + fprintf(stderr, "Failed to send LIST\n"); + return NULL; + } + + struct sockaddr_in from; + int fromlen = sizeof(from); + int sfd; + + if ((sfd = ::accept(datasock, (struct sockaddr *)&from, &fromlen)) == -1) + { + perror("Failed to accept()"); + goto_state(LoggedIn); + return NULL; + } + closedata(LoggedIn); + + ifstream in(sfd); + string line; + ftp_filelist *fl = NULL; + + int ret; + while((ret = readline(in, line)) > 0) + { + if (line.contains('\r')) + line = line.before('\r'); + + ftp_filelist *nfl = site_host->parse_filelist(line, timezone); + + if (nfl == NULL) + continue; + nfl->next = fl; + fl = nfl; + } + + ::close(sfd); + getreply(); + goto_state(LoggedIn); + + return fl; +} + +int +ftpconn::getfile(const string &fname, int fd, ftpxfer *xfer) +{ + string filename = fname; + string path = filename.before('/', -1); + string file = filename.after('/', -1); + if (file == "") + file = fname; + + semlock lock(sem); + + cout << "ftpconn::getfile getting file on host " << hostname + << ", dir " << path << ", file " << file << "\n"; + + if (goto_state(LoggedIn)) + { + fprintf(stderr, "Failed to log in\n"); + if (xfer != NULL) + xfer->error(EPERM); + return -1; + } + + ftp_return ftp_here(*this, site_root); + if (path != "" && ftpsetcwd(path) != 250) + { + cerr << "Failed to change to \"" << path << "\n"; + return -1; + } + + + if (sendcmd("TYPE I") != 200) + { + fprintf(stderr, "Failed to set TYPE I\n"); + if (xfer != NULL) + xfer->error(EIO); + return -1; + } + + if (goto_state(Listening)) + { + fprintf(stderr, "Failed to listen\n"); + if (xfer != NULL) + xfer->error(EIO); + return -1; + } + + if (sendcmd("RETR "+file)/100 != 1) + { + fprintf(stderr, "Failed to send RETR\n"); + if (xfer != NULL) + xfer->error(EIO); + return -1; + } + + struct sockaddr_in from; + int fromlen = sizeof(from); + int sfd; + + if ((sfd = ::accept(datasock, (struct sockaddr *)&from, &fromlen)) == -1) + { + perror("Failed to accept()"); + if (xfer != NULL) + xfer->error(errno); + goto_state(LoggedIn); + return -1; + } + + goto_state(Transfer); + + unsigned char buf[2048]; + int ret; + + cout << "Fetching " << file << " from " << hostname << ':' << path << '\n'; + while((ret = fullread(sfd, buf, sizeof(buf))) > 0) + { + putchar('#'); fflush(stdout); + if (fullwrite(fd, buf, ret) == -1) + { + ret = -1; + break; + } + + if (xfer) + xfer->notify(sfd); + } + if (ret == -1) + { + perror("file xfer failed"); + if (xfer != NULL) + xfer->error(errno); + ::close(sfd); + goto_state(LoggedIn); + return -1; + } + + cout << file << " done\n"; + + getreply(); + ::close(sfd); + + state = LoggedIn; // Go directly, avoid unneeded ABOR + + return 0; +} + +int +ftpconn::ftpcwd(string &cwd) +{ + string repl; + int ret; + + if ((ret = sendcmd("PWD", &repl)) != 257) + return ret; + + static const Regex bqrx("^[^\"]*\""); + static const Regex aqrx("\"[^\"]*$"); + static const Regex rmqrx("\"\""); + static const string nil; + + repl.gsub(bqrx, nil); + repl.gsub(aqrx, nil); + repl.gsub(rmqrx, nil); + + cwd = repl; + return ret; +} + +int +ftpconn::ftpsetcwd(const string &dir, int nostep) +{ + int ret; + static const string cwd("CWD "); + + if (nostep) + ret = sendcmd(cwd+dir); + else + { + string *steps; + int nelem = site_host->pathsteps(dir, &steps); + int i; + + ret = 250; + + for(i = 0; i < nelem; i++) + { + ret = sendcmd(cwd+steps[i]); + if (ret / 100 != 2) + break; + } + + delete [] steps; + } + return ret; +} + +int +ftpconn::makedir(const string &dname) +{ + string dirname = dname; + string path = dirname.before('/', -1); + string dir = dirname.after('/', -1); + if (dir == "") + dir = dname; + + semlock lock(sem); + + cout << "ftpconn::makedir making dir on host " << hostname + << ", dirname=" << dirname << ", basedir=" << path + << ", subdir=" << dir << "\n"; + + if (goto_state(LoggedIn)) + { + fprintf(stderr, "Failed to log in\n"); + return -1; + } + + ftp_return ftp_here(*this, site_root); + if (path != "" && ftpsetcwd(path) != 250) + { + cerr << "Failed to change to \"" << path << "\"\n"; + return -1; + } + + int ret = sendcmd("MKD "+dir); + + if (ret/100 != 2) + return -1; + return 0; +} Added: trunk/filesystems/ftpfs/conninfo.cc ============================================================================== --- trunk/filesystems/ftpfs/conninfo.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/conninfo.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,70 @@ +// -*- C++ -*- + +// Get/set info about connection + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#pragma implementation + +#include + +#include "conninfo.h" +#include "ftpconn.h" + +#include + +conninfo::conninfo(ftpfs &fs, ftpconn *c) + :ino(fs), conn(c) +{ + // Use our invoker's ID rather than the person doing the syscall. + uid = getuid(); + gid = getgid(); + mode = S_IFREG | 0444; + size = 0; +} + +conninfo::~conninfo() +{ +} + +int +conninfo::do_read(const up_preamble &, upp_repl &, + const upp_read_s &arg, upp_read_r &ret) +{ + string s; + + conn->setparams(); + conn->conf.unparsestr(s); + + if (conn->lastreply != NULL) + { + s += "Last reply: "; + s += *conn->lastreply + "\n"; + } + + cout << "arg.off="< arg.size ? arg.size : sz; + + ret.data.alloc(sz); + ret.data.nelem = sz; + memcpy(ret.data.elems, s.chars() + arg.off, sz); + + return 0; +} + +int +conninfo::do_write(const up_preamble &, upp_repl &, + const upp_write_s &arg, upp_write_r &ret) +{ + ret.wrote = arg.data.nelem; + + return 0; +} Added: trunk/filesystems/ftpfs/README ============================================================================== --- trunk/filesystems/ftpfs/README 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/README 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,79 @@ + ftpfs - FTP filesystem + + *** BEWARE *** +This is a new experimental filesystem. It has never been tested on +the open Internet. If something goes wrong, it can quite easily +saturate an FTP site and generate a lot of network bandwidth. + ************** + +This filesystem allows FTP sites to be accessed in a filesystem-like +way. Normally they will be anonymous FTP sites, but non-anonymous +ones can be set up. + +It should be mounted like so: + muserfs ftpfs mount-point cache-dir + +The cache dir contains a long-term cache of the ftp'd data to minimize +network use. The filesystem shape and the cache dir have the same +shape: there is a directory for each site in the top directory, with +the tree for that site underneath. + +To connect to a new site, type "mkdir sitename" (where sitename is a +hostname, fully qualified if necessary) in the top filesystem +directory. This will resolve the name and create a new cache +directory. After that, you can just cd into the site and look around. +Inaccessable directories appear to be empty, but otherwise the +filesystem looks just like the ftp site. Files which are out of date +or not present in the cache are transferred as required; otherwise +they are just fetched from the local cache. + +There are a number of config and parameter files about. They all have +the same format: one parameter per line in the form "name: value". + +Each site dir in the cache tree has a file called ".ftpfs_site" which +has site-related parameters. "username" and "password" are supported, +because any user can mount the filesystem, users can have private +cache directories with secret usernames and passwords (so long as the +cache has 700 permissions). Also there are also "failure_timeout" +(time before retying after an error) and "update_timeout" (time to +update after the last update, without any other reason). Both are in +seconds. "timezone" is for timezone correction of times from the +remote site, measured in number of minutes needed to be added to the +time to make it UTC (GMT). ftpfs makes an attempt to find the local +time at target machines to determine this automatically, but anonymous +FTP sites often give times and dates in UTC anyway. + +Also, if you touch the file ".ftpfs_update" in any directory in the +filesystem (which never exists), it causes the directory its in to be +updated. + +Each directory in the cache (apart from the very top one) has a +".ftpfs_dir" file containing per-directory information. There are a +couple of valid parameters it uses: "last_update", which is the time +the directory was last looked at on the ftp site (0 if it hasn't), and +"last_failure" which is the last time this dir failed to be updated. +Each directory also has a ".ftpfs_dirinfo" file, which contains +information about files in the directory, even if they have not been +transferred yet. + +Also, the filesystem only copes with unix ftp sites. Parsers for +different pathname syntaxes and LIST outputs have to be written for +other OS types. + +This filesystem uses a threads library to maintain multiple threads of +execution. This allows more than one process to use the filesystem at +once. For example, even if one process is reading from a long FTP +transfer, other processes can use other FTP sites, or even the same +one without being affected much (response time is slower, but its +better than nothing). Unfortunately, since the filesystem only +maintains one FTP connection per site, only one file at a time can be +read from an FTP site. I may fix this in future to allow more than +one FTP connection per site. + +There is a perl script "reap.pl" which prunes ftpfs cache trees of +old files to keep the total cache size below some preset size. +At present this needs to be invoked from a cron job or some similar +mechanism, though in future ftpfs may invoke it itself if the cache +is full. + + J Added: trunk/filesystems/ftpfs/ftpconn.h ============================================================================== --- trunk/filesystems/ftpfs/ftpconn.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/ftpconn.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,145 @@ +// -*- C++ -*- + +// FTP connection class + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#ifndef _FTPCONN_H_ +#define _FTPCONN_H_ + +#pragma interface + +#include +#include + +#include "LWP.h" +#include "ConfFile.h" + +enum ftpstate_t { + Unresolved, + Resolved, + Connected, + LoggedIn, + Listening, + Transfer, + Bad +}; + +#include +#include + +enum ftp_filetype +{ + FT_Unknown, + FT_File, + FT_Directory, + FT_Link +}; + +struct ftp_filelist +{ + string name; + string link; + ftp_filetype type; + time_t time; + size_t size; + + ftp_filelist *next; +}; + +class ftpconn +{ + friend class conninfo; + + // Reference count + int ref; + + // Connection state + ftpstate_t state; + const string hostname; + + // Parameters + string username; // Username (default "anonymous") + string passwd; // Password + string site_root; // Dir to cd to + short need_siteroot; + time_t timezone; // Seconds from GMT + short need_tz; + time_t upd_timeout; // Time before an update times out + time_t fail_timeout; // Time before retrying after failure + void getparams(); + void setparams(); + + class host *site_host; // Site's host-specific operations + + // Config file + ConfFile conf; + conninfo *infoino; + + // Control connection + struct sockaddr_in addr; + struct sockaddr_in myaddr; + int ctlsock; + + class ifstream *inbuf; + + // Data connection + struct sockaddr_in dataaddr; + int datasock; + + void init(const struct hostent *); + int resolve_name(const struct hostent *); + + // Transition functions + ftpstate_t resolve(ftpstate_t); + ftpstate_t connect(ftpstate_t); + ftpstate_t close(ftpstate_t); + ftpstate_t login(ftpstate_t); + ftpstate_t logout(ftpstate_t); + ftpstate_t listen(ftpstate_t); + ftpstate_t closedata(ftpstate_t); + ftpstate_t abort(ftpstate_t); + + int goto_state(ftpstate_t); + + int sendcmd(string cmd, string * = NULL); + int getreply(string * = NULL); + string *lastreply; + + Semaphore sem; + +public: + ftpconn(const Path &conffile, const string &host); + ftpconn(const Path &conffile, const string &host, + const struct hostent *); + ~ftpconn(); + + ftp_filelist *getfilelist(const string &path); + int getfile(const string &path, int fd, class ftpxfer *); + int ftpcwd(string &cwd); + int ftpsetcwd(const string &cwd, int =0); + int makedir(const string &dir); + + void incref() { ref++; } + void decref() + { + if (--ref == 0) + delete this; + } + + int get_upd_timeout() const { return upd_timeout; } + int get_fail_timeout() const { return fail_timeout; } +}; + +class ftpxfer +{ +public: + virtual ~ftpxfer() {} + + virtual void notify(int) = 0; + virtual void error(int) {} +}; + +#endif /* _FTPCONN_H_ */ Added: trunk/filesystems/ftpfs/conninfo.h ============================================================================== --- trunk/filesystems/ftpfs/conninfo.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/conninfo.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,30 @@ +// -*- C++ -*- + +// Get/set connection info + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#ifndef _CONNINFO_H_ +#define _CONNINFO_H_ + +#pragma interface + +#include "ino.h" +#include + +class conninfo : public ino +{ + class ftpconn *conn; + + int do_write(const up_preamble &, upp_repl &, + const upp_write_s &, upp_write_r &); + int do_read(const up_preamble &, upp_repl &, + const upp_read_s &, upp_read_r &); + +public: + conninfo(class ftpfs &, class ftpconn *conn); + ~conninfo(); +}; +#endif /* _CONNINFO_H_ */ Added: trunk/filesystems/ftpfs/host.cc ============================================================================== --- trunk/filesystems/ftpfs/host.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/host.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,18 @@ +// -*- C++ -*- + +// Simple implementation file for class host + +#pragma implementation + +#include "host.h" + +host::~host() +{ +} + +const string & +host::wildcard() const +{ + static const string nil; + return nil; +} Added: trunk/filesystems/ftpfs/host.h ============================================================================== --- trunk/filesystems/ftpfs/host.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/host.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,36 @@ +// -*- C++ -*- + +// Host-type specific information + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#ifndef _HOST_H_ +#define _HOST_H_ + +#pragma interface + +#include +#include +#include + +class host +{ +public: + virtual ~host(); + + // Return steps to get to required directory + virtual int pathsteps(const string &path, string *steps[]) = 0; + + // Get local time + virtual time_t localtime(struct sockaddr_in) = 0; + + // Parse a line of file listing + virtual struct ftp_filelist *parse_filelist(const string &, time_t) = 0; + // Return host type identifier + virtual const string &hosttype() const = 0; + virtual const string &wildcard() const; +}; + +#endif /* _HOST_H_ */ Added: trunk/filesystems/ftpfs/unix_host.cc ============================================================================== --- trunk/filesystems/ftpfs/unix_host.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/unix_host.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,238 @@ +// -*- C++ -*- + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#pragma implementation + +#include "unix_host.h" +#include "serv_port.h" +#include "ftpconn.h" +#include "getdate.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static const serv_port daytime_port("daytime", "tcp"); + +int +unix_host::pathsteps(const string &path, string *ret[]) +{ + static const Regex deldot("\\(^\\./\\)\\|\\(/\\.\\/\\)\\|\\(/\\.$\\)\\|\\(//\\)\\|\\(^\\.$\\)"); + static const Regex deldotdot("\\(^|/\\)[^/]+/\\.\\./"); + + *ret = new string[1]; + (*ret)[0] = path; + (*ret)[0].gsub(deldot, ""); + (*ret)[0].gsub(deldotdot, "/"); + + if ((*ret)[0] == "") + return 0; + + return 1; +} + +// Get local time at remote machine with the "time" service +time_t +unix_host::localtime(struct sockaddr_in addr) +{ + int fd; + unsigned char rawtime[512]; + int size; + + addr.sin_port = daytime_port.port; + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) + { + perror("Time service socket"); + return -1; + } + + if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) + { + perror("Time service connect"); + close(fd); + return -1; + } + + if ((size = fullread(fd, rawtime, sizeof(rawtime)-1)) == -1) + { + perror("Time service read"); + close(fd); + return -1; + } + close(fd); + + rawtime[size] = 0; + + time_t rtime = get_date(rawtime, NULL); + + struct tm *tm = ::gmtime(&rtime); + cout << "Remote time "<tm_year : year, + hours == -1 ? 0 : hours, + mins == -1 ? 0 : mins, 0, + MER24, DSToff, timezone); +} + +struct ftp_filelist * +unix_host::parse_filelist(const string &ro_line, time_t timezone) +{ + string line = ro_line; + + // Match a line of "ls" output + static const Regex ls_line( + "^\\([-dl][r-][w-][xsS-][r-][w-][xs-][r-][w-][xTt-]\\) *"// perms + "[0-9]+ +" // links + "[0-9a-zA-Z_-]+ +" // uid + "[0-9a-zA-Z_-]+ +" // gid + "\\([0-9]+\\) +" // size + "\\(\\(Jan\\|Feb\\|Mar\\|Apr\\|May\\|Jun\\|Jul\\|Aug\\|Sep\\|Oct\\|Nov\\|Dec\\) \\( \\|[0-9]\\)[0-9] \\([012][0-9]:[0-5][0-9]\\| [0-9][0-9][0-9][0-9]\\)\\) " // date + "\\(.+\\)$" // name + ); + static const Regex bsd_ls_line( + "^\\([-dl][r-][w-][xsS-][r-][w-][xs-][r-][w-][xTt-]\\) *"// perms + "[0-9]+ +" // links + "[0-9a-zA-Z_-]+ +" // uid + "\\([0-9]+\\) +" // size + "\\(\\(Jan\\|Feb\\|Mar\\|Apr\\|May\\|Jun\\|Jul\\|Aug\\|Sep\\|Oct\\|Nov\\|Dec\\) \\( \\|[0-9]\\)[0-9] \\([012][0-9]:[0-5][0-9]\\| [0-9][0-9][0-9][0-9]\\)\\) " // date + "\\(.+\\)$" // name + ); + + const Regex *ls_rx = &ls_line; + + if (!line.matches(ls_line)) + { + if (!line.matches(bsd_ls_line)) + { + cout << "Failed to match ls line " << line << '\n'; + return NULL; + } + ls_rx = &bsd_ls_line; + } + + int start, len; + + ftp_filelist *nf = new ftp_filelist; + ls_rx->match_info(start, len, 7); + nf->name = string(line.at(start,len)); + + switch(line[0]) + { + case 'd': + nf->type = FT_Directory; + break; + case '-': + nf->type = FT_File; + break; + case 'l': + { + string name = nf->name; + static const Regex sym_rx("^\\([^ ]+\\) -> \\(.*\\)$"); + if (!name.matches(sym_rx)) + { + nf->type = FT_Unknown; + break; + } + + nf->type = FT_Link; + sym_rx.match_info(start, len, 1); + nf->name = string(name.at(start, len)); + sym_rx.match_info(start, len, 2); + nf->link = string(name.at(start, len)); + } + break; + default: + nf->type = FT_Unknown; + } + + ls_rx->match_info(start, len, 2); + string sz_str(line.at(start, len)); + nf->size = strtol(sz_str, NULL, 10); + + ls_rx->match_info(start, len, 3); + string date_str(line.at(start, len)); + nf->time = parsedate(date_str, timezone); + nf->next = NULL; + + struct tm *tm = gmtime(&nf->time); + cout << "Name " << nf->name << " size " << nf->size << + " date " << asctime(tm); + + return nf; +} + +const string & +unix_host::hosttype() const +{ + static const string ux("unix"); + + return ux; +} Added: trunk/filesystems/ftpfs/dir.h ============================================================================== --- trunk/filesystems/ftpfs/dir.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/dir.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,57 @@ +// -*- C++ -*- + +// Directory inodes +// This contains the basic sync mechanisms for priming from a disk +// filesystem, and for serializing access to a single inode + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#ifndef _DIR_H_ +#define _DIR_H_ + +#pragma interface + +#include +#include +#include +#include "Path.h" + +class ftpfs; +class ftpconn; + +class dir: public DirInode +{ + int do_iput(const up_preamble &, upp_repl &, const upp_iput_s &); + + void beforeop(up_ops); + void afterop(up_ops); + + Semaphore sem; + +protected: + Path name; + + virtual Inode *newinode(dir *, const struct stat *, const string &) = 0; + + ftpfs &filesys; + dir *parent; +public: + dir(ftpfs &fs, const string &name, dir *up); + + string path() const { return name.path(); } + + virtual int depth() const + { + if (parent && parent != this) + return parent->depth() + 1; + return 0; + } + + int open(); + const Path &getname() const { return name; } + void init(); +}; + +#endif /* _FTPDIR_H_ */ Added: trunk/filesystems/ftpfs/dos_host.h ============================================================================== --- trunk/filesystems/ftpfs/dos_host.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/dos_host.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,30 @@ +// -*- C++ -*- + +// DOS host information + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +// Dos ftp server support by marcus@ee.pdx.edu (Marcus Daniels) + +#ifndef _DOS_HOST_H_ +#define _DOS_HOST_H_ + +#pragma interface + +#include "host.h" +#include +#include +#include + +class dos_host: public host +{ + int pathsteps(const string &, string *steps[]); + time_t localtime(struct sockaddr_in); + struct ftp_filelist *parse_filelist(const string &, time_t); + const string &hosttype() const; + const string &wildcard() const; +}; + +#endif /* _DOS_HOST_H_ */ Added: trunk/filesystems/ftpfs/ftpfs.h ============================================================================== --- trunk/filesystems/ftpfs/ftpfs.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/ftpfs.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,46 @@ +// -*- C++ -*- + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#ifndef _FTPFS_H_ +#define _FTPFS_H_ + +#pragma interface + +#include +#include + +// Thread priorities for different classes of threads +// Operations should be quick, so they get timely response. +// UPD_TPRI is higher than COM_TPRI, but it blocks itself to be +// woken by the comm thread, so its really lower priority... +#define OPS_TPRI 7 // Doing operations +#define UPD_TPRI 5 // Updating a file (bulk FTP transfer) +#define COM_TPRI 4 // Waiting for select input + +class ftpfs : public Filesystem +{ + string cache; + + Handle hcount; + + Inode *root; + +public: + ftpfs(const char *mpoint, const string &cache); + ~ftpfs(); + + const uid_t uid; + const gid_t gid; + + int do_mount(const up_preamble &, upp_repl &, + upp_mount_r &ret); + + int Enquire(up_ops); + + Handle genhand() { return hcount++; } +}; + +#endif /* _FTPFS_H_ */ Added: trunk/filesystems/ftpfs/ConfFile.cc ============================================================================== --- trunk/filesystems/ftpfs/ConfFile.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/ConfFile.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,185 @@ +// -*- C++ -*- + +// Config file handling + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#pragma implementation + +#include "ConfFile.h" +#include "pushd.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +ConfFile::ConfFile(const Path &path) + :name(path) +{ + list = NULL; + + parse(); + changed = 0; +} + +ConfFile::~ConfFile() +{ + unparse(); + for(list_t *next; list; list = next) + { + next = list->next; + delete list; + } +} + +void +ConfFile::unparsestr(string &s) const +{ + for(const list_t *p = list; p != NULL; p = p->next) + s += p->name + ": " + p->val + "\n"; +} + +void +ConfFile::unparse() +{ + if (!changed) + return; + + string path = name.path(); + ofstream out(path.data(), ios::out|ios::trunc, 0644); + + if (out.bad()) + { + cout << "Failed to open config file " << path << "\n"; + return; + } + + string s; + unparsestr(s); + out << s; + + changed = 0; +} + +void +ConfFile::parseline(const string &line) +{ + string &mline = (string &)line; + + if (line[0] == '#') + return; + +regex_t regex; +regmatch_t matches[2]; + +if (regcomp(®ex, "^\\([a-zA-Z_]+\\):[ \t]*\\(.*\\)$", 0)==0) +{ + if (regexec(®ex, line.data(), 2, matches,0)!=REG_NOMATCH) + { + if (matches[0].rm_so!=-1 && matches[1].rm_so!=-1) + { + string n(mline.substr(matches[0].rm_so, matches[0].rm_eo+1)); + string v(mline.substr(matches[1].rm_so, matches[1].rm_eo+1)); + set(n, v); + } + } + regfree(®ex); +} + +} + +void +ConfFile::parse() +{ + char *dat; + int ret; + string path = name.path(); + ifstream in(path.data(), ios::in, 0664); + + if (in.bad()) + return; + dat = (char *)malloc(200); + while(!in.eof()) + { + in.getline(dat, 200); + const string line(dat); + parseline(line); + } + free(dat); +} + +ConfFile::list_t * +ConfFile::find(const string &name) const +{ + list_t *p; + + for(p = list; p != NULL; p = p->next) + if (name == p->name) + return p; + return NULL; +} + +int +ConfFile::get(const string &name, string &val) const +{ + list_t *p; + + if ((p = find(name)) == NULL) + return 0; + val = p->val; + return 1; +} + +void +ConfFile::set(const string &name, const string &val) +{ + list_t *p; + + p = find(name); + + if (p == NULL) + { + p = new list_t; + p->name = name; + p->next = list; + list = p; + } + p->val = val; + + changed = 1; +} + +void +ConfFile::setnum(const string &name, long val) +{ + char buf[32]; + ostrstream str(buf, sizeof(buf)); + + str << val << '\0'; + + set(name, string(buf)); +} + +int +ConfFile::getnum(const string &name, long &val) const +{ + string v; + + if (!get(name, v)) + return 0; + + val = atol(v.data()); + + return 1; +} Added: trunk/filesystems/ftpfs/sitetopdir.cc ============================================================================== --- trunk/filesystems/ftpfs/sitetopdir.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/sitetopdir.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,22 @@ +// -*- C++ -*- + +// Top directory of an FTP site + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#pragma implementation + +#include "sitetopdir.h" +#include "ftpconn.h" +#include "ConfFile.h" +#include "Path.h" +#include "conninfo.h" + +sitetopdir::sitetopdir(ftpfs &fs, string dname, dir *up) + :ftpdir(fs, dname, up, NULL, ".ftpfs_site") +{ + link(".ftpfs_info", new conninfo(fs, conn)); +} + Added: trunk/filesystems/ftpfs/ConfFile.h ============================================================================== --- trunk/filesystems/ftpfs/ConfFile.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/ConfFile.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,52 @@ +// -*- C++ -*- + +// Configuration file handling +// This class handles reading and writing config files +// with simple name-value pairs. + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#ifndef _CONFFILE_H_ +#define _CONFFILE_H_ + +#pragma interface + +#include +#include +#include "Path.h" + +class ConfFile +{ + int changed; + + void parse(); + void unparse(); + + Path name; + + struct list_t + { + list_t *next; + string name; + string val; + } *list; + + list_t *find(const string &name) const; + +public: + ConfFile(const Path &); + ~ConfFile(); + + void parseline(const string &name); + void unparsestr(string &) const; + + void set(const string &name, const string &val); + int get(const string &name, string &val) const; + + void setnum(const string &name, long); + int getnum(const string &name, long &) const; +}; + +#endif /* _CONFFILE_H_ */ Added: trunk/filesystems/ftpfs/ftpfile.cc ============================================================================== --- trunk/filesystems/ftpfs/ftpfile.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/ftpfile.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,357 @@ +// -*- C++ -*- + +// Deal with keeping files up to date and transferring them. +// Also copes with ordinary FS reads of files. The complexity +// is in allowing a file to be read as it's being updated without +// getting problems. + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#pragma implementation + +#include "ftpfile.h" +#include "ftpconn.h" +#include "ftpdir.h" +#include "ftpfs.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +ftpfile::ftpfile(ftpfs &fs, const string &name, ftpdir *dir, ftpconn *conn) + : dir(dir), ino(fs), conn(conn), name(name) +{ + fd = -1; + updating = 0; + wlist = NULL; + mode = S_IFREG | 0444; + conn->incref(); + upd_thread = NULL; + + open(); + if (fd != -1) + { + struct stat st; + + if (fstat(fd, &st) == 0) + { + size = st.st_size; + mtime = st.st_mtime; + } + close(); + } +} + +ftpfile::~ftpfile() +{ + if (upd_thread != NULL) + delete upd_thread; + close(); + conn->decref(); +} + +struct waiting +{ + off_t off; + Semaphore sem; + int err; + waiting *next, *prev; + + waiting(off_t, waiting *next); +}; + +waiting * +ftpfile::addwlist(off_t off) +{ + waiting *w = new waiting(off, wlist); + + wlist = w; + + return w; +} + +void +ftpfile::delwlist(waiting *w) +{ + if (w->next) + w->next->prev = w->prev; + if (w->prev) + w->prev->next = w->next; + else + wlist = w->next; +} + +waiting::waiting(off_t off, waiting *n) + :off(off), sem(0), next(n) +{ + err = 0; + next = prev = NULL; +} + +// This class is passed as a callback to the ftpconn method for +// getting a file +class docopy: public ftpxfer +{ + ftpfile &ftp; + off_t last_off; + int err; + +public: + docopy(string path, int cfd, ftpfile &, ftpconn *); + ~docopy(); + + void notify(int); + void error(int e) { err = e; } + // Things for passing through the thread args + int cfd; + string path; + ftpconn *conn; +}; + +static void +copy_cache(int, char **, void *v) +{ + cout << "update thread starting\n"; + docopy *dc = (docopy *)v; + dc->conn->getfile(dc->path, dc->cfd, dc); + delete dc; + cout << "update thread finishing\n"; + suicide(); + abort(); +} + +docopy::docopy(string path, int cfd, ftpfile &f, ftpconn *conn) + : ftp(f), cfd(cfd), path(path), conn(conn) +{ + assert(ftp.updating == 0); + ftp.updating = 1; + last_off = 0; + err = 0; +} + +docopy::~docopy() +{ + assert(ftp.updating == 1); + // Wake up everything outstanding + for(waiting *w = ftp.wlist; w != NULL; w = w->next) + { + ftp.delwlist(w); + w->err = err; + w->sem.signal(); + delete w; + } + + string nm = ftp.dir->path() + "/" + ftp.name; + struct utimbuf ut; + ut.actime = ftp.atime; + ut.modtime = ftp.mtime; + utime(nm.data(), &ut); + + ftp.updating = 0; + ftp.close(); +} + +void +docopy::notify(int infd) +{ + off_t size = lseek(cfd, 0, SEEK_CUR); + + // Force thread change if it wouldn't otherwise. + // If we're doing this we re-queue it with a low select + // dispatch priority. + // If it's yielding a lot because of blocking reads anyhow, + // it means other threads get good response + + if (size >= (last_off + 8*1024)) + { + class copyyield: public DispatchFD + { + Semaphore sem; + public: + copyyield(): sem(0) {} + + int dispatch(int,int) { sem.signal(); return 0; } + void wait() { sem.wait(); } + }; + + copyyield *cy = new copyyield(); + ftp.filesys.comm()->addDispatch(infd, cy, DISP_R, 0); + cy->wait(); + last_off = size; + } + for(waiting *w = ftp.wlist; w != NULL; w = w->next) + if (w->off < size) + { + cout << "passing offset " << w->off << + " at " << size << "\n"; + ftp.delwlist(w); + w->sem.signal(); + delete w; + } + ftp.size = size; +} + +void +ftpfile::decref() +{ + if (nlink-- == 0) + { + string cn = dir->path() + "/" + name; + ::unlink(cn.data()); + delete this; + } +} + +int +ftpfile::is_uptodate() const +{ + struct stat st; + string cn = dir->path() + "/" + name; + + if (stat((const char *)cn.data(), &st) == 0 && + size == st.st_size && + size != 0) + return 1; + return 0; +} + +// Start updating file if needed +// This starts an update thread. Things wanting to read the file should +// use ftpfile::read, which checks to see if the cache file is being updated. +// If so, it puts an entry on the waiting list. If the update thread passes +// a point being waited for by a reading thread, it is woken. +int +ftpfile::updatefile() +{ + if (updating) + return 0; + + if (is_uptodate()) + return 0; + + string cn = dir->path() + "/" + name; + string fn = dir->ftppath() + "/" + name; + + ::unlink(cn.data()); + close(); + if (open(1, 0444)) + return -1; + + // Start cache update thread + docopy *dc = new docopy(fn, fd, *this, conn); + new LWP(UPD_TPRI, copy_cache, 16*1024, 0, NULL, dc); + + return 0; +} + +/* Open the cache file */ +int +ftpfile::open(int create, int mode) +{ + string cp; + + close(); + cp = dir->path() + "/" + name; + fd = ::open(cp.data(), create ? O_RDWR|O_TRUNC|O_CREAT|O_APPEND : O_RDONLY, mode); +// cout << "ftpfile::open(" << create << ", " << mode << ") opened " << cp << " fd="<< fd << '\n'; + + return fd == -1 ? -1 : 0; +} + +void +ftpfile::close() +{ + ::close(fd); + fd = -1; +} + +// Read from the file +// If the file is being updated from the ftp site, we wait until +// the update thread says some data we want has arrived. Otherwise, +// just go direct to the file +int +ftpfile::read(unsigned char *buf, size_t sz, off_t off) +{ + struct stat st; + + if (fd == -1 && open() == -1) + return -1; + + int cfd = dup(fd); + if (cfd == -1) + ::perror("dup failed"); + if (fstat(cfd, &st) == -1) + { + ::perror("fstat failed"); + return -1; + } + + if (updating && off >= st.st_size) + { + waiting *w = addwlist(off); + w->sem.wait(); + if (w->err != 0) + { + cout << "read failed in wait: " << strerror(w->err) + << '\n'; + ftruncate(cfd, 0); + close(); + errno = w->err; + return -1; + } + } + + lseek(cfd, off, SEEK_SET); + int ret = ::read(cfd, buf, sz); + if (ret == -1) + perror("read failed"); + ::close(cfd); + + return ret; +} + +int +ftpfile::do_iput(const up_preamble &, upp_repl &, + const upp_iput_s &arg) +{ + if (!updating) + close(); + return 0; +} + +int +ftpfile::do_read(const up_preamble &, upp_repl &, + const upp_read_s &arg, upp_read_r &ret) +{ + updatefile(); + + unsigned char buf[arg.size]; + int rd = read(buf, arg.size, arg.off); + + if (rd == -1) + return errno; + + ret.data.alloc(rd); + ret.data.nelem = rd; + memcpy(ret.data.elems, buf, rd); + + return 0; +} + +void +ftpfile::setstats(size_t sz, time_t time) +{ + size = sz; + mtime = time; +} Added: trunk/filesystems/ftpfs/ftpdir.h ============================================================================== --- trunk/filesystems/ftpfs/ftpdir.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/ftpfs/ftpdir.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,68 @@ +// -*- C++ -*- + +// (C) Copyright 1994 Jeremy Fitzhardinge +// This code is distributed under the terms of the +// GNU General Public Licence. See COPYING for more details. + +#ifndef _FTPDIR_H_ +#define _FTPDIR_H_ + +#pragma interface + +#include "dir.h" + +#include + +class ftpconn; + +class ftpdir: public dir +{ + void construct(); + void init(); + + void cleanup(); + + // Parent dir in ftp site + ftpdir *ftpup; + + // Parameters about this dir + class ConfFile *conf; + time_t last_upd; + time_t last_failure; + + // Inode creation + Inode *newinode(dir *, const struct stat *, const string &); + + // Resync with FTP site + int updatedir(int force = 0); + int init_done; + + // Config parameters + void getparams(); + void setparams(); + + // Operations + int do_readdir(const up_preamble &, upp_repl &, + const upp_readdir_s &, upp_readdir_r &); + int do_multireaddir(const up_preamble &, upp_repl &, + const upp_multireaddir_s &, upp_multireaddir_r &); + int do_lookup(const up_preamble &pre, upp_repl &rep, + const upp_lookup_s &arg, upp_lookup_r &ret); + int do_create(const up_preamble &, upp_repl &, + const upp_create_s &, upp_create_r &); + +protected: + // FTP connection + ftpconn *conn; + +public: + ftpdir(ftpfs &fs, const string &name, dir *up, + ftpdir *ftpup, ftpconn *conn); + ftpdir(ftpfs &fs, const string &name, dir *up, ftpdir *ftpup, + const string &cfname); + ~ftpdir(); + + string ftppath() const; +}; + +#endif /* _FTPDIR_H_ */ Added: trunk/filesystems/intfs/intfsIno.h ============================================================================== --- trunk/filesystems/intfs/intfsIno.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/intfs/intfsIno.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,40 @@ +// -*- C++ -*- + +#ifndef _INTFSINO_H_ +#define _INTFSINO_H_ + +#pragma interface + +#include +#include + +class intfs; +class ifsDirIno; + +class ifsIno: public SimpleInode +{ +protected: + intfs &filesys; + + const string name; + string link; + ifsDirIno *dir; + + int do_readlink(const up_preamble &, upp_repl &, + const upp_readlink_s &, upp_readlink_r &); + int do_followlink(const up_preamble &, upp_repl &, + const upp_followlink_s &, upp_followlink_r &); + int do_write(const up_preamble &, upp_repl &, + const upp_write_s &, upp_write_r &); + + void update(); + + int open(int mode); + +public: + string path(); + ifsIno(intfs &fs, Handle hand, ifsDirIno *, string name, string link); + ~ifsIno(); +}; + +#endif /* _INTFSINO_H_ */ Added: trunk/filesystems/intfs/intfsFifoIno.cc ============================================================================== --- trunk/filesystems/intfs/intfsFifoIno.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/intfs/intfsFifoIno.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,165 @@ +// -*- C++ -*- + +// An inode with a command behind it +// These are transient, and only exist long enough to be opened. +// They go away once they have been put, never to be seen again. +// The contents are only generated if they are actually read. + +#pragma implementation + +#include "intfsFifoIno.h" +#include "intfsFifoDir.h" +#include "intfsDirIno.h" +#include "intfs.h" + +#include "dbg.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +ifsFifoIno::ifsFifoIno(intfs &fs, string command, ifsDirIno *dir) + : SimpleInode(fs, fs.genhand()), + command(command), dir(dir), filesys(fs) +{ + atime = ctime = mtime = time(0); + mode = S_IFIFO | 0444; + pid = -1; + readfd = -1; + + name = filesys.getfifod()->create(this); + named = 1; + + DB(printf("ifsFifoIno::ifsFifoIno, linked into fifod name=%s, command=%s\n", + (const char *)name, (const char *)command)); +} + +ifsFifoIno::~ifsFifoIno() +{ + unname(); + ::close(readfd); + readfd = -1; +// if (pid > 0) +// ::kill(pid, SIGTERM); +// pid = -1; +} + +void +ifsFifoIno::unname() +{ + if (named) + filesys.getfifod()->unlink(name); + named = 0; +} + +int +ifsFifoIno::do_open(const up_preamble &, upp_repl &, + const upp_open_s &arg, upp_open_r &ret) +{ + LOG("ifsFifoIno::do_open"); + unname(); + + uid = arg.cred.uid; + euid = arg.cred.euid; + gid = arg.cred.gid; + egid = arg.cred.egid; + + return 0; +} + +int +ifsFifoIno::do_iput(const up_preamble &, upp_repl &, + const upp_iput_s &) +{ + LOG("ifsFifoIno::do_iput"); + + delete this; + return 0; +} + +int +ifsFifoIno::start() +{ + int pfd[2]; + + if (pipe(pfd) == -1) + return errno; + + signal(SIGCHLD, SIG_IGN); + + switch(pid = fork()) + { + case -1: + return errno; + case 0: + close(0); + close(1); + close(2); + close(pfd[0]); + filesys.comm()->CloseFDs(1); + + open("/dev/null", O_RDWR); + dup(pfd[1]); + dup(pfd[1]); + close(pfd[1]); + + int dfd = dir->dupfd(); + fchdir(dfd); + close(dfd); + + setreuid(uid, euid); + setregid(gid, egid); + + signal(SIGTERM, SIG_DFL); + + execlp("/bin/sh", "/bin/sh", "-c", (const char *)command, 0); + fprintf(stderr, "exec of /bin/sh -c %s failed: %s\n", + (const char *)command, strerror(errno)); + exit(1); + } + + close(pfd[1]); + readfd = pfd[0]; + + return 0; +} + +int +ifsFifoIno::do_read(const up_preamble &, upp_repl &, + const upp_read_s &arg, upp_read_r &data) +{ + int ret; + + LOG("ifsFifoIno::do_read"); + + if (pid == -1 && (ret = start()) != 0) + return ret; + + int dpid = filesys.comm()->DeferRepl(); + + if (dpid != -1 && dpid != 0) + return -1; + + char buf[1024]; + off_t sz = arg.size > sizeof(buf) ? sizeof(buf) : arg.size; + + while((ret = read(readfd, buf, sz)) == -1) + if (errno != EINTR) + return errno; + + if (ret > 0) + { + data.data.alloc(ret); + memcpy(data.data.elems, buf, ret); + } + data.data.nelem = ret; + + return 0; +} Added: trunk/filesystems/intfs/intfsFifoIno.h ============================================================================== --- trunk/filesystems/intfs/intfsFifoIno.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/intfs/intfsFifoIno.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,48 @@ +// -*- C++ -*- + +#ifndef _INTFSFIFOINO_H_ +#define _INTFSFIFOINO_H_ + +#pragma interface + +#include +#include + +#include + +class intfs; +class ifsDirIno; + +class ifsFifoIno: public SimpleInode +{ + string command; + ifsDirIno *dir; + string name; + + pid_t pid; + int readfd; + int named; + + int start(); + void unname(); + + uid_t uid, euid; + gid_t gid, egid; + +protected: + intfs &filesys; + + int do_open(const up_preamble &, upp_repl &, + const upp_open_s &, upp_open_r &); + int do_iput(const up_preamble &, upp_repl &, + const upp_iput_s &); + int do_read(const up_preamble &, upp_repl &, + const upp_read_s &, upp_read_r &); +public: + ifsFifoIno(intfs &, string command, ifsDirIno *dir); + ~ifsFifoIno(); + + string getname() const { return name; } +}; + +#endif /* _INTFSFIFOINO_H_ */ Added: trunk/filesystems/intfs/intfsLinkIno.cc ============================================================================== --- trunk/filesystems/intfs/intfsLinkIno.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/intfs/intfsLinkIno.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,46 @@ +// -*- C++ -*- + +// Inode for symbolic links in intfs filesystem + +#pragma implementation + +#include "intfsLinkIno.h" +#include "intfsFifoIno.h" +#include "intfsDirIno.h" + +#include "dbg.h" + +ifsLinkIno::ifsLinkIno(intfs &fs, Handle hand, ifsDirIno *dir, string name, string link) + : ifsIno(fs, hand, dir, name, link) +{ +} + +ifsLinkIno::~ifsLinkIno() +{ +} + +int +ifsLinkIno::do_followlink(const up_preamble &pre, upp_repl &rep, + const upp_followlink_s &arg, upp_followlink_r &ret) +{ + LOG("ifsLinkIno::do_followlink"); + + if (link(NULL,2) != "#!") + return ifsIno::do_followlink(pre, rep, arg, ret); + + ifsFifoIno *ino = new ifsFifoIno(filesys, link.after(1), dir); + + string p; + + cat(dir->toppath(), "/.fifo/", ino->getname(), p); + int len = p.length(); + + DB(printf("ifsLinkIno::do_followlink returning link to %s\n", + (const char *)p.data())); + + ret.path.alloc(len); + ret.path.nelem = len; + memcpy(ret.path.elems, (const char *)p.data(), len); + + return 0; +} Added: trunk/filesystems/intfs/README ============================================================================== --- trunk/filesystems/intfs/README 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/intfs/README 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,85 @@ +intfs - filesystem for intensional files. + +This filesystem allows file contents to be expressed in terms of +programs to generate the contents. It allows simple user space +filesystems to be constructed without the effort of having +to write a full userfs filesystem. + +To mount, use + muserfs intfs + +The is a directory tree which is to be mirrored. The intfs +filesystem will appear as a tree of directories in the same shape as +the base directory, except containing symlinks to the original files +rather than images of them. Symlinks in the base directory tree appear +unchanged in the mirrored tree (that is, the link contents point to the +same place). + +Normally a symlink contains a pathname to another file or symlink, +relative to the directory containing the symlink. In this case, if +the symlink points to a path starting with "#!", the rest of the path +is treated as a script for /bin/sh. When the file is read, the +command is actually executed, and the stdout and stderr is read as the +file contents. If you do a fstat on the open file descriptor, it +appears to be a pipe or fifo file. + +For example (commands typed in a mounted intfs filesystem): +$ ls -l +lrwxrwxrwx 1 jeremy users 16 May 13 19:58 file.gz -> /usr/tmp/file.gz +lrwxrwxrwx 1 jeremy users 14 May 13 19:58 file -> #!zcat file.gz +$ cat file +This is a compressed file + +So, as you see, file contents can be generated on demand. + +HOW IT WORKS + +This works by having different code for the up_readlink and +up_followlink operations. Normally, reading the link gives you the +literal path of the file which is being referred to. However, it is +possible to have a symlink which goes to a different place when +followed than would appear from reading it. + +A userfs filesystem still has to return a pathname for a file as a +result of a up_followlink operation, so intfs has a special directory +".fifo" in the mount directory which contains transient FIFO files. +When a normal link is followed, intfs just returns the link contents +as read by readlink. For intensional links (those starting with +'#!'), it returns a relative path to a fifo file in .fifo. The fifo +file only exists in the directory for a very short time: it is removed +when that path is opened or when the inode is "iput", which ever comes +first. Therefore, if the link is being followed for opening, it can +be opened once before the name disappears. If the link is followed +for something else, like a stat, it will be "iput" immediately, +without ever being read. + +There is a race-condition: if an intensional file is being stat'd, +then it does appear in .fifo, so something else could open it and +read it. + +If intfs can (if its running as root), it tries to execute the command +with the permissions of the program reading the file. It gets these +permissions from the credentials passed when the file is opened. +Because the filename is removed from .fifos as soon as it is opened, +nothing else can open the file and get the output of the program +executing for another user. The program is run with the same +environment as intfs, with a current directory in the corresponding +place in the base filesystem. + +This is an experimental filesystem, and so has some problems. In +paritcular, it doesn't keep track of the underlying filesystem changes +very well, so its best to do all the file rename/deletion/ creation +through the intfs filesystem. + +THe basic idea for intfs came from Paul Eggert and D. Stott Parker's +paper in the 1992 Usenix File Systems Workshop Proceedings, which +presented IFS0, a filesystem having properties similar to intfs, but +implemented in SunOS shared libraries. They followed this work up +with the IFS1 filesystem, presented in the Usenix Winter 1993 +Technical Conference proceedings. The library approach is probably +more suited for this filesystem than using userfs, but I had userfs +and haven't found out how to make Linux shared libraries, so here it +is. + + Jeremy Fitzhardinge + jeremy@sw.oz.au Added: trunk/filesystems/intfs/intfsLinkIno.h ============================================================================== --- trunk/filesystems/intfs/intfsLinkIno.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/intfs/intfsLinkIno.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,23 @@ +// -*- C++ -*- + +#ifndef _INTFSLINKINO_H_ +#define _INTFSLINKINO_H_ + +#pragma interface + +#include +#include "intfsIno.h" + +class ifsLinkIno: public ifsIno +{ +protected: + int do_followlink(const up_preamble &, upp_repl &, + const upp_followlink_s &, upp_followlink_r &); +public: + ifsLinkIno(intfs &fs, Handle hand, ifsDirIno *, + string name, string link); + ~ifsLinkIno(); + +}; + +#endif /* _INTFSLINKINO_H_ */ Added: trunk/filesystems/intfs/pushd.cc ============================================================================== --- trunk/filesystems/intfs/pushd.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/intfs/pushd.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,31 @@ +// -*- C++ -*- + +// PushD/PopD operations + +#include "pushd.h" + +#include +#include +#include +#include + +pushd::pushd(int dir) +{ + int fd = open(".", O_RDONLY); + + if (fd == -1 || fchdir(dir) == -1) + { + fprintf(stderr, "pushd::pushd() open or fchdir failed"); + return; + } + + old = fd; +} + +pushd::~pushd() +{ + fchdir(old); + close(old); +} + + Added: trunk/filesystems/intfs/intfs.cc ============================================================================== --- trunk/filesystems/intfs/intfs.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/intfs/intfs.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,130 @@ +// -*- C++ -*- + +// Intensive filesystem - the opposite of an extensive filesystem. + +// The basic idea is that rather than having file which literally +// describe their contents, we have files which can describe how their +// contents are built. + +// This is done by having symbolic links which contain strings of +// shell commands rather than literal file names. Such links are +// identified by having the 1st 2 characters "#!". + +// The filesystem is a layer over another filesystem to provide this +// functionality. For each normal file in the base filesystem there +// is a symbolic link in the intfs filesystem. Symbolic links in +// the base filesystem appear literally in the intfs. Normal +// symlinks are treated normally, but ones with command syntax are +// interpreted to generate the contents of the file. In such cases +// the readlink operation returns the command, but followlink returns +// the name of the temp file or named pipe with the actual contents +// of the file. + +#pragma implementation + +#include +#include +#include + +#include "intfs.h" +#include "intfsDirIno.h" +#include "intfsFifoDir.h" + +#include "dbg.h" + +int +intfs::Enquire(up_ops op) +{ + switch(op) + { + case up_mount: + case up_iread: + case up_readdir: + case up_multireaddir: + case up_lookup: + case up_readlink: + case up_followlink: + case up_unlink: + case up_rename: + case up_create: + case up_symlink: + case up_iput: +// case up_iwrite: + case up_read: + case up_write: + case up_open: + case up_close: + return 0; + + default: + return DeferFilesys::Enquire(op); + } +} + +intfs::intfs(const char *mpoint, string base) + : DeferFilesys(mpoint), base(base) +{ + inocnt = 2; + root = new ifsDirIno(*this, genhand(), NULL, base); + fifod = new ifsFifoDir(*this, genhand(), root); + root->link(".fifo", fifod); +} + +intfs::~intfs() +{ +} + +int +intfs::do_mount(const up_preamble &, upp_repl &, upp_mount_r &ret) +{ + ret.root.handle = root->gethandle(); + return 0; +} + +int +main(int argc, char **argv) +{ + GetOpt getopt(argc, argv, "i:o:m:"); + int optch, err = 0; + int infd, outfd; + const char *mpoint = ""; + const char *base; + + infd = outfd = -1; + while((optch = getopt()) != EOF) + switch(optch) + { + case 'i': + infd = atoi(getopt.optarg); + break; + case 'o': + outfd = atoi(getopt.optarg); + break; + case 'm': + mpoint = getopt.optarg; + break; + default: + err++; + } + + if (err || infd == -1 || outfd == -1 || getopt.optind == argc) + { + fprintf(stderr, "Usage: %s -i infd -o outfd -m mpoint basedir\n", + argv[0]); + exit(1); + } + + base = argv[getopt.optind]; + +#if 0 && DEBUG + printf("pid=%d, return to cont\n", getpid()); + getchar(); +#endif + intfs ifs(mpoint, base); + DeferComm comm(ifs, outfd, infd); + + if (comm.Run() == -1) + fprintf(stderr, "%s: Comm.Run() failed!\n", argv[0]); + + return 0; +} Added: trunk/filesystems/intfs/intfs.h ============================================================================== --- trunk/filesystems/intfs/intfs.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/intfs/intfs.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,34 @@ +// -*- C++ -*- + +#ifndef _INTFS_H_ +#define _INTFS_H_ + +#pragma interface + +#include +#include + +class ifsDirIno; +class ifsFifoDir; + +class intfs : public DeferFilesys +{ + const string base; + ifsDirIno *root; + ifsFifoDir *fifod; + + Handle inocnt; + +protected: + int Enquire(up_ops); + + int do_mount(const up_preamble &, upp_repl &, upp_mount_r &); +public: + Handle genhand() { return inocnt++; } + intfs(const char *mpoint, string base); + ~intfs(); + + ifsFifoDir *getfifod() const { return fifod; } +}; + +#endif /* _INTFS_H_ */ Added: trunk/filesystems/intfs/pushd.h ============================================================================== --- trunk/filesystems/intfs/pushd.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/intfs/pushd.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,15 @@ +// -*- C++ -*- + +#ifndef _PUSHD_H_ +#define _PUSHD_H_ + +class pushd +{ + int old; + +public: + pushd(int fd); + ~pushd(); +}; + +#endif /* _PUSHD_H_ */ Added: trunk/filesystems/intfs/intfsFifoDir.cc ============================================================================== --- trunk/filesystems/intfs/intfsFifoDir.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/intfs/intfsFifoDir.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,65 @@ +// -*- C++ -*- + +#pragma implementation + +#include "intfs.h" +#include "intfsFifoDir.h" + +#include +#include +#include +#include +#include + +#include "dbg.h" + +ifsFifoDir::ifsFifoDir(intfs &fs, Handle hand, DirInode *parent) + :DirInode(fs, hand, parent, 30) +{ + count = 0; + + uid = 0; + gid = 0; + mode = S_IFDIR | S_ISVTX | 0555; + mtime = ctime = time(0); +} + +ifsFifoDir::~ifsFifoDir() +{ +} + +string +ifsFifoDir::create(Inode *ino) +{ + char buf[20]; + + sprintf(buf, "C%d", count++); + + string n(buf); + + link(n, ino); + + DB(printf("ifsFifoDir::create linked inode to %s\n", (const char *)n)); + return n; +} + +int +ifsFifoDir::do_unlink(const up_preamble &, upp_repl &, + const upp_unlink_s &) +{ + return EPERM; +} + +int +ifsFifoDir::do_link(const up_preamble &, upp_repl &, + const upp_link_s &) +{ + return EPERM; +} + +int +ifsFifoDir::do_rename(const up_preamble &, upp_repl &, + const upp_rename_s &) +{ + return EPERM; +} Added: trunk/filesystems/intfs/intfsDirIno.cc ============================================================================== --- trunk/filesystems/intfs/intfsDirIno.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/intfs/intfsDirIno.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,318 @@ +// -*- C++ -*- + +// Cope with directories in an intfs filesystem + +#pragma implementation + +#include "intfsDirIno.h" +#include "intfsLinkIno.h" +#include "intfsIno.h" +#include "intfs.h" + +#include "pushd.h" + +#include +#include +#include +#include +#include "readdir.h" + +#include "dbg.h" + +ifsDirIno::ifsDirIno(intfs &fs, Handle hand, + ifsDirIno *parent, string dirname) + :DirInode(fs, hand, parent == NULL ? this : parent, 30), + name(dirname), dotdot(parent == NULL ? this : parent), + filesys(fs) +{ + fd = -1; + mtime = atime = ctime = 0; + updating = 0; + + open(); + struct stat st; + + if (fstat(fd, &st) != -1) + { + mode = st.st_mode; + uid = st.st_uid; + gid = st.st_gid; + } + close(); +} + +ifsDirIno::~ifsDirIno() +{ + close(); +} + +string ifsDirIno::toppath() +{ + ifsDirIno *p; + string ret = "."; + + for(p = this; p != NULL && p->dotdot != p; p = p->dotdot) + { + string n; + cat("../", ret, n); + ret = n; + } + + return ret; +} + +string ifsDirIno::path() +{ + string p = name; + + if (dotdot && dotdot != this) + cat(dotdot->path(), "/", p, p); + + return p; +} + +void ifsDirIno::update() +{ + struct dirent de; + int ret; + + if (updating) + return; + updating = 1; + + if ((ret = open())) + { + DB(fprintf(stderr, "ifsDirIno::update open failed: %s\n", strerror(ret))); + updating = 0; + return; + } + + struct stat st; + + if (fstat(fd, &st) == -1) + { + DB(perror("ifsDirIno::update stat failed")); + close(); + updating = 0; + return; + } + + atime = st.st_atime; + ctime = st.st_ctime; + uid = st.st_uid; + gid = st.st_gid; + mode = st.st_mode; + + if (st.st_mtime == mtime) + { + close(); + updating = 0; + return; + } + + mtime = st.st_mtime; + + pushd here(fd); + + while((ret = readdir(fd, &de, 1)) > 0) + { + if (lstat(de.d_name, &st) == -1) + continue; + + string entname(de.d_name, de.d_reclen); + + DirEntry *dent = lookup(entname); + + if (dent == NULL) + { + Inode *ino; + + if (S_ISLNK(st.st_mode)) + { + char buf[256]; + int len; + + DB(printf("%s is a link\n", + (const char *)entname.data())); + if ((len = readlink((const char *)entname.data(), + buf, sizeof(buf))) == -1) + continue; + ino = new ifsLinkIno(filesys, + filesys.genhand(), + this, entname, + string(buf, len)); + } + else if (S_ISDIR(st.st_mode)) + { + DB(printf("%s is a directory\n", + (const char *)entname.data())); + ino = new ifsDirIno(filesys, filesys.genhand(), + this, entname); + } + else + { + string str; +// DB(printf("%s is a file\n", +// (const char *)entname)); + cat(path(), "/", entname, str); + ino = new ifsIno(filesys, + filesys.genhand(), + this, entname, str); + } + link(entname, ino); + } + else + ((ifsDirIno *)dent->geti())->update(); + } + if (ret != 0) + DB(perror("ifsDirIno::update, readdir failed")); + updating = 0; + close(); +} + +int +ifsDirIno::open() +{ + string p = path(); + + fd = ::open(p.data(), O_RDONLY); + int err = errno; + + return (fd == -1) ? err : 0; +} + +void +ifsDirIno::close() +{ + ::close(fd); + fd = -1; +} + +int +ifsDirIno::dupfd() +{ + int fl = 0; + + if (fd == -1) + { + fl = 1; + open(); + } + + int ret = dup(fd); + + if (fl) + close(); + return ret; +} + +int +ifsDirIno::do_unlink(const up_preamble &, upp_repl &, + const upp_unlink_s &arg) +{ + LOG("ifsDirIno::do_unlink"); + int ret; + + if (ret = open()) + return ret; + + pushd here(fd); + close(); + + string file((const char *)arg.name.elems, (int)arg.name.nelem); + DirEntry *de = lookup(file); + + if (S_ISDIR(((ifsDirIno *)de->geti())->mode)) + { + if (::rmdir((const char *)file.data()) == -1) + ret = errno; + } + else + { + if (::unlink((const char *)file.data()) == -1) + ret = errno; + } + + if (ret == 0 || ret == ENOENT) + ret = unlink(string((const char *)arg.name.elems, + (int)arg.name.nelem)); + return ret; +} + +int ifsDirIno::do_symlink(const up_preamble &, upp_repl &, const upp_symlink_s &arg) +{ + open(); + pushd here(fd); + string name((const char *)arg.name.elems, (int)arg.name.nelem); + string link((const char *)arg.symname.elems, (int)arg.symname.nelem); + + if (::symlink((const char *)link.data(), (const char *)name.data()) == -1) + return errno; + return 0; +} + +int ifsDirIno::do_create(const up_preamble &, upp_repl &, + const upp_create_s &arg, upp_create_r &ret) +{ + open(); + pushd here(fd); + close(); + string name((const char *)arg.name.elems, (int)arg.name.nelem); + Inode *ino; + string str; + Handle hand = filesys.genhand(); + + cat(path(), "/", name, str); + + if (S_ISREG(arg.mode)) + { + int fd = ::open((const char *)name.data(), + O_TRUNC|O_CREAT|O_RDONLY, arg.mode); + if (fd == -1) + return errno; + ::close(fd); + ino = new ifsIno(filesys, hand, this, name, str); + } + else if (S_ISDIR(arg.mode)) + { + if (::mkdir((const char *)name.data(), arg.mode) == -1) + return errno; + ino = new ifsDirIno(filesys, hand, this, name); + } + else + { + if (::mknod((const char *)name.data(), arg.mode, arg.rdev) == -1) + return errno; + ino = new ifsIno(filesys, hand, this, name, str); + } + + link(name, ino); + + ret.file.handle = ino->gethandle(); + return 0; +} + +int +ifsDirIno::do_rename(const up_preamble &pre, upp_repl &rep, + const upp_rename_s &arg) +{ + open(); + pushd here(fd); + close(); + + string oname((const char *)arg.oname.elems, (int)arg.oname.nelem); + string nname((const char *)arg.nname.elems, (int)arg.nname.nelem); + ifsDirIno *ndir = (ifsDirIno *)findino(arg.ndir.handle); + string npath; + + cat(ndir->path(), "/", nname, npath); + + DB(printf("renaming from %s to %s\n", + (const char *)oname.data(), (const char *)npath.data())); + + if (::rename((const char *)oname.data(), (const char *)npath.data()) == -1) + return errno; + + return DirInode::do_rename(pre, rep, arg); +} + Added: trunk/filesystems/intfs/intfsFifoDir.h ============================================================================== --- trunk/filesystems/intfs/intfsFifoDir.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/intfs/intfsFifoDir.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,32 @@ +// -*- C++ -*- + +#ifndef _INTFSFIFODIR_H_ +#define _INTFSFIFODIR_H_ + +#pragma interface + +#include +#include + +class intfs; + +class ifsFifoDir: public DirInode +{ + int count; + +protected: + int do_rename(const up_preamble &, upp_repl &, + const upp_rename_s &); + int do_unlink(const up_preamble &, upp_repl &, + const upp_unlink_s &arg); + int do_link(const up_preamble &, upp_repl &, + const upp_link_s &); + +public: + ifsFifoDir(intfs &, Handle, DirInode *parent); + ~ifsFifoDir(); + + string create(Inode *); +}; + +#endif /* _INTFSFIFODIR_H_ */ Added: trunk/filesystems/intfs/intfsIno.cc ============================================================================== --- trunk/filesystems/intfs/intfsIno.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/intfs/intfsIno.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,114 @@ +// -*- C++ -*- + +// General base class for non-directory inodes in intfs + +#pragma implementation + +#include "intfsIno.h" +#include "intfs.h" +#include "intfsDirIno.h" + +#include "dbg.h" + +#include +#include +#include +#include + +ifsIno::ifsIno(intfs &fs, Handle hand, ifsDirIno *dir, string name, string link) + : SimpleInode(fs, hand), + filesys(fs), name(name), link(link), dir(dir) +{ + size = link.length(); + mode = S_IFLNK|0777; +} + +ifsIno::~ifsIno() +{ +} + +int ifsIno::do_readlink(const up_preamble &, upp_repl &, + const upp_readlink_s &, upp_readlink_r &ret) +{ + int len; + ret.name.alloc(len = link.length()); + memcpy(ret.name.elems, (const char *)link.data(), len); + ret.name.nelem = len; + + return 0; +} + +int ifsIno::do_followlink(const up_preamble &, upp_repl &, + const upp_followlink_s &, upp_followlink_r &ret) +{ + int len; + ret.path.alloc(len = link.length()); + memcpy(ret.path.elems, (const char *)link.data(), len); + ret.path.nelem = len; + + return 0; +} + +int ifsIno::do_write(const up_preamble &, upp_repl &, + const upp_write_s &arg, upp_write_r &ret) +{ + LOG("ifsIno::do_write"); + int fd = open(O_WRONLY); + int r; + + if (fd < 0) + return -fd; + if (::lseek(fd, arg.off, SEEK_SET) == -1) + { + int er = errno; + ::close(fd); + return er; + } + if ((r = ::write(fd, arg.data.elems, arg.data.nelem)) == -1) + { + int er = errno; + ::close(fd); + return er; + } + ret.wrote = r; + ::close(fd); + return 0; +} + +string ifsIno::path() +{ + string n; + + cat(dir->path(), "/", name, n); + + return n; +} + +void ifsIno::update() +{ + struct stat st; + string p = path(); + + if (::lstat((const char *)p.data(), &st) == -1) + { + DB(printf("ifsIno::update stat of %s failed: %s\n", + (const char *)p.data(), strerror(errno))); + return; + } + atime = st.st_atime; + ctime = st.st_ctime; + mtime = st.st_mtime; + uid = st.st_uid; + gid = st.st_gid; +} + +int ifsIno::open(int mode) +{ + string p; + int fd; + + cat(dir->path(), "/", name, p); + if ((fd = ::open((const char *)p.data(), mode)) == -1) + return -errno; + return fd; +} Added: trunk/filesystems/intfs/Makefile ============================================================================== --- trunk/filesystems/intfs/Makefile 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/intfs/Makefile 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,24 @@ +TOP=../.. +include $(TOP)/rules +LIBDIR=$(TOP)/lib +KERNDIR=$(TOP)/kernel + +CXXFLAGS = -DDEBUG -I$(LIBDIR) -I$(KERNDIR) -I$(TOP)/genser -I/usr/include/g++ +LDFLAGS = $(PROF) -L$(LIBDIR) -g + +OBJ = intfs.o intfsIno.o intfsDirIno.o intfsLinkIno.o intfsFifoDir.o \ + intfsFifoIno.o readdir.o pushd.o + +PROGS = intfs + +all:: $(PROGS) + +intfs: $(OBJ) $(DEPLIBUSERFS) + $(CXX) $(LDFLAGS) -o intfs $(OBJ) $(LIBUSERFS) + +clean:: dummy + rm -f *.o *~ core $(PROGS) + +dep depend:: dummy + $(CXX) $(CXXFLAGS) -M *.cc> .depend + Added: trunk/filesystems/intfs/intfsDirIno.h ============================================================================== --- trunk/filesystems/intfs/intfsDirIno.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/intfs/intfsDirIno.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,46 @@ +// -*- C++ -*- + +#ifndef _INTFSDIRINO_H_ +#define _INTFSDIRINO_H_ + +#pragma interface + +#include +#include + +class intfs; + +class ifsDirIno: public DirInode +{ + const string name; + ifsDirIno *dotdot; + int fd; + intfs &filesys; + + int open(); + void close(); + + int updating; + +protected: + void update(); + int do_unlink(const up_preamble &, upp_repl &, + const upp_unlink_s &); + int do_symlink(const up_preamble &, upp_repl &, + const upp_symlink_s &arg); + int do_create(const up_preamble &, upp_repl &, + const upp_create_s &, upp_create_r &); + int do_rename(const up_preamble &, upp_repl &, + const upp_rename_s &); +public: + string path(); + string toppath(); + + ifsDirIno(intfs &fs, Handle hand, ifsDirIno *parent, + string dirname); + ~ifsDirIno(); + + int dupfd(); +}; + +#endif /* _INTFSDIRINO_H_ */ Added: trunk/filesystems/cvsfs/cvsdir.h ============================================================================== --- trunk/filesystems/cvsfs/cvsdir.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/cvsfs/cvsdir.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,6 @@ +/* + * Functions to read a CVS checkout directory + */ + +int ReadCVSDir (CVS_DIRENT *dir); + Added: trunk/filesystems/cvsfs/cvstree.h ============================================================================== --- trunk/filesystems/cvsfs/cvstree.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/cvsfs/cvstree.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,10 @@ +/* + * cvstree.h - declarations of fns for filesystem tree manipulation + */ + +int get_path(char *name, int size, CVS_DIRENT *t, int type); +int RemoveChild(CVS_DIRENT *dir, CVS_DIRENT *ent); +CVS_DIRENT *FindChild(CVS_DIRENT *ent, char *name, int namelen); +CVS_DIRENT *CreateChild(char *name, int type); +int ReadChildren(CVS_DIRENT *ent, int type); + Added: trunk/filesystems/cvsfs/cvs.h ============================================================================== --- trunk/filesystems/cvsfs/cvs.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/cvsfs/cvs.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,56 @@ + +#ifndef __CVS_H__ +#define __CVS_H__ + +typedef struct _ChunkInfo +{ + int *offsets; + int size; + int first_line; /* for the future */ + int last_line; /* for the future */ + struct _ChunkInfo *next;/* for the future */ +} ChunkInfo; + +int ReadChunkInfo(int fd, ChunkInfo **ci); +int ReadChunkedData(int fd, ChunkInfo *ci, size_t offset, + size_t count, unsigned char *buf); +size_t ChunkSize(const ChunkInfo *ci); +size_t GetVersionLength(int fd); + +#define Y_MAGIC 0x005D595D + +/* some file types */ +#define NO_TYPE 0x00 /* bad or unknown file type */ +#define VER_FILE 0x10 /* repository version file */ +#define STD_FILE 0x11 /* normal file in checked out dir */ +#define REP_DIR 0x12 /* repository directory */ +#define STD_DIR 0x13 /* normal directory in checked out dir */ +#define CHECKOUT_FILE 0x14 /* checked out and existing file */ +#define CHECKOUT_DIR 0x15 /* checked out and existing directory */ +#define DELETED_FILE 0x16 /* directory checked out but deleted */ +#define DELETED_DIR 0x17 /* directory checked out but deleted */ + +#define IS_DELETED(type) (((type)==DELETED_FILE)||((type)==DELETED_DIR)) + +/* maximum length of a filename */ +#define MAXCVSFILE 1024 + +/* + * malloc allocs us around 0x100 bytes per alloc anyhow, so + * we might as well use it. + */ +typedef struct CVS_DIRENT { + int magic; + int file_type; /* this is true if the file is in the repository */ + int fd; + int ref_count; + struct CVS_DIRENT *parent; + struct CVS_DIRENT *next; + struct CVS_DIRENT *child; + ChunkInfo *info; + char *cvsdir,*codir; /* name of the repositry and checkout dir */ + char strings[MAXCVSFILE]; /* because i'm lazy */ +} CVS_DIRENT; + +#endif + Added: trunk/filesystems/cvsfs/cvsfs.c ============================================================================== --- trunk/filesystems/cvsfs/cvsfs.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/cvsfs/cvsfs.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,1133 @@ +/* cvs access archive filesystem. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#include +#include + +#include +#include "cvs.h" +#include "cvstree.h" +#include "cvsdir.h" + +static char *mpoint; +static CVS_DIRENT *root; + +unsigned char *delete_me = NULL; + +/* No point in this being in a seperate file. */ +#include + +#define FAIL(str) fprintf(stderr, "%s:%d %s failed with errno = %s (%d)\n", \ + __FILE__, __LINE__, str, strerror(errno), errno) + +static int myread (int fd, void *buf, int sz) +{ + int rd = 0; + int ret; + + while (sz > 0) + { + ret = read (fd, buf, sz); + + if (ret == -1) + { + if (errno == EINTR) + continue; + + perror ("myread"); + exit (1); + } + + if (ret == 0) + break; + + sz -= ret; + buf += ret; + rd += ret; + } + + return rd; +} + +static int mywrite (int fd, const void *buf, int sz) +{ + int wr = 0; + int ret; + + while (sz > 0) + { + ret = write (fd, buf, sz); + + if (ret == -1) + { + if (errno == EINTR) + continue; + FAIL ("write"); + exit (1); + } + + if (ret == 0) + { + fprintf (stderr, "write wrote 0 bytes\n"); + break; + } + + sz -= ret; + buf += ret; + wr += ret; + } + + return wr; +} + +static int readpkt (int fd, up_preamble *pre, unsigned char *buf) +{ + int presz = sizeof_up_preamble (pre); + unsigned int rd; + unsigned char pbuf[presz]; + + memset (pbuf, 0, sizeof (pbuf)); + + rd = myread (fd, pbuf, presz); + if (rd != presz) + { + if (rd == 0) + return 0; + if (rd > 0) + fprintf (stderr, "readpkt, incomplete read (%d, not %d)\n", + rd, presz); + perror ("readpkt, header read"); + return -1; + } + + decode_up_preamble (pre, pbuf); + + if (pre->isreq != UP_ENQ && pre->isreq != UP_REQ) + fprintf (stderr, "pre->isreq = %d\n", pre->isreq); + + if (pre->version != UP_VERSION) + { + fprintf (stderr, "Version mismatch: us=%d them=%d\n", + UP_VERSION, pre->version); + return -1; + } + + if (pre->size != 0) + { + if (myread (fd, buf, pre->size) != pre->size) + { + perror ("readpkt, body read"); + return -1; + } + } + + return 1; +} + +static int writepkt (int fd, upp_repl *repl, const unsigned char *buf) +{ + int replsz = sizeof_upp_repl (repl); + unsigned char pbuf[replsz]; + unsigned int wr; + unsigned char *p; + + assert (repl->version == UP_VERSION); + assert (repl->isreq == UP_REPL); + + p = encode_upp_repl (repl, pbuf); + + assert (replsz == p - pbuf); + + wr = mywrite (fd, pbuf, replsz); + if (wr != replsz) + { + perror ("writepkt, header write"); + return -1; + } + + if (repl->size > 0 && repl->err_no == 0) + { + if ( mywrite(fd, buf, repl->size) != repl->size) + { + perror ("writepkt, body write"); + return -1; + } + } + + return 1; +} + +static void genpkt (upp_repl *repl, int seq, up_ops op) +{ + repl->version = UP_VERSION; + repl->seq = seq; + repl->op = op; + repl->isreq = 0; + repl->size = 0; + repl->err_no = 0; +} + +static int do_iread (unsigned char *buf, upp_repl *repl) +{ + upp_iread_s rcv; + upp_iread_r snd; + struct stat st; + CVS_DIRENT *ent ; + char name[1024]; + + decode_upp_iread_s(&rcv, buf); + + memset(&snd, 0, sizeof(snd)); + + ent = (CVS_DIRENT *) rcv.handle.handle; + snd.handle = rcv.handle; + + if( IS_DELETED(ent->file_type)) + return ENOENT; + + if(0 > get_path(name,sizeof name-2, ent, ent->file_type)) + { + fprintf(stderr,"Filename too long.\n"); + return ENAMETOOLONG; + } + + /* fprintf(stderr,"stat on file: %s\n",name); */ + + if(ent->file_type==VER_FILE) + strcat(name,",v"); + + /* if the file exists, add it to our tree */ + if(0>lstat(name,&st)) + { + return ENOENT; + } + + /* this is slow, but if we don't do it, reading is wrong */ + if(ent->file_type == VER_FILE) + { + int fd = open(name,O_RDONLY); + /* fprintf(stderr,"Checking length %s ...",name); */ + snd.ino.size = GetVersionLength(fd); + /* fprintf(stderr,"OK\n"); */ + close(fd); + } + else + snd.ino.size = st.st_size; + + /* clear the writable bits for repository files */ + if(ent->file_type == VER_FILE) + snd.ino.mode = st.st_mode&~(S_IWUSR|S_IWGRP|S_IWOTH); + else if(ent->file_type == STD_DIR || ent->file_type == REP_DIR) + snd.ino.mode = S_IFDIR | st.st_mode; + else + snd.ino.mode = st.st_mode; + + /* copy from one filesystem to the other */ + snd.ino.uid = st.st_uid; + snd.ino.gid = st.st_gid; + snd.ino.nlink = st.st_nlink; + snd.ino.blksize = st.st_blksize; + snd.ino.blocks = st.st_blocks; + snd.ino.mtime = st.st_mtime; + snd.ino.atime = st.st_atime; + snd.ino.ctime = st.st_ctime; + snd.ino.rdev = st.st_rdev; + + repl->size = encode_upp_iread_r(&snd, buf) - buf; + + return 0; +} + +static int do_lookup (unsigned char *buf, upp_repl *repl) +{ + upp_lookup_s rcv; + upp_lookup_r snd; + CVS_DIRENT *ent; + CVS_DIRENT *t; + + decode_upp_lookup_s(&rcv, buf); + + ent = (CVS_DIRENT *) rcv.dir.handle; + + if (rcv.name.nelem == 2 + && rcv.name.elems[0] == '.' && rcv.name.elems[1] == '.') + { + t = ent->parent; + } + else if (rcv.name.nelem == 1 && rcv.name.elems[0] == '.') + { + t = ent; + } + else + { + if(!ent->child) + { + /* files in the checked out filesystem shadow those in the repositry */ + ReadCVSDir(ent); + ReadChildren(ent,STD_DIR); + ReadChildren(ent,REP_DIR); + } + t = FindChild(ent, rcv.name.elems, rcv.name.nelem); + if(t && IS_DELETED(t->file_type)) + return ENOENT; + } + FREE(rcv.name.elems); + if (!t) + { + return ENOENT; + } + snd.handle.handle = (Ulong) t; + + repl->size = encode_upp_lookup_r (&snd, buf) - buf; + + return 0; +} + +/* read the elements in a directory */ +static int do_readdir (unsigned char *buf, upp_repl *repl) +{ + upp_readdir_s rcv; + upp_readdir_r snd; + CVS_DIRENT *ent; + CVS_DIRENT *t; + + decode_upp_readdir_s(&rcv, buf); + + ent = (CVS_DIRENT *) rcv.dir.handle; + + snd.off = 0; + snd.name.nelem = 0; + + /* if there are no children, try and read some */ + if(!ent->child) + { + /* files in the checked out filesystem shadow those in the repositry */ + ReadCVSDir(ent); + ReadChildren(ent,STD_DIR); + ReadChildren(ent,REP_DIR); + } + + /* now just look up the appropriate offset */ + switch(rcv.off) { + case 0: + snd.name.elems = "."; + t = ent; + break; + case 1: + snd.name.elems = ".."; + t = ent->parent; + break; + default: + rcv.off-=2; + for(t=ent->child; t && rcv.off--; ) + { + do { + t = t->next; + } while(t && IS_DELETED(t->file_type)); + } + if (t) + snd.name.elems = t->strings; + } + + if(t) { + snd.off = 1; + snd.name.nelem = strlen (snd.name.elems); + snd.file.handle = (Ulong) t; + } + + repl->size = encode_upp_readdir_r(&snd, buf) - buf; + + return 0; +} + +/* 0 is success, nonzero failure */ +static int MakeCheckoutDir(CVS_DIRENT *dir) +{ + char name[MAXCVSFILE]; + int r; + + /* if we're already a standard directory, return */ + if(dir->file_type == STD_DIR) + return 0; + + /* if we're not a repository directory, bail */ + if(dir->file_type != REP_DIR) + return EPERM; + + /* if we're at the root directory, then it should already exist... */ + if(dir->parent == dir) + return 0; + + r = MakeCheckoutDir(dir->parent); + + if(r != 0) + return r; + + /* force the name to be in the checkout area */ + if(0>get_path(name,sizeof name,dir,STD_DIR)) + return ENAMETOOLONG; + + fprintf(stderr,"Making checkout directory %s\n",name); + /* TODO: this mask should be read from the repository directory */ + if(0>mkdir(name,0755)) + return errno; + + /* update the directory entry to be a checkout directory */ + dir->file_type = STD_DIR; + + return 0; +} + +static int do_rename (unsigned char *buf, upp_repl *repl) +{ + upp_rename_s rcv; + CVS_DIRENT *olddir; + CVS_DIRENT *newdir; + CVS_DIRENT *ent; + CVS_DIRENT *target; + char oldfile[1024]; + char newfile[1024]; + + decode_upp_rename_s (&rcv, buf); + + fprintf(stderr,"do_rename: "); + + olddir = (CVS_DIRENT *) rcv.odir.handle; + newdir = (CVS_DIRENT *) rcv.ndir.handle; + + ent = FindChild(olddir, rcv.oname.elems, rcv.oname.nelem); + if(!ent) + { + fprintf(stderr,"no child found.\n"); + return ENOENT; + } + + if(ent->file_type != STD_FILE) + { + fprintf(stderr,"not a standard file.\n"); + return EPERM; + } + + /* + * If the directory is not a checkout directory + * then a new mirror directory will be created in the checkout area. + */ + if(MakeCheckoutDir(newdir)) + { + fprintf(stderr,"couldn't make a checkout directory\n"); + return EPERM; + } + + /* + * Check if there is already a directory entry by this name + * and whether or not we can overwrite it. + */ + if((target = FindChild(newdir,rcv.nname.elems,rcv.nname.nelem))) + if((target->file_type == REP_DIR) || (target->file_type == VER_FILE)) + return EPERM; + + if(0>get_path(oldfile,sizeof oldfile,ent,ent->file_type)) + { + fprintf(stderr,"old path too long.\n"); + return ENAMETOOLONG; + } + + /* TODO: need to check whether we will overwrite a deleted checkout file */ + + strncpy(ent->strings,rcv.nname.elems,rcv.nname.nelem); + ent->strings[rcv.nname.nelem]=0; + + if(0>get_path(newfile,sizeof newfile,ent,ent->file_type)) + { + fprintf(stderr,"new path too long.\n"); + return ENAMETOOLONG; + } + if(0>rename(oldfile,newfile)) + { + /* copy the old name back */ + strncpy(ent->strings,rcv.oname.elems,rcv.oname.nelem); + ent->strings[rcv.oname.nelem]=0; + + return errno; + } + + /* if there was a file overwritten by the rename, remove it */ + if(target) + RemoveChild(newdir,target); + + fprintf(stderr,"%s -> %s rename OK.\n",oldfile,newfile); + + return 0; +} + +static int do_unlink (unsigned char *buf, upp_repl *repl) +{ + upp_unlink_s rcv; + CVS_DIRENT *dir; + CVS_DIRENT *ent; + char filename[1024]; + + decode_upp_unlink_s (&rcv, buf); + + dir = (CVS_DIRENT *) rcv.dir.handle; + + if(dir->magic != Y_MAGIC) + return EPERM; + + ent = FindChild(dir, rcv.name.elems, rcv.name.nelem); + + if(0>get_path(filename,sizeof filename,ent,ent->file_type)) + return ENAMETOOLONG; + + if(ent->ref_count) + fprintf(stderr,"Unlinking an open file. Maybe not so good...\n"); + + switch(ent->file_type) + { + case VER_FILE: + case REP_DIR: + return EPERM; + case STD_FILE: + if(0>unlink(filename)) + return errno; + RemoveChild(dir,ent); + break; + case STD_DIR: + if(0>rmdir(filename)) + return errno; + RemoveChild(dir,ent); + break; + case DELETED_FILE: + case DELETED_DIR: + return ENOENT; + case CHECKOUT_FILE: + if(0>unlink(filename)) + return errno; + ent->file_type = DELETED_FILE; + break; + case CHECKOUT_DIR: + if(0>rmdir(filename)) + return errno; + ent->file_type = DELETED_DIR; + break; + default: + fprintf(stderr,"File type %X. What's that?\n",ent->file_type); + return EPERM; + } + + return 0; +} + +static int do_create (unsigned char *buf, upp_repl *repl) +{ + upp_create_s rcv; + upp_create_r snd; + CVS_DIRENT *dir; + CVS_DIRENT *ent; + char filename[1024]; + + decode_upp_create_s (&rcv, buf); + dir = (CVS_DIRENT *) rcv.dir.handle; + + if(dir->magic != Y_MAGIC) + return EPERM; + + if( (ent = FindChild(dir,rcv.name.elems,rcv.name.nelem)) ) + { + if(!IS_DELETED(ent->file_type)) + return EPERM; + if(0>get_path(filename,sizeof filename,ent,ent->file_type)) + return ENAMETOOLONG; + } + else + { + if(MakeCheckoutDir(dir)) + { + fprintf(stderr,"create: couldn't make checkout directory\n"); + return EPERM; + } + + strncpy(filename,rcv.name.elems,rcv.name.nelem); + filename[rcv.name.nelem]=0; + + ent = CreateChild(filename,(rcv.mode&S_IFDIR)?STD_DIR:STD_FILE); + if(0>get_path(filename,sizeof filename,ent,ent->file_type)) + { + free(ent); + return ENAMETOOLONG; + } + } + + /* new files must be created on the RW filesystem */ + switch(ent->file_type) + { + case STD_FILE: + ent->fd = creat ( filename, rcv.mode); + if(ent->fd<0) + { + free(ent); + return errno; + } + close(ent->fd); + ent->fd = 0; + /* OK, now add it to its parent's child list (at the beginning) */ + ent->next = dir->child; + dir->child = ent; + break; + + case STD_DIR: + if(0>mkdir(filename,rcv.mode)) + return errno; + /* OK, now add it to its parent's child list (at the beginning) */ + ent->next = dir->child; + dir->child = ent; + break; + + case DELETED_DIR: + if(0>mkdir(filename,rcv.mode)) + return errno; + ent->file_type = CHECKOUT_DIR; + break; + + case DELETED_FILE: + ent->fd = creat ( filename, rcv.mode); + if(ent->fd<0) + return errno; + close(ent->fd); + ent->file_type = CHECKOUT_FILE; + break; + default: + fprintf(stderr,"cvs: Somebody tried to create a wierd file.\n"); + return EPERM; + } + + /* now return the handle to the new file */ + snd.file.handle = (Ulong) ent; + repl->size = encode_upp_create_r (&snd, buf) - buf; + + return 0; +} + +static int do_open (unsigned char *buf, upp_repl *repl) +{ + upp_open_s rcv; + CVS_DIRENT *ent; + char filename[1024]; + + decode_upp_open_s (&rcv, buf); + + ent = (CVS_DIRENT *) rcv.file.handle; + + if(ent->magic != Y_MAGIC) + return EPERM; + + if(!ent->ref_count) + { + if(0>get_path(filename,sizeof filename,ent,ent->file_type)) + return EPERM; + + switch(ent->file_type) + { + case VER_FILE: + strcat(filename,",v"); + ent->fd = open ( filename, O_RDONLY); + if(ent->fd<0) + return EPERM; + /* maybe we should re-read the chunk info? */ + if(!ent->info) + if(ReadChunkInfo(ent->fd, &ent->info)) + return EPERM; + break; + + case STD_DIR: /* nothing to do when opening directories */ + case CHECKOUT_DIR: + break; + + case DELETED_FILE: + case DELETED_DIR: + return ENOENT; + + case STD_FILE: + case CHECKOUT_FILE: + ent->fd = open ( filename, O_RDWR); + if(ent->fd<0) + { + fprintf(stderr,"Open %s failed\n",filename); + return EPERM; + } + break; + } + } + ent->ref_count++; + + return 0; +} + +/* + * free handles if nobody left using the file + */ +static int do_close (unsigned char *buf, upp_repl *repl) +{ + upp_close_s rcv; + CVS_DIRENT *ent; + + decode_upp_close_s (&rcv, buf); + + ent = (CVS_DIRENT *) rcv.file.handle; + + if(!ent->ref_count) + return EPERM; + + ent->ref_count--; + if(!ent->ref_count) + { + switch(ent->file_type) + { + case VER_FILE: + if(ent->info) + { + if(ent->info->offsets) + free(ent->info->offsets); + ent->info->offsets=NULL; + free(ent->info); + ent->info = NULL; + } + /* fall through */ + case CHECKOUT_FILE: + case STD_FILE: + close(ent->fd); + ent->fd = 0; + /* fall through */ + case CHECKOUT_DIR: + case STD_DIR: + case REP_DIR: + default: + /* still falling... */ + } + } + + return 0; +} + +static int do_truncate (unsigned char *mbuf, upp_repl *repl) +{ + upp_truncate_s rcv; + CVS_DIRENT *ent; + char filename[1024]; + + decode_upp_truncate_s (&rcv, mbuf); + + ent = (CVS_DIRENT *) rcv.file.handle; + + if(ent->magic != Y_MAGIC) + return EPERM; + + switch(ent->file_type) + { + case VER_FILE: + case REP_DIR: + case STD_DIR: + case CHECKOUT_DIR: + case DELETED_DIR: + case DELETED_FILE: + return EPERM; + + case STD_FILE: + case CHECKOUT_FILE: + if(ent->ref_count) + { + if(0>ftruncate(ent->fd,rcv.size)) + return errno; + } + else + { + if(0>get_path(filename,sizeof filename,ent,ent->file_type)) + return ENAMETOOLONG; + + if(0>truncate(filename,rcv.size)) + return errno; + } + break; + } + + return 0; +} + +/* + * We can only write to files in the checkout directory. + */ +static int do_write (unsigned char *mbuf, upp_repl *repl) +{ + upp_write_s rcv; + upp_write_r snd; + CVS_DIRENT *ent; + int rc; + + decode_upp_write_s (&rcv, mbuf); + + ent = (CVS_DIRENT *) rcv.file.handle; + + /* check that the file is actually open */ + if(!ent->ref_count) + return EPERM; + + /* make doublely sure we don't write to repository files */ + switch(ent->file_type) + { + case VER_FILE: + case STD_DIR: + case REP_DIR: + case CHECKOUT_DIR: + case DELETED_DIR: + case DELETED_FILE: + return EPERM; + case CHECKOUT_FILE: + case STD_FILE: + lseek(ent->fd, rcv.off, SEEK_SET); + rc = write(ent->fd, rcv.data.elems, rcv.data.nelem); + if(rc < 0) + return errno; + break; + default: + fprintf(stderr,"Wierdo file write. Blah!\n"); + return EPERM; + } + + snd.wrote = rc; + + repl->size = encode_upp_write_r (&snd, mbuf) - mbuf; + + return 0; +} + +/* + * two cases: read from a normal file or read from the repository + */ +static int do_read (unsigned char *mbuf, upp_repl *repl) +{ + upp_read_s rcv; + upp_read_r snd; + CVS_DIRENT *ent; + int rc; + long size; + + snd.data.nelem = 0; + snd.data.elems = NULL; + + decode_upp_read_s (&rcv, mbuf); + + ent = (CVS_DIRENT *) rcv.file.handle; + + /* check that the file is actually open */ + if(!ent->ref_count) + return EPERM; + + switch(ent->file_type) + { + case VER_FILE: + if(!ent->info) + return EIO; + size = ChunkSize(ent->info); + break; + + case CHECKOUT_FILE: + case STD_FILE: + size = lseek(ent->fd,0,SEEK_END); + if(0>lseek(ent->fd,rcv.off,SEEK_SET)) + return EPERM; + break; + + default: + return EPERM; + } + + if( (size - rcv.off) < rcv.size ) + size = (size - rcv.off); + else + size = rcv.size; + + /* where is this going to be free'd ? */ + if(size) + snd.data.elems = (unsigned char *)malloc(size); + + if(snd.data.elems) + { + if(ent->file_type == VER_FILE) + rc = ReadChunkedData(ent->fd, ent->info, rcv.off, size, snd.data.elems); + else + rc = read(ent->fd,snd.data.elems,size); + + if(rc < 0) + return rc; + snd.data.nelem = rc; + } + + repl->size = encode_upp_read_r (&snd, mbuf) - mbuf; + + /* hack alert! */ + delete_me = snd.data.elems; + + return 0; +} + +/* these must line up with the values defined for the kernel in linux/fs.h */ +#define ATTR_MODE 1 +#define ATTR_UID 2 +#define ATTR_GID 4 +#define ATTR_SIZE 8 +#define ATTR_ATIME 16 +#define ATTR_MTIME 32 +#define ATTR_CTIME 64 + +/* + * make a change to an inode's mode, size, time, ownership, etc. + */ +static int do_notify_change(unsigned char *mbuf, upp_repl *repl) +{ + upp_notify_change_s rcv; + CVS_DIRENT *ent; + char name[1024]; + struct stat st; + struct utimbuf ut; + + decode_upp_notify_change_s (&rcv, mbuf); + ent = (CVS_DIRENT *)rcv.handle.handle; + + switch(ent->file_type) + { + case VER_FILE: + case REP_DIR: + case DELETED_DIR: + case DELETED_FILE: + return EPERM; + case STD_FILE: + case STD_DIR: + case CHECKOUT_FILE: + case CHECKOUT_DIR: + break; + default: + return EPERM; + } + + if(0>get_path(name, sizeof name, ent, ent->file_type)) + return ENAMETOOLONG; + + /* read the old values */ + if(0>lstat(name,&st)) + return errno; + + if(rcv.iattr.ia_valid & ATTR_MODE ) + if(0>chmod(name,rcv.iattr.ia_mode)) + return errno; + + if(rcv.iattr.ia_valid & (ATTR_UID|ATTR_GID)) + { + if(rcv.iattr.ia_valid & ATTR_UID ) + st.st_uid = rcv.iattr.ia_uid; + if(rcv.iattr.ia_valid & ATTR_GID ) + st.st_gid = rcv.iattr.ia_gid; + if(0>chown(name,st.st_uid,st.st_gid)) + return errno; + } + + if(rcv.iattr.ia_valid & ATTR_SIZE ) + { + if(0>truncate(name, rcv.iattr.ia_size)) + return errno; + } + + if(rcv.iattr.ia_valid & (ATTR_ATIME|ATTR_MTIME|ATTR_CTIME) ) + { + if(rcv.iattr.ia_valid & ATTR_ATIME ) + st.st_atime = rcv.iattr.ia_atime; + if(rcv.iattr.ia_valid & ATTR_MTIME ) + st.st_mtime = rcv.iattr.ia_mtime; + if(rcv.iattr.ia_valid & ATTR_CTIME ) /* this is not used */ + st.st_ctime = rcv.iattr.ia_ctime; + } + + if(rcv.iattr.ia_valid & (ATTR_ATIME|ATTR_MTIME) ) + { + ut.actime = st.st_atime; + ut.modtime = st.st_mtime; + if(0>utime(name,&ut)) + return errno; + } + + return 0; +} + +static int do_mount (unsigned char *buf, upp_repl *repl) +{ + upp_mount_r snd; + + snd.root.handle = (Ulong) root; + repl->size = encode_upp_mount_r(&snd, buf) - buf; + /* INIT */ + repl->size = encode_upp_mount_r(&snd, buf) - buf; + return 0; +} + +static void run (int wr, int rd) +{ + up_preamble pre; + upp_repl repl; + /* Ah! The bogey man's a-coming to get me! */ + unsigned char buf[4096]; + int error; + + while(readpkt(rd, &pre, buf) == 1) + { + genpkt(&repl, pre.seq, pre.op); + + switch(pre.op) + { +#define DO(op, b, r) case up_##op: \ + error = (pre.isreq == UP_ENQ ? 0 : do_##op(b, r)); \ + break; + DO(mount, buf, &repl); + DO(iread, buf, &repl); + /* DO(iput, buf, &repl); */ + DO(lookup, buf, &repl); + DO(readdir, buf, &repl); + DO(unlink, buf, &repl); + DO(open, buf, &repl); + DO(close, buf, &repl); + DO(read, buf, &repl); + DO(write, buf, &repl); + DO(create, buf, &repl); + DO(truncate, buf, &repl); + DO(notify_change, buf, &repl); + DO(rename, buf, &repl); +#undef DO + default: + error = ENOSYS; + break; + } + + repl.err_no = error; + if (error != 0) + repl.size = 0; + + if (writepkt(wr, &repl, buf) != 1) + break; + + /* this is a terrible hack! */ + if(delete_me) + { + free(delete_me); + delete_me = NULL; + } + } +} + +CVS_DIRENT *y_read(char *cvsdir, char *codir) +{ + CVS_DIRENT *root; + + if(!cvsdir || !codir) + return NULL; + + root = (CVS_DIRENT*)malloc(sizeof(CVS_DIRENT) + /*+strlen(cvsdir)+strlen(codir)+1*/); + + root->magic = Y_MAGIC; + root->file_type = REP_DIR; + root->info = NULL; + root->fd = 0; + root->ref_count = 1; + root->parent = root; + root->next = NULL; + root->child = NULL; + + /* pointers are to memory at the end of the CVS_DIRENT structure */ + root->cvsdir = &root->strings[0]; + strcpy(root->cvsdir,cvsdir); + root->codir = &root->strings[strlen(root->strings)+1]; + strcpy(root->codir,codir); + + fprintf(stderr,"mounting mirror file system of %s\n",root->strings); + + return root; +} + +int main (int argc, char **argv) +{ + int infd = 0; + int outfd = 1; + int c; + char *cvsroot = NULL; + + while ((c = getopt (argc, argv, "i:o:m:r:")) != EOF) + { + switch(c) + { + case 'i': + infd = atoi(optarg); + break; + case 'o': + outfd = atoi(optarg); + break; + case 'm': + mpoint = optarg; + break; + case 'r': + cvsroot = optarg; + break; + default: + fprintf (stderr, "%s: bad option\n", argv[0]); + return 1; + } + } + +#ifdef FUTURE + /* + * check that we have a CVS repository to work with. + */ + if(cvsroot == NULL) + { + cvsroot = getenv("CVSROOT"); + if(cvsroot == NULL) + { + fprintf(stderr,"neither CVSROOT environment variable nor -r option specified.\n"); + fprintf(stderr,"Where is your CVS repository?\n"); + return 1; + } + } +#endif + + if (optind != argc - 2 ) + { + fprintf (stderr, "%s: cvs directory and checkout dir not named\n", argv[0]); + return 1; + } + + root = y_read (argv[optind], argv[optind+1]); + if (!root) + return 1; + + signal (SIGCHLD, SIG_IGN); + + run(outfd, infd); + + return 0; +} + Added: trunk/filesystems/cvsfs/cvsdir.c ============================================================================== --- trunk/filesystems/cvsfs/cvsdir.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/cvsfs/cvsdir.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,180 @@ +/* + * CVS directory reader + * + * Functions in this file read the contents of a CVS directory + * (the checked out files) and add them to the directory's child + * list. Files are initially named checked out but deleted, and + * are updated to CHECKEDOUT if they are found in the directory. + * That is done elsewhere. We need to keep a record of which files + * are checked out and deleted otherwise we will add the original + * from the repository over the top of it, and it won't be deleted! + */ + +#include +#include +#include +#include +#include +#include +#include + +#include"cvs.h" +#include"cvsdir.h" +#include "cvstree.h" + +/* + * This function will check whether the checkout root for the + * named directory matches that specified on the command line. + * + * Returns 0 for success + * Returns errno for failure + */ +int CheckRoot(CVS_DIRENT *dir, char *name) +{ + return 0; +} + +/* + * This function will check whether the repository for the + * named directory matches that specified on the command line. + * + * Returns 0 for success + * Returns errno for failure + */ +int CheckRepository(CVS_DIRENT *dir, char *name) +{ + return 0; +} + +int MarkEOL(char *data, int max) +{ + int i=0; + + /* find end of line */ + while( (i=max) + return 0; + + if(data[i]==0) + return 0; + + data[i++]=0; + + return i; +} + +/* + * Read the names of all the checked out files in this directory + * and make them into dirents for this directory. + * + * The format of the lines in the Entries file is as follows: + * /ANNOUNCE/1.16/Sun Mar 28 15:38:32 1999// + * D/console//// + * + * leading D means a directory. The filename is the second field. + */ +int ReadCheckedoutFiles(CVS_DIRENT *dir, char *name) +{ + char buffer[MAXCVSFILE]; + int fd,n,pos; + + fd = open(name, O_RDONLY); + if(fd<0) + return 1; + + do + { + pos = 0; + + n = read(fd, buffer, sizeof buffer); + if(n<0) + break; + + do + { + char *token,*line=&buffer[pos]; + int file_type=NO_TYPE; + CVS_DIRENT *ent; + + /* make a string */ + pos = MarkEOL(line,n); + if(pos == 0) + break; + + fprintf(stderr,"Read line %s\n",line); + /* determine the type of file */ + token = strsep(&line,"/"); + if(!token) + continue; + if(!strcmp(token,"D")) + file_type = DELETED_DIR; + if(!strcmp(token,"")) + file_type = DELETED_FILE; + if(file_type==NO_TYPE) + continue; + + /* get the file's name */ + token = strsep(&line,"/"); + if(!token) + continue; + ent = CreateChild(token,file_type); + if(!ent) + continue; + + fprintf(stderr,"added checked out file: %s\n",token); + + /* add the child to the parent */ + ent->parent = dir; + ent->next = dir->child; + dir->child = ent; + } while (pos); + } while (n && pos); + + return 0; +} + +/* + * Read in all the files that have been checked out. + */ +int ReadCVSDir (CVS_DIRENT *dir) +{ + char name[MAXCVSFILE]; + char *p; + struct stat st; + + if(0>get_path(name, sizeof name-4,dir, STD_DIR)) + return ENAMETOOLONG; + + /* first check that there is a CVS subdirectory */ + p = &name[strlen(name)]; + + strcpy(p,"/CVS"); + + fprintf(stderr,"Reading %s\n",name); + + if(0>lstat(name,&st)) + return ENOTDIR; + + if(!S_ISDIR(st.st_mode)) + return ENOTDIR; + + if(CheckRepository(dir,name)) + return ENOTDIR; + + if(CheckRoot(dir,name)) + return ENOTDIR; + + strcat(p,"/Entries"); + + fprintf(stderr,"Reading %s\n",name); + + if(ReadCheckedoutFiles(dir, name)) + return ENOTDIR; + + dir->file_type = CHECKOUT_DIR; + + return 0; +} + Added: trunk/filesystems/cvsfs/cvs.c ============================================================================== --- trunk/filesystems/cvsfs/cvs.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/cvsfs/cvs.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,315 @@ +/* + * cvs version file reader + * + * Eventually plan to be able to read all the versions + */ + +#include +#include +#include +#include +#include +#include +#include "cvs.h" + +#define CVSBLOCK 1024 + +/* + * count the characters in an rcs string eg. @......@@.....@ + */ +static int ParseString(int fd) +{ + char line[1000]; + int i,n,count=0; + int saw_esc = 0; + int end = 0; + + while(!end) + { + n = read(fd,line,sizeof line); + if(n<=0) + end=1; + for(i=0; (i=n); + lseek(fd,i - n + 1, SEEK_CUR); /* go back */ + buffer[i]=0; + + return 0; +} + +/* + * Read information about the location of data in the file + * Offsets are not one to one because of RCS escape characters(@). + */ +size_t *ReadOffsetInfo(int fd, size_t start, size_t size) +{ + size_t *offsets; + char line[CVSBLOCK]; + int i,n,count=0; + size_t total=0; + int saw_esc = 0; + int end = 0; + + lseek(fd,start,SEEK_SET); + + /* allocate data for the offset info */ + offsets = (size_t *)malloc(sizeof(size_t)*((size+CVSBLOCK-1)/CVSBLOCK)); + if(!offsets) + return NULL; + + while(!end) + { + n = read(fd,line,sizeof line); + if(n<=0) + end=1; + for(i=0; (i %x\n",count,start+total); */ + } + if(saw_esc) + { + if(line[i]!='@') + end = 1; + else + count++; + saw_esc = 0; + } + else + { + if(line[i]=='@') + saw_esc = 1; + else + count++; + } + } + } + return offsets; +} + +/* + * this is not going to be very efficient or correct for now + * It would be best to use yacc to generate a parser for the rcs file, + * but this is only proof of concept. + */ +int ReadChunkInfo(int fd, ChunkInfo **ci) +{ + char line[80]; + size_t start_data; + + while(!ReadLine(fd,line,sizeof line)) + { + line[sizeof line -1]=0; + if(!strcmp(line,"text")) + { + /* fprintf(stderr,"Found start of last version\n"); */ + break; + } + } + read(fd,line,1); + if('@' != line[0]) + return 1; + *ci = (ChunkInfo*)malloc(sizeof (ChunkInfo)); + if(!*ci) + return 1; + + start_data= lseek(fd, 0, SEEK_CUR); + (*ci)->size = ParseString(fd); + (*ci)->first_line = 0; + (*ci)->last_line = 0; + (*ci)->next = NULL; + + /* allocate data for the offset info */ + (*ci)->offsets = ReadOffsetInfo(fd, start_data, (*ci)->size); + + return 0; +} + +/* + * This function is called every time a directory is read. + * If the length in the directory is incorrect, then programs want + * to read too much data from the file. + * + * That's not good because it makes reading directories very + * slow, but unless the length can be determined without parsing + * the whole file, tough. + */ +size_t GetVersionLength(int fd) +{ + char line[80]; + + while(!ReadLine(fd,line,sizeof line)) + { + line[sizeof line -1]=0; + if(!strcmp(line,"text")) + { + /* fprintf(stderr,"Found start of last version\n"); */ + break; + } + } + read(fd,line,1); + if('@' != line[0]) + return 0; + + return ParseString(fd); +} + +/* + * This could be made a lot more efficient with the use of + * memcpy. You can't use strchr, as there may be zero bytes in the data. + * + * The idea is the read one block, removing any escape + * characters from the data. + */ +int ReadChunk(int fd, ChunkInfo *ci, int blockno, unsigned char *buf) +{ + int i,j,n,saw_esc,jnow; + size_t count = CVSBLOCK; + + lseek(fd,ci->offsets[blockno], SEEK_SET); + /* printf("Reading at %X\n",ci->offsets[blockno]); */ + + j=0; + saw_esc = 0; + while(count > j) + { + n = read(fd, &buf[j], count-j); + if(n<=0) + break; + jnow = j; + for(i=jnow; i<(jnow+n); i++) + { + if(saw_esc) + { + buf[j++]=buf[i]; + saw_esc=0; + } + else + { + if(buf[i]=='@') + saw_esc = 1; + else + buf[j++]=buf[i]; + } + } + } + + return j; +} + +/* + * Read data from the file in blocks of CVSBLOCK + * Need to keep a list of offsets because we don't know + * how many escape characters there are. + */ +int ReadChunkedData(int fd, ChunkInfo *ci, size_t offset, + size_t count, unsigned char *buf) +{ + unsigned char block[CVSBLOCK]; + int total, blockno, size; + + if( (offset+count) > ci->size) + count = ci->size - offset; + + total = 0; + for(blockno = offset/CVSBLOCK; blockno<=((offset+count)/CVSBLOCK); blockno++) + { + + /* printf("reading chunk %d\n",blockno); */ + + ReadChunk(fd, ci, blockno, block); + + /* set size to count to transfer as much as possible */ + size = count; + + /* then check we don't overrun the end of the read block */ + if( ((offset%CVSBLOCK)+size) > CVSBLOCK) + size = CVSBLOCK - offset%CVSBLOCK; + + memcpy(buf,&block[offset%CVSBLOCK],size); + count -= size; + offset += size; + buf += size; + total += size; + } + + return total; +} + +size_t ChunkSize(const ChunkInfo *ci) +{ + if(ci == NULL) + return 0; + return ci->size; +} + +#ifdef TEST + +int main() +{ + int fd = open("/usr/src/wine/cvs/wine/wine.ini,v",O_RDONLY); + int n; + ChunkInfo *ci = NULL; + unsigned char *data; + + if(!fd) + { + fprintf(stderr,"Open failed\n"); + return 1; + } + + if(0!=ReadChunkInfo(fd,&ci)) + { + fprintf(stderr,"ReadChunkInfo failed\n"); + return 1; + } + + fprintf(stderr,"Size is %d, offset is %d\n",ci->size,ci->offset); + n = ChunkSize(ci); + data = (unsigned char *)malloc(n); + ReadChunkedData(fd,ci,0,n,data); + write(1,data,n); + return 0; +} + +#endif Added: trunk/filesystems/cvsfs/cvstree.c ============================================================================== --- trunk/filesystems/cvsfs/cvstree.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/cvsfs/cvstree.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,284 @@ +/* cvs access archive filesystem. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#include +#include + +#include +#include "cvs.h" + +/* + * Construct a real path name without trailing slash + * This will be used to access the existing file system. + * + * type indicates whether we are accessing the RO or RW + * base file system. + */ +int get_path(char *name, int size, CVS_DIRENT *t, int type) +{ + int len,plen; + + if(!t) + return -ENOENT; + if(t->parent != t) + { + len = strlen(t->strings)+1; /* include trailing zero byte */ + if(len>size) + return -ENOENT; + len++; /* include slash */ + if(0>(plen=get_path(name, size - len, t->parent, type))) + return -ENOENT; + strcat(name,"/"); + strcat(name,t->strings); + } + else + { + /* we're at the root inode */ + plen=0; + switch(type) + { + case VER_FILE: + case REP_DIR: + len = strlen(t->cvsdir)+1; /* include trailing zero byte */ + if(len>size) + return -ENOENT; + strcpy(name,t->cvsdir); + break; + case STD_FILE: + case STD_DIR: + case DELETED_DIR: + case DELETED_FILE: + case CHECKOUT_FILE: + case CHECKOUT_DIR: + len = strlen(t->codir)+1; /* include trailing zero byte */ + if(len>size) + return -ENOENT; + strcpy(name,t->codir); + break; + default: + strcpy(name,""); + return -ENOENT; + } + } + return plen+len; +} + +/* + * Remove a child entry from a directory. + */ +int RemoveChild(CVS_DIRENT *dir, CVS_DIRENT *ent) +{ + CVS_DIRENT **t; + + if(!dir || !ent) + return 1; + + for(t = &dir->child; *t; t = &((*t)->next)) + { + if(*t == ent) + break; + } + if(*t) + { + CVS_DIRENT *freeme = *t; + *t = (*t)->next; + free(freeme); + } + else + return 1; + + return 0; +} + +/* + * Return a dirent with the name specified or NULL. + * This is the essence of the lookup function. + */ +CVS_DIRENT *FindChild(CVS_DIRENT *ent, char *name, int namelen) +{ + CVS_DIRENT *t; + int i=0; + + for(t = ent->child; t; t=t->next) + { + if(i++>1000) + { + fprintf(stderr,"Wow. Something's wrong here\n"); + return NULL; + } + /* check the length */ + if(t->strings[namelen]) + continue; + if (!strncmp(t->strings, name, namelen)) + break; + } + return t; +} + +/* create a blank entry */ +CVS_DIRENT *CreateChild(char *name, int type) +{ + CVS_DIRENT *ent; + + ent = (CVS_DIRENT *) malloc(sizeof (CVS_DIRENT)); + if(!ent) + return ent; + + strcpy(ent->strings,name); + ent->magic = Y_MAGIC; + ent->file_type = type; + ent->info = NULL; + ent->fd = 0; + ent->ref_count=0; + ent->parent = NULL; + ent->child = NULL; + ent->cvsdir = NULL; + ent->next = NULL; + + return ent; +} + +int getdents(unsigned int fd, struct dirent *dirp, unsigned int count) +{ + _syscall3(int, getdents, uint, fd, struct dirent *, dirp, uint, count); + return(0); +} + +/* + * type can be VER_FILE or STD_FILE + */ +int ReadChildren(CVS_DIRENT *ent, int type) +{ + /* read the directory into memory */ + CVS_DIRENT *t; + char buffer[1024],filename[1024],*p; + struct dirent *de=(struct dirent *)buffer; + int len,n,fd; + struct stat st; + + if(0>get_path(filename, sizeof filename, ent, type)) + return ENOTDIR; + + fprintf(stderr,"reading dir: %s\n",filename); + + fd = open(filename,O_RDONLY); + if(fd<0) + return ENOTDIR; + + /* ok, now prepare to stat each file by adding it to the buffer */ + p = &filename[strlen(filename)]; + *p++ = '/'; + + while(1) + { + de=(struct dirent *)&buffer[0]; + n=0; + len=getdents(fd, de, sizeof buffer); + if(!len) + break; + while(nd_name,".") && strcmp(de->d_name,"..")) + { + int add_file = 1; + int file_type = NO_TYPE; + + switch(type) + { + case REP_DIR: + case VER_FILE: + /* check that the file is a CVS version or a directory */ + if(strcmp(&de->d_name[strlen(de->d_name)-2],",v")) + { + /* stat the file */ + strcpy(p,de->d_name); + if(0>stat(filename,&st)) + add_file = 0; + if(!S_ISDIR(st.st_mode)) + add_file = 0; + else + file_type = REP_DIR; + } + else + { + /* remove the ,v */ + de->d_name[strlen(de->d_name)-2]=0; + add_file = 1; + file_type = VER_FILE; + } + break; + case STD_DIR: + case STD_FILE: + /* stat the file */ + strcpy(p,de->d_name); + if(0>stat(filename,&st)) + add_file = 0; + else + if(S_ISDIR(st.st_mode)) + file_type = STD_DIR; + else + file_type = STD_FILE; + break; + default: + fprintf(stderr,"Unknown file type.\n"); + } + + /* if there is already a child with this name, don't add this one */ + if(FindChild(ent, de->d_name, strlen(de->d_name))) + { + add_file = 0; + switch(ent->file_type) + { + case DELETED_DIR: + if(file_type==STD_DIR) + ent->file_type = CHECKOUT_DIR; + break; + case DELETED_FILE: + if(file_type==STD_DIR) + ent->file_type = CHECKOUT_FILE; + ent->file_type = CHECKOUT_FILE; + break; + } + } + + if(add_file) + { + fprintf(stderr,"Adding %s\n",de->d_name); + t = CreateChild(de->d_name,file_type); + + if(t) + { + /* add this to the head of the parent's child list */ + t->parent = ent; + t->next = ent->child; + ent->child = t; + } + } + } + n+=de->d_reclen; + de = (struct dirent *)&buffer[n]; + } + } + close(fd); + + return 0; +} + Added: trunk/filesystems/cvsfs/Makefile ============================================================================== --- trunk/filesystems/cvsfs/Makefile 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/cvsfs/Makefile 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,38 @@ +CC = gcc +CFLAGS = -O2 -Wall -I../../kernel +CPPFLAGS = #-DDEBUG +LDFLAGS = -s + +SRCS = cvsfs.c cvs.c cvsdir.c cvstree.c +DISTS = $(SRCS) README Makefile + +cvsfs : cvsfs.o cvs.o cvsdir.o cvstree.o + +test: cvs.o + $(CC) $(CFLAGS) cvs.c -DTEST -o cvscat + +.PHONY : dist dep clean realclean spotless + +dep : .depend +.depend : $(SRCS) + $(CC) $(CFLAGS) -MM *.c > .depend + +dist : $(DISTS) + rm -rf /tmp/cvsfs + mkdir /tmp/cvsfs + cp -a $(DISTS) /tmp/cvsfs + (cd /tmp; tar cfvz - cvsfs) >cvsfs.tar.gz + rm -rf /tmp/cvsfs + +clean : + rm -f *.o core *~ *.orig *.rej cvsfs + +realclean : clean + rm -rf cvsfs + +spotless : realclean + rm -f .depend + +ifeq (.depend,$(wildcard .depend)) +include .depend +endif Added: trunk/filesystems/cvsfs/README ============================================================================== --- trunk/filesystems/cvsfs/README 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/cvsfs/README 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,42 @@ +Hello, + +cvsfs was derived from arcfs by David P Gymer. + +This code allows read only access to the latest versions in a CVS repositry. +Reading is done on the fly. i have tested this by building "wine" + +This filesystem allows you to build a CVS module without checking it out of +the repository. + +usage: + insmod kernel/src/userfs.o + utils/muserfs contrib/cvsfs/cvsfs /usr/src/mnt /usr/src/wine/cvs/wine \ + /usr/src/wine/wine + +(/usr/src/wine/cvs/wine is the wine directory in my cvs repository) +(/usr/src/wine/wine is the checkout directory) + +Normally, instead of using cvsfs you would type: + setenv CVSROOT /usr/src/wine/cvs + cd /usr/src/wine + cvs checkout wine + cd wine + configure + make depend + make + +After installing cvsfs, you can do the following: + setenv CVSROOT /usr/src/wine/cvs + cd /usr/src/wine + mkdir wine + mkdir mnt + + cd mnt + configure + make depend + make + +This way, you don't have to checkout the wine module to compile it... + +Mike McCormack 24 April 1999 + Added: trunk/filesystems/gvfs/vfsbase.h ============================================================================== --- trunk/filesystems/gvfs/vfsbase.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/gvfs/vfsbase.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,68 @@ +/* + * Portions of this work Copyright (C) 2001 Oracle Corporation + * + * This 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 software 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 library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef _VFSBASE_H +#define _VFSBASE_H + +#include + +#define FAIL(str) fprintf(stderr, "%s:%d %s failed with errno = %s (%d)\n", __FILE__, __LINE__, str, strerror(errno), errno) +#ifdef DEBUG +#include +#include +#define DB(x) {x;} +#else +#define DB(x) /**/ +#endif +#define DIRINO 1 +#define DIRECTORY_SIZE -1 +#define VFS_OPTAB_SIZE 25 +typedef int (*VfsOperation) (unsigned char *, upp_repl *); + +/* { + VfsOperation create; + VfsOperation lookup; + VfsOperation close; + VfsOperation read; + VfsOperation write; + VfsOperation truncate; + VfsOperation fsync; + VfsOperation readdir; + VfsOperation link; + VfsOperation unlink; + VfsOperation symlink; + VfsOperation readlink; + VfsOperation followlink; + VfsOperation mount; + VfsOperation umount; + VfsOperation iread; + VfsOperation iwrite; + VfsOperation statfs; + VfsOperation iput; + VfsOperation open; + VfsOperation permission; + VfsOperation rename; + VfsOperation multireaddir; + VfsOperation notify_change; + VfsOperation inode_valid; +} VfsOptab; */ + + +#endif /* _VFSBASE_H */ Added: trunk/filesystems/gvfs/gvfsops.c ============================================================================== --- trunk/filesystems/gvfs/gvfsops.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/gvfs/gvfsops.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,820 @@ +/* + * Portions of this work Copyright (C) 2001 Oracle Corporation + * + * This 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 software 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 library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include + +/* #include */ +#include + +#include "vfsbase.h" +#include "gvfs.h" + + +static char *mpoint; +static GVFS_DIRENT *root; + +static int do_gnome_vfs_readdir (GVFS_DIRENT * dir); +static int make_root_inode (char *uri, GnomeVFSFileInfo * info); + +#ifdef DEBUG +#define MESSAGE(x) fprintf(stderr, "%s\n", (x)) +#else +#define MESSAGE(x) +#endif + + +static GVFS_DIRENT * +make_gvfs_dirent (GVFS_DIRENT * dir, GnomeVFSFileInfo * info) +{ + GVFS_DIRENT *ent; + char *dirname; + + dirname = dir->fullname; + ent = malloc (sizeof (GVFS_DIRENT) + strlen (dirname) + strlen (info->name) + 2); + if (!ent) + return NULL; + + strcpy (ent->fullname, dirname); + strcat (ent->fullname, "/"); + strcat (ent->fullname, info->name); + ent->name = ent->fullname + strlen (dirname) + 1; + ent->pdir = dir; + ent->next = 0; + ent->vfs_handle = 0; + +#define SET_FIELD(x, yup, nope) ( info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_##x ? (yup) : (nope) ) + /* size better be a valid field!!!! */ + ent->ino.size = SET_FIELD (SIZE, info->size, 0); + ent->ino.nlink = SET_FIELD (LINK_COUNT, info->link_count, 1); + ent->ino.mode = SET_FIELD (PERMISSIONS, info->permissions, 0777); + ent->ino.atime = SET_FIELD (ATIME, info->atime, time (0)); + ent->ino.mtime = SET_FIELD (MTIME, info->mtime, time (0)); + ent->ino.ctime = SET_FIELD (CTIME, info->ctime, time (0)); + ent->ino.blksize = SET_FIELD (IO_BLOCK_SIZE, info->io_block_size, 512); + ent->ino.blocks = + SET_FIELD (BLOCK_COUNT, info->block_count, (ent->ino.size + 511) / 512); +#undef SET_FIELD + + /* hackola - user web is 100 */ + ent->ino.uid = 100; + ent->ino.gid = 100; + + if (info->type == GNOME_VFS_FILE_TYPE_DIRECTORY) + { + ent->ino.mode |= S_IFDIR; + ent->ino.size = -1; /* FIXME: this is redundant with S_IFDIR */ + ent->data.dir.first = 0; + ent->data.dir.state = DIR_NEEDS_LOOKUP; + } + else + { + ent->ino.mode |= S_IFREG; + ent->data.file.vfs_pos = 0; + } + return ent; +} + + +static GVFS_DIRENT * +root_ent (GVFS_DIRENT * ent) +{ + MESSAGE("root_ent"); + while (ent->pdir != ent) + ent = ent->pdir; + return ent; +} + +static GVFS_DIRENT * +find_gvfs_dirent (GVFS_DIRENT * dir, char *name, int namelen) +{ + GVFS_DIRENT *ent; + MESSAGE("find_gvfs_dirent"); + ent = NULL; + if (dir->data.dir.state == DIR_NEEDS_LOOKUP) + do_gnome_vfs_readdir (dir); + ent = dir->data.dir.first; + while (ent) + { + if (strncmp (ent->name, name, namelen) == 0 && + strlen (ent->name) == namelen) + break; + ent = ent->next; + } + return ent; +} + + +static int +do_iread (unsigned char *buf, upp_repl * repl) +{ + upp_iread_s rcv; + upp_iread_r snd; + MESSAGE("do_iread"); + + decode_upp_iread_s (&rcv, buf); + + memset (&snd, 0, sizeof (snd)); + snd.handle = rcv.handle; + + if (rcv.handle.handle == DIRINO) + { + snd.ino.mode = 0444; + snd.ino.mode |= S_IFDIR | 0111; + snd.ino.mtime = snd.ino.ctime = snd.ino.atime = time (0); + snd.ino.nlink = 1; + } + else + { + GVFS_DIRENT *ent = (GVFS_DIRENT *) rcv.handle.handle; + memcpy (&snd.ino, &ent->ino, sizeof (up_inode)); + if (snd.ino.size == -1) + snd.ino.size = 0; + } + + repl->size = encode_upp_iread_r (&snd, buf) - buf; + MESSAGE("do_iread: done"); + return 0; +} + +static int +do_gnome_vfs_readdir (GVFS_DIRENT * dir) +{ + GnomeVFSFileInfo *info; + GList *list, *tmp; + gchar *root_uri, *uri; + GVFS_DIRENT **ent; + MESSAGE("do_gnome_vfs_readdir"); + + uri = strdup (dir->fullname); + list = NULL; + signal (SIGCHLD, SIG_DFL); + if (gnome_vfs_directory_list_load (&list, uri, + (GNOME_VFS_FILE_INFO_GET_MIME_TYPE | + GNOME_VFS_FILE_INFO_FORCE_FAST_MIME_TYPE + | GNOME_VFS_FILE_INFO_FOLLOW_LINKS), + NULL) == GNOME_VFS_OK && list != NULL) + { + tmp = list; + ent = &(dir->data.dir.first); + while (tmp != NULL) + { + info = (GnomeVFSFileInfo *) (tmp->data); + if (info->type != GNOME_VFS_FILE_TYPE_DIRECTORY && + info->type != GNOME_VFS_FILE_TYPE_REGULAR) + { + tmp = tmp->next; + continue; + } + if (strcmp (info->name, ".") == 0 || strcmp (info->name, "..") == 0) + { + tmp = tmp->next; + continue; + } + *ent = make_gvfs_dirent (dir, info); + + tmp = tmp->next; + ent = &((*ent)->next); + } + gnome_vfs_file_info_list_free (list); + } + else + fprintf (stderr, "do_gnome_vfs_readdir: list_load FAILED for %s\n", uri); + + signal (SIGCHLD, SIG_IGN); + free (uri); + dir->data.dir.state = DIR_OK; +} + +static int +do_lookup (unsigned char *buf, upp_repl * repl) +{ + upp_lookup_s rcv; + upp_lookup_r snd; + GVFS_DIRENT *ent; + MESSAGE("do_lookup"); + + decode_upp_lookup_s (&rcv, buf); + + ent = (GVFS_DIRENT *) rcv.dir.handle; + if (ent->ino.size != -1) + return ENOTDIR; + + if (rcv.name.nelem == 2 + && rcv.name.elems[0] == '.' && rcv.name.elems[1] == '.') + { + ent = ent->pdir; + } + else if (rcv.name.nelem != 1 || rcv.name.elems[0] != '.') + { + ent = find_gvfs_dirent (ent, rcv.name.elems, rcv.name.nelem); + } + FREE (rcv.name.elems); + if (!ent) + return ENOENT; + snd.handle.handle = (Ulong) ent; + + repl->size = encode_upp_lookup_r (&snd, buf) - buf; + + return 0; +} + +static int +do_readdir (unsigned char *buf, upp_repl * repl) +{ + upp_readdir_s rcv; + upp_readdir_r snd; + GVFS_DIRENT *ent; + MESSAGE("do_readdir"); + + decode_upp_readdir_s (&rcv, buf); + + ent = (GVFS_DIRENT *) rcv.dir.handle; + if (ent->ino.size != -1) + return ENOTDIR; + + snd.off = 0; + snd.name.nelem = 0; + + if (!rcv.off--) + { + snd.name.elems = "."; + } + else if (!rcv.off--) + { + snd.name.elems = ".."; + ent = ent->pdir; + } + else + { + if (ent->data.dir.state == DIR_NEEDS_LOOKUP) + do_gnome_vfs_readdir (ent); + ent = ent->data.dir.first; + while (ent && rcv.off--) + ent = ent->next; + if (ent) + snd.name.elems = ent->name; + } + + if (ent) + { + snd.off = 1; + snd.name.nelem = strlen (snd.name.elems); + snd.file.handle = (Ulong) ent; + } + + repl->size = encode_upp_readdir_r (&snd, buf) - buf; + + return 0; +} + +static int +gnome_vfs_handle_check (GnomeVFSHandle ** handle) +{ + GnomeVFSFileInfo info; + + MESSAGE("gnome_vfs_handle_check: top"); + + if (!handle || !*handle) + { + MESSAGE("gnome_vfs_handle_check: NULL handle"); + return 0; + } + + return 1; + +#if 0 + /* do not check the handle for now */ + /* probably a bad idea anyway */ + if (gnome_vfs_get_file_info_from_handle (*handle, &info, + GNOME_VFS_FILE_INFO_DEFAULT) == + GNOME_VFS_OK) + { + MESSAGE("gnome_vfs_handle_check: good handle"); + return 1; + } + + MESSAGE("gnome_vfs_handle_check: BAD handle, clearing it!"); + gnome_vfs_close (*handle); + *handle = 0; + return 0; +#endif +} + +static int +do_open (unsigned char *buf, upp_repl * repl) +{ + upp_open_s rcv; + GVFS_DIRENT *ent; + gchar *root_uri, *uri; + int ret; + + MESSAGE("do_open"); + decode_upp_open_s (&rcv, buf); + + ent = (GVFS_DIRENT *) rcv.file.handle; + MESSAGE(ent->fullname); + /* Directories are opened here, but read using _readdir instead of _read, + so all we do is return success! */ + if (ent->ino.size == -1) + return 0; + + /* is the vfs_handle already open and alive? */ + if (gnome_vfs_handle_check (&ent->vfs_handle)) + return 0; + + MESSAGE("do_open: handle is OK"); + uri = strdup (ent->fullname); + + if (uri == NULL) + return EFBIG; /* ????? what to return here? */ + + ret = EINVAL; + ent->data.file.vfs_pos = 0; + signal (SIGCHLD, SIG_DFL); + MESSAGE("do_open: now doing the gnome_vfs_open"); + if (gnome_vfs_open (&(ent->vfs_handle), uri, GNOME_VFS_OPEN_READ) == GNOME_VFS_OK) + { + ret = 0; + MESSAGE("do_open: FAILED in gnome_vfs_open"); + } + signal (SIGCHLD, SIG_IGN); + free (uri); + MESSAGE("do_open: ok"); + return ret; +} + +static int +do_close (unsigned char *buf, upp_repl * repl) +{ + upp_close_s rcv; + GVFS_DIRENT *ent; + MESSAGE("do_close"); + + decode_upp_close_s (&rcv, buf); + + ent = (GVFS_DIRENT *) rcv.file.handle; + if (ent->ino.size == -1) + return 0; + + if (ent->vfs_handle == 0) + return 0; + + gnome_vfs_close (ent->vfs_handle); + ent->vfs_handle = 0; + ent->data.file.vfs_pos = 0; + return 0; + +} + +static int +reopen_gnome_vfs (GVFS_DIRENT * ent, GnomeVFSOpenMode mode) +{ + fprintf(stderr, "reopen_gnome_vfs: %s : mode=%d\n", ent->fullname, (int)mode); + gnome_vfs_close (ent->vfs_handle); + signal (SIGCHLD, SIG_DFL); + if (gnome_vfs_open (&(ent->vfs_handle), ent->fullname, mode) != GNOME_VFS_OK) + { + signal (SIGCHLD, SIG_IGN); + return EPERM; + } + signal (SIGCHLD, SIG_IGN); + ent->data.file.vfs_pos = 0; + return 0; +} + +static int +fake_o_seek (GVFS_DIRENT * ent, GnomeVFSFileSize seekTo) +{ +#define SEEK_BUF_SIZE 65536 +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + GnomeVFSFileSize seekActual; + int seekNum; + char *seekBuf = malloc (SEEK_BUF_SIZE); + MESSAGE("fake_o_seek"); + + while (ent->data.file.vfs_pos < seekTo) + { + seekNum = MIN (SEEK_BUF_SIZE, seekTo - ent->data.file.vfs_pos); + if (gnome_vfs_read (ent->vfs_handle, seekBuf, seekNum, + &seekActual) != GNOME_VFS_OK) + { + free (seekBuf); + return EPERM; + } + ent->data.file.vfs_pos += seekActual; + } + free (seekBuf); + return 0; +#undef SEEK_BUF_SIZE +#undef MIN +#undef MAX +} + +static int +do_create (unsigned char *buf, upp_repl * repl) +{ + upp_create_s rcv; + upp_create_r snd; + GVFS_DIRENT *dir; + GVFS_DIRENT *ent; + char *newuri; + GnomeVFSHandle *handle; + int ret; + MESSAGE("do_create"); + + decode_upp_create_s (&rcv, buf); + dir = (GVFS_DIRENT *) rcv.dir.handle; + + ent = find_gvfs_dirent (dir, rcv.name.elems, rcv.name.nelem); + if (ent) + { + snd.file.handle = (Ulong) ent; + repl->size = encode_upp_create_r (&snd, buf) - buf; + return 0; + } + + newuri = malloc (rcv.name.nelem + strlen (dir->fullname) + 2); + strcpy (newuri, dir->fullname); + strcat (newuri, "/"); + strncat (newuri, rcv.name.elems, rcv.name.nelem); + newuri[rcv.name.nelem + strlen (dir->fullname) + 1] = 0; + + if (rcv.mode & S_IFDIR) + { + fprintf(stderr, "do_create: gnome_vfs_make_directory\n"); + ret = gnome_vfs_make_directory (newuri, 0777); + if (ret != GNOME_VFS_OK) + { + fprintf(stderr, "gnome_vfs_make_directory failed for %s\n", newuri); + free (newuri); + return EPERM; + } + } + else + { + fprintf(stderr, "do_create: gnome_vfs_create\n"); + ret = gnome_vfs_create (&handle, newuri, GNOME_VFS_OPEN_WRITE, 1, 0666); + if (ret != GNOME_VFS_OK) + { + fprintf(stderr, "gnome_vfs_create failed for %s\n", newuri); + free (newuri); + return EPERM; + } + } + free (newuri); + + dir->data.dir.state = DIR_NEEDS_LOOKUP; + ent = find_gvfs_dirent (dir, rcv.name.elems, rcv.name.nelem); + if (ent == NULL) + return ENOENT; + if (handle) + ent->vfs_handle = handle; + snd.file.handle = (Ulong) ent; + repl->size = encode_upp_create_r (&snd, buf) - buf; + return 0; +} + +static int +do_read (unsigned char *mbuf, upp_repl * repl) +{ + upp_read_s rcv; + upp_read_r snd; + GVFS_DIRENT *ent; + int rc; + GnomeVFSFileSize fsize; + char *tmpbuf; + int ret; + MESSAGE("do_read"); + + snd.data.nelem = 0; + + decode_upp_read_s (&rcv, mbuf); + + ent = (GVFS_DIRENT *) rcv.file.handle; + if (ent->ino.size == -1) + return EISDIR; + + if (!gnome_vfs_handle_check (&ent->vfs_handle)) + return EBADF; + + if ((unsigned long long) rcv.off < ent->data.file.vfs_pos) + { + ret = reopen_gnome_vfs (ent, GNOME_VFS_OPEN_READ); + if (ret) + return ret; + } + + if ((unsigned long long) rcv.off > ent->data.file.vfs_pos) + { + ret = fake_o_seek (ent, (unsigned long long) rcv.off); + if (ret) + return ret; + } + + tmpbuf = malloc (rcv.size); + gnome_vfs_read (ent->vfs_handle, tmpbuf, rcv.size, + (GnomeVFSFileSize *) & (snd.data.nelem)); + snd.data.elems = tmpbuf; + ent->data.file.vfs_pos += snd.data.nelem; + + repl->size = encode_upp_read_r (&snd, mbuf) - mbuf; + free (tmpbuf); + + return 0; +} + +static int +do_write (unsigned char *mbuf, upp_repl * repl) +{ + upp_write_s rcv; + upp_write_r snd; + GVFS_DIRENT *ent; + int ret; + MESSAGE("do_write"); + + decode_upp_write_s (&rcv, mbuf); + + ent = (GVFS_DIRENT *) rcv.file.handle; + + if (ent->ino.size == -1) + return EISDIR; + + if (!gnome_vfs_handle_check (&ent->vfs_handle)) + return EBADF; + if (gnome_vfs_handle_get_open_mode (ent->vfs_handle) != + GNOME_VFS_OPEN_WRITE) + { + fprintf(stderr, "do_write: mode!=GNOME_VFS_OPEN_WRITE, reopening\n"); + ret = reopen_gnome_vfs (ent, GNOME_VFS_OPEN_WRITE); + if (ret) + return ret; + } + + if ((unsigned long long) rcv.off != ent->data.file.vfs_pos) + { + fprintf (stderr, + "do_write: only SEQUENTIAL writes allowed for now!!!\n"); + return EPERM; + } +#if 0 + if ((unsigned long long) rcv.off > ent->data.file.vfs_pos) + { + fprintf (stderr, "do_write: need to seek ahead: %ld -> %d\n", + ent->data.file.vfs_pos, rcv.off); + ret = fake_o_seek (ent, (unsigned long long) rcv.off); + if (ret) + return ret; + } +#endif + + if (gnome_vfs_write (ent->vfs_handle, + rcv.data.elems, + rcv.data.nelem, + (GnomeVFSFileSize *) & snd.wrote) != GNOME_VFS_OK) + { + fprintf (stderr, "error on gnome_vfs_write: pos=%d amt=%d wrote=%d\n", + ent->data.file.vfs_pos, rcv.data.nelem, snd.wrote); + return EPERM; + } + ent->data.file.vfs_pos += snd.wrote; + + repl->size = encode_upp_write_r (&snd, mbuf) - mbuf; + return 0; +} + +static int +do_mount (unsigned char *buf, upp_repl * repl) +{ + upp_mount_r snd; + MESSAGE("do_mount"); + + snd.root.handle = (Ulong) root; + repl->size = encode_upp_mount_r (&snd, buf) - buf; + /* INIT */ + /* kch: has no fucking clue why this is done 2x */ + repl->size = encode_upp_mount_r (&snd, buf) - buf; + return 0; +} + +static int +do_truncate (unsigned char *buf, upp_repl * repl) +{ + upp_truncate_s rcv; + GVFS_DIRENT *ent; + MESSAGE("do_truncate"); + + decode_upp_truncate_s(&rcv, buf); + ent = (GVFS_DIRENT *)rcv.file.handle; + + fprintf(stderr, "truncate called for file: %s\n", ent->fullname); + if (gnome_vfs_truncate(ent->fullname, rcv.size)!= GNOME_VFS_OK) + { + /* for our purposes, truncate never necessary */ + /* famous last werdz */ + return 0; + } + + return 0; +} + +static int +do_unlink (unsigned char *buf, upp_repl *repl) +{ + upp_unlink_s rcv; + GVFS_DIRENT *dir, *ent; + + decode_upp_unlink_s (&rcv, buf); + dir = (GVFS_DIRENT *) rcv.dir.handle; + ent = find_gvfs_dirent (ent, rcv.name.elems, rcv.name.nelem); + fprintf(stderr, "for now, I am IGNORING unlink for file: %s\n", ent->fullname); + return 0; +} + + +static VfsOperation gvfs_optab[] = { + do_create, /* create */ + do_lookup, /* lookup */ + do_close, /* close */ + do_read, /* read */ + do_write, /* write */ + do_truncate, /* truncate */ + NULL, /* fsync */ + do_readdir, /* readdir */ + NULL, /* link */ + do_unlink, /* unlink */ + NULL, /* symlink */ + NULL, /* readlink */ + NULL, /* followlink */ + do_mount, /* mount */ + NULL, /* umount */ + do_iread, /* iread */ + NULL, /* iwrite */ + NULL, /* statfs */ + NULL, /* iput */ + do_open, /* open */ + NULL, /* permission */ + NULL, /* rename */ + NULL, /* multireaddir */ + NULL, /* notify_change */ + NULL /* inode_valid */ +}; + + +int +main (int argc, char **argv) +{ + int infd = 0; + int outfd = 1; + int c; + char *uri; + GnomeVFSFileInfo info; + MESSAGE("main"); + + gnome_vfs_init (); + while ((c = getopt (argc, argv, "i:o:m:")) != EOF) + switch (c) + { + case 'i': + infd = atoi (optarg); + break; + case 'o': + outfd = atoi (optarg); + break; + case 'm': + mpoint = optarg; + break; + default: + fprintf (stderr, "%s: bad option\n", argv[0]); + return 1; + } + + if (optind != argc - 1) + { + fprintf (stderr, "%s: no URI given\n", argv[0]); + return 1; + } + + uri = malloc (strlen (argv[optind]) + 2); + strcpy (uri, argv[optind]); +#if 0 + if (*(uri + strlen (uri) - 1) != '/') + strcat (uri, "/"); +#endif + + memset (&info, 0, sizeof (info)); + if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_DEFAULT) != + GNOME_VFS_OK) + { + fprintf (stderr, "%s: bad URI given: %s\n", argv[0], uri); + free (uri); + return 1; + } + if (make_root_inode (uri, &info)) + { + free (uri); + return 1; + } + free (uri); + signal (SIGCHLD, SIG_IGN); + run (gvfs_optab, outfd, infd); + gnome_vfs_shutdown (); + return 0; +} + +static int +make_root_inode (char *uri, GnomeVFSFileInfo * info) +{ + MESSAGE("make_root_inode"); + root = malloc (sizeof (GVFS_DIRENT) + strlen (uri) + 1); + if (!root) + { + fprintf (stderr, "not enough memory to create root inode... LATER!\n"); + return 1; + } + + root->next = 0; + root->vfs_handle = 0; + root->ino.size = -1; + root->ino.nlink = 1; /* 2? */ + root->ino.mode = S_IFDIR | 0777; + root->ino.atime = time (0); + root->ino.mtime = time (0); + root->ino.ctime = time (0); + root->ino.blksize = 512; + root->ino.blocks = 0; + root->ino.uid = 100; + root->ino.gid = 100; + root->pdir = root; + root->data.dir.first = 0; + root->data.dir.state = DIR_NEEDS_LOOKUP; + + if (info->type & GNOME_VFS_FILE_TYPE_DIRECTORY) + { + strcpy (root->fullname, uri); + root->name = root->fullname; + fprintf (stderr, "normal URI\n"); + } + else if (info->type & GNOME_VFS_FILE_TYPE_REGULAR) + { + GVFS_DIRENT *ent; + char *tmp; + + fprintf (stderr, "file URI (doing some funky shit)\n"); + tmp = strrchr (uri, '/'); + if (tmp == NULL) + { + free (root); + return 1; + } + tmp++; + *tmp = 0; + strcpy (root->fullname, uri); + root->name = root->fullname; + ent = make_gvfs_dirent (root, info); + if (ent) + { + root->data.dir.first = ent; + root->data.dir.state = DIR_OK; + } + } + + return 0; +} Added: trunk/filesystems/gvfs/vfsbase.c ============================================================================== --- trunk/filesystems/gvfs/vfsbase.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/gvfs/vfsbase.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,242 @@ +/* + * Portions of this work Copyright (C) 2001 Oracle Corporation + * + * This 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 software 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 library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include + +#include "vfsbase.h" + +/* No point in this being in a seperate file. */ +#include + +int +myread (int fd, void *buf, int sz) +{ + int rd = 0; + int ret; + + while (sz > 0) + { + ret = read (fd, buf, sz); + + if (ret == -1) + { + if (errno == EINTR) + continue; + + perror ("myread"); + exit (1); + } + + if (ret == 0) + break; + + sz -= ret; + buf += ret; + rd += ret; + } + + return rd; +} + +int +mywrite (int fd, const void *buf, int sz) +{ + int wr = 0; + int ret; + + while (sz > 0) + { + ret = write (fd, buf, sz); + + if (ret == -1) + { + if (errno == EINTR) + continue; + if (errno == EPIPE) + { + fprintf (stderr, "Eeeeek! A broken pipe on write! "); + fprintf (stderr, "wrote: %d/%d bytes\n", wr, sz); + return -1; + } + FAIL ("write"); + exit (1); + } + + if (ret == 0) + { + fprintf (stderr, "write wrote 0 bytes\n"); + break; + } + + sz -= ret; + buf += ret; + wr += ret; + } + + return wr; +} + +int +readpkt (int fd, up_preamble * pre, unsigned char *buf) +{ + int presz = sizeof_up_preamble (pre); + unsigned int rd; + unsigned char pbuf[presz]; + + memset (pbuf, 0, sizeof (pbuf)); + + rd = myread (fd, pbuf, presz); + if (rd != presz) + { + if (rd == 0) + return 0; + if (rd > 0) + fprintf (stderr, "readpkt, incomplete read (%d, not %d)\n", + rd, presz); + perror ("readpkt, header read"); + return -1; + } + + decode_up_preamble (pre, pbuf); + + if (pre->isreq != UP_ENQ && pre->isreq != UP_REQ) + fprintf (stderr, "pre->isreq = %d\n", pre->isreq); + + if (pre->version != UP_VERSION) + { + fprintf (stderr, "Version mismatch: us=%d them=%d\n", + UP_VERSION, pre->version); + return -1; + } + + if (pre->size != 0) + { + if (myread (fd, buf, pre->size) != pre->size) + { + perror ("readpkt, body read"); + return -1; + } + } + + return 1; +} + +int +writepkt (int fd, upp_repl * repl, const unsigned char *buf) +{ + int replsz = sizeof_upp_repl (repl); + unsigned char pbuf[replsz]; + unsigned int wr; + unsigned char *p; + + assert (repl->version == UP_VERSION); + assert (repl->isreq == UP_REPL); + + p = encode_upp_repl (repl, pbuf); + + assert (replsz == p - pbuf); + + wr = mywrite (fd, pbuf, replsz); + if (wr != replsz) + { + perror ("writepkt, header write"); + return -1; + } + + if (repl->size > 0 && repl->err_no == 0) + { + if (mywrite (fd, buf, repl->size) != repl->size) + { + perror ("writepkt, body write"); + return -1; + } + } + + return 1; +} + +void +genpkt (upp_repl * repl, int seq, up_ops op) +{ + repl->version = UP_VERSION; + repl->seq = seq; + repl->op = op; + repl->isreq = 0; + repl->size = 0; + repl->err_no = 0; +} + +void +run (VfsOperation optab[], int wr, int rd) +{ + up_preamble pre; + upp_repl repl; + unsigned char buf[4096]; + int error, ret1, ret2; + + while ((ret1=readpkt (rd, &pre, buf)) == 1) + { + genpkt (&repl, pre.seq, pre.op); + + if ((unsigned int) pre.op >= VFS_OPTAB_SIZE || + optab[(unsigned int) pre.op] == NULL) + { + fprintf(stderr, "run: some op i don't handle: %d\n", pre.op); + error = ENOSYS; + } + else + { + VfsOperation op = optab[pre.op]; + error = (pre.isreq == UP_ENQ ? 0 : (*op) (buf, &repl)); + } + + repl.err_no = error; + if (error != 0) + repl.size = 0; + + if ((ret2=writepkt (wr, &repl, buf)) != 1) + { + fprintf(stderr, "run: writepkt returned %d exiting\n", ret2); + break; + } + } + if (ret1!=1) + fprintf(stderr, "run: readpkt returned %d exiting\n", ret1); +} Added: trunk/filesystems/gvfs/gvfs.h ============================================================================== --- trunk/filesystems/gvfs/gvfs.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/gvfs/gvfs.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,69 @@ +/* + * Portions of this work Copyright (C) 2001 Oracle Corporation + * + * This 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 software 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 library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef GVFS_H +#define GVFS_H + +#include "vfsbase.h" + +/* static VfsOperation do_mount, do_iread, do_lookup, do_readdir; +static VfsOperation do_open, do_close, do_read; */ + +typedef enum +{ + DIR_NEEDS_LOOKUP, + DIR_OK +} +gvfs_dir_state; + +typedef struct tagDIRENT GVFS_DIRENT; +struct tagDIRENT +{ + GVFS_DIRENT *next; + GVFS_DIRENT *pdir; /* The directory to which this belongs, or self for root */ + up_inode ino; + GnomeVFSHandle *vfs_handle; + union + { + struct + { + GnomeVFSFileSize vfs_pos; + } + file; + struct + { + gvfs_dir_state state; + GVFS_DIRENT *first; + } + dir; + } + data; + char *name; + char fullname[1]; +}; + +/* +int a_open (ARC_DIRENT *); +int a_close (ARC_DIRENT *); +int a_read (ARC_DIRENT *, long, long, unsigned long *, unsigned char **); +ARC_DIRENT *arc_read (const char *); +*/ + +#endif /* GVFS_H */ Added: trunk/filesystems/gvfs/Makefile ============================================================================== --- trunk/filesystems/gvfs/Makefile 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/gvfs/Makefile 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,40 @@ +CC = gcc +CFLAGS = -DDEBUG -g -I../../kernel -I/usr/local/userfs/include -I/usr/local/userfs/lib/vfs/include -D_REENTRANT -I/home/manish/nicstuff/gnome-vfs-1.0.1 `pkg-config glib-2.0 --cflags` +CPPFLAGS = #-DDEBUG +LDFLAGS = -g -s -L/usr/local/userfs/lib -lgnomevfs -lpthread -L/usr/lib -L/usr/X11R6/lib -rdynamic `pkg-config glib-2.0 --libs` + +NAME = gvfs +SRCS = gvfsops.c vfsbase.c +INC = gvfs.h vfsbase.h +DISTS = $(SRCS) $(INC) README Makefile + +$(NAME) : $(SRCS:%.o=%.c) + +gvfs : gvfsops.o vfsbase.o + gcc -DDEBUG $(CFLAGS) $(LDFLAGS) vfsbase.o gvfsops.o -o gvfs + +.PHONY : dist dep clean realclean spotless + +dep : .depend +.depend : $(SRCS) $(INC) + $(CC) $(CFLAGS) -MM *.c > .depend + +dist : $(DISTS) + rm -rf /tmp/$(NAME) + mkdir /tmp/$(NAME) + cp -a $(DISTS) /tmp/$(NAME) + (cd /tmp; tar cfvz - $(NAME)) >$(NAME).tar.gz + rm -rf /tmp/$(NAME) + +clean : + rm -f *.o core *~ *.orig *.rej gvfs + +realclean : clean + rm -rf gvfs + +spotless : realclean + rm -f .depend + +ifeq (.depend,$(wildcard .depend)) +include .depend +endif Added: trunk/filesystems/homer/homer.h ============================================================================== --- trunk/filesystems/homer/homer.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/homer/homer.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,16 @@ +// -*- C++ -*- + +#include "Filesystem.h" + +class password; + +class homer:public Filesystem +{ +protected: + int Enquire(up_ops op); + + int do_mount(const up_preamble &, upp_repl &, upp_mount_r &); + +public: + homer(const char *, password *); +}; Added: trunk/filesystems/homer/password.cc ============================================================================== --- trunk/filesystems/homer/password.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/homer/password.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,76 @@ +// -*- C++ -*- +// Passwords, specifically for ``homer'' + +#include "password.h" +#include +#include + +const pwent * +password::entry(int ino) +{ + pwent *pwe; + + for(pwe = pwlist; pwe != NULL; pwe = pwe->next) + if (pwe->ino == ino) + return pwe; + return NULL; +} + +const pwent * +password::entry(const char *name) +{ + pwent *pwe; + + for(pwe = pwlist; pwe != NULL; pwe = pwe->next) + if (strcmp(name, pwe->name) == 0) + return pwe; + return NULL; +} + +const pwent * +password::entry(const char *name, int len) +{ + pwent *pwe; + + for(pwe = pwlist; pwe != NULL; pwe = pwe->next) + if (strncmp(name, pwe->name, len) == 0) + return pwe; + return NULL; +} + +password::password() +{ + passwd *pw; + pwent *pwe; + + update = time(0); + pwlist = NULL; + ino = 0; + while((pw = getpwent()) != NULL) + { + pwe = new pwent; + + pwe->dir = strdup(pw->pw_dir); + pwe->name = strdup(pw->pw_name); + pwe->uid = pw->pw_uid; + pwe->gid = pw->pw_gid; + pwe->ino = ino++; + pwe->next = pwlist; + pwlist = pwe; + } + endpwent(); +} + +password::~password() +{ + pwent *next; + + for(; pwlist != NULL; pwlist = next) + { + next = pwlist->next; + free(pwlist->dir); + free(pwlist->name); + delete pwlist; + } +} + Added: trunk/filesystems/homer/Makefile ============================================================================== --- trunk/filesystems/homer/Makefile 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/homer/Makefile 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,22 @@ +TOP=../.. +include $(TOP)/rules +FLAGS=-I$(TOP)/kernel -I$(TOP)/lib -I$(TOP)/genser +CXXFLAGS = $(FLAGS) +CFLAGS = $(FLAGS) + +LDFLAGS = $(PROF) +PROGS=homer + +HOMEOBJ = homer.o password.o + +all:: $(PROGS) + +homer: $(HOMEOBJ) $(DEPLIBUSERFS) + $(CXX) $(LDFLAGS) -o $@ $(HOMEOBJ) $(LIBUSERFS) + +clean:: dummy + rm -f *.o *~ core $(PROGS) + +dep depend:: + $(CXX) $(CXXFLAGS) -M *.cc > .depend + Added: trunk/filesystems/homer/homer.cc ============================================================================== --- trunk/filesystems/homer/homer.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/homer/homer.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,206 @@ +// -*- C++ -*- +// Find home +// A simple user process filesystem. This one sets up a dir full +// of symlinks pointing to everyone in /etc/passwd's home dirs. +// +// This program is distributed under the terms of the +// Free Software Foundation General Public Licence. +// Copyright Jeremy Fitzhardinge 1993 + +#include +#include +#include +#include +#include "homer.h" +#include "password.h" +#include +#include +#include +#include "dbg.h" + +// Choose an inode number for the filesystem. We use the line +// number in /etc/passwd as the inode, starting from zero, so have +// something high to avoid it. This can be bigger, but it gets +// unwieldy. +const Handle DIRINO = 65534; + +// This is all the operations the filesystem as a whole will accept +// from the kernel. This is done this way so that if the kernel +// asks about completely new operations we can still say "no". +int +homer::Enquire(up_ops op) +{ + LOG("enq"); + switch(op) + { + case userfs_up_mount: + case userfs_up_iread: + case userfs_up_readdir: + case userfs_up_multireaddir: + case userfs_up_lookup: + case userfs_up_readlink: +// case userfs_up_unlink: + return 0; + + default: + // Rather than just failing, ask our base class + return Filesystem::Enquire(op); + } +} + +// Just another constructor for the generic directory inode +// After construction everything is handled by the base class +class dirino:public DirInode +{ +public: + dirino::dirino(Filesystem &, Handle, password *); +}; + +// A symlink to the home dir +// This has most of the work in it, but there isn't very much +// to do. +class nameino:public SimpleInode +{ + char *dir; + int dirlen; + +protected: + int do_readlink(const up_preamble &, upp_repl &, + const upp_readlink_s &, upp_readlink_r &); +public: + nameino(Filesystem &, Handle, uid_t, gid_t, char *); + virtual ~nameino(); +}; + +nameino::nameino(Filesystem &fs, Handle hand, + uid_t u, gid_t g, char *d) + : SimpleInode(fs, hand) +{ + uid = u; + gid = g; + dir = strdup(d); + size = dirlen = strlen(d); + mode = S_IFLNK | 0777; + atime = ctime = mtime = time(0); +} + +nameino::~nameino() +{ + free(dir); +} + +// Make a dir entry for each line in the passwd file, and init our +// own inode values. +dirino::dirino(Filesystem &fs, Handle h, password *pw) + :DirInode(fs, h, this) +{ + const pwent *pwe; + + pwe = pw->getlist(); + + for (; pwe != NULL; pwe = pwe->next) + { + Inode *ino = findino(pwe->ino); + link(pwe->name, ino); + } + + uid = getuid(); + gid = getgid(); + mode = S_IFDIR | 0555; + mtime = ctime = atime = time(0); +} + +// Constructor for the filesystem. +// This creates all the filesystem's inodes from the password file, +// then creates a single directory to give them names. +homer::homer(const char *mpoint, password *pw) : Filesystem(mpoint) +{ + const pwent *pwe = pw->getlist(); + + for(; pwe != NULL; pwe = pwe->next) + new nameino(*this, pwe->ino, pwe->uid, pwe->gid, pwe->dir); + + new dirino(*this, DIRINO, pw); +} + +int +homer::do_mount(const up_preamble &pre, upp_repl &repl, + upp_mount_r &ret) +{ + ret.root.handle = DIRINO; + return 0; +} + +int +nameino::do_readlink(const up_preamble &pre, upp_repl &repl, + const upp_readlink_s &arg, upp_readlink_r &ret) +{ + LOG("readlink"); + + atime = time(0); + ret.name.elems = (__s8 *)dir; + ret.name.nelem = dirlen; + + return 0; +} + +const char *mpoint = NULL; + +int +main(int argc, char *argv[]) +{ + int infd = 0; + int outfd = 1; + int c; + + LOG("Starting"); + +#ifdef DEBUG + printf("pid=%d\n", getpid()); + getchar(); +#endif + + // Parse the command line options from muserfs + while((c = getopt(argc, argv, "i:o:m:")) != EOF) + switch(c) + { + case 'i': + infd = atoi(optarg); + break; + + case 'o': + outfd = atoi(optarg); + break; + + case 'm': + mpoint = optarg; + break; + + default: + fprintf(stderr, "%s: bad option\n", argv[0]); + exit(1); + } + + signal(SIGCHLD, SIG_IGN); + + LOG("GOING to run"); + + // Create password file class + password pwfile; + + // Create filesystem + homer homefs(mpoint, &pwfile); + + // Create communications with kernel + Comm comm(homefs, outfd, infd); + + fprintf(stderr, "now communicating with kernel\n"); + + // Run -- doesn't return until EOF or error + if (comm.Run() == -1) + fprintf(stderr, "Something went wrong!\n"); + + LOG("Stop"); + + return 0; +} Added: trunk/filesystems/mailfs/mailfs.cc ============================================================================== --- trunk/filesystems/mailfs/mailfs.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/mailfs/mailfs.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,119 @@ +// -*- C++ -*- + +// Example filesystem + +#pragma implementation + +// Misc headers +#include + +// Filesystem related headers +#include +#include "mailfs.h" +//#include "mailfile.h" +#include "maildir.h" + +// A simple constructor for the filesystem +// All this does is pass the arguments to the base class +// and initialize the inode handle counter. +// The counter is for generating unique handles as required. +// The mechanism used is very simple, because there is a bounded +// number of inodes. +mailfs::mailfs(const char *mpoint, const char *mail) + : Filesystem(mpoint) +{ + hcount=2; + mail_file = mail; + ifile = new ifstream(mail); +} + +mailfs::~mailfs() +{ + if(ifile) + delete ifile; +} + +// Declare to the kernel which operations we will support. +int +mailfs::Enquire(up_ops op) +{ + switch(op) + { + case up_mount: + case up_iread: + case up_readdir: + case up_multireaddir: + case up_lookup: + case up_read: + case up_readlink: + case up_rename: + case up_unlink: + return 0; + default: + break; + } + return Filesystem::Enquire(op); +} + +// Do the mount. This simply returns the handle of the root +// directory and creates the directory. +int +mailfs::do_mount(const up_preamble &, upp_repl &, + upp_mount_r &ret) +{ + Inode *root = new mailtopdir(*this, genhand(), NULL); + ret.root.handle = root->gethandle(); + return 0; +} + +// Parse the arguments from muserfs and construct the filesystem +// and communications. +int +main(int argc, char **argv) +{ + GetOpt getopt(argc, argv, "i:o:m:f:"); + int optch, err = 0; + int infd, outfd; + const char *mpoint = ""; + const char *mfile; + + mfile = getenv("MAIL"); + infd = outfd = -1; + while((optch = getopt()) != EOF) + switch(optch) + { + case 'i': + infd = atoi(getopt.optarg); + break; + case 'o': + outfd = atoi(getopt.optarg); + break; + case 'm': + mpoint = getopt.optarg; + break; + case 'f': + mfile = getopt.optarg; + break; + default: + err++; + } + + if (err) + { + fprintf(stderr, "Usage: %s -i infd -o outfd -m mpoint -f mailfile\n", + argv[0]); + exit(1); + } + +#if 0 && DEBUG + printf("pid=%d, return to cont\n", getpid()); + getchar(); +#endif + mailfs efs(mpoint, mfile); + Comm comm(efs, outfd, infd); + + if (comm.Run() == -1) + fprintf(stderr, "%s: Comm.Run() failed!\n", argv[0]); + + return 0; +} Added: trunk/filesystems/mailfs/mailfs.h ============================================================================== --- trunk/filesystems/mailfs/mailfs.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/mailfs/mailfs.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,33 @@ +// -*- C++ -*- + +// Example filesystem + +#ifndef _MAILFS_H_ +#define _MAILFS_H_ + +#include +#include +#include + +#pragma interface + +class mailfs:public Filesystem +{ + Handle hcount; + String mail_file; + ifstream *ifile; + + int Enquire(up_ops); + + int do_mount(const up_preamble &, upp_repl &, upp_mount_r &); + +public: + mailfs(const char *, const char *); + ~mailfs(); + + Handle genhand() { return hcount++; } + String mail() { return mail_file; }; + ifstream *file() { return ifile; }; +}; + +#endif /* _MAILFS_H_ */ Added: trunk/filesystems/mailfs/maillink.cc ============================================================================== --- trunk/filesystems/mailfs/maillink.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/mailfs/maillink.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,29 @@ +// -*- C++ -*- + +#pragma implementation + +#include "maillink.h" + +#include +#include + +maillink::maillink(Filesystem &fs, Handle h, String str) + : SimpleInode(fs, h), str(str) +{ + uid = getuid(); + gid = getgid(); + mode = S_IFLNK | 0777; + size = str.length(); +// atime = ctime = mtime = time(0); +} + +int +maillink::do_readlink(const up_preamble &, upp_repl &, + const upp_readlink_s &arg, upp_readlink_r &ret) +{ +// atime = time(0); + + ret.name.elems = (char *)str.chars(); + ret.name.nelem = str.length(); + return 0; +} Added: trunk/filesystems/mailfs/maildir.cc ============================================================================== --- trunk/filesystems/mailfs/maildir.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/mailfs/maildir.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,139 @@ +// -*- C++ -*- + +#pragma implementation + +#include "maildir.h" +#include "mailfile.h" +#include "maillink.h" +#include "mailfs.h" +#include "mail.h" + +#include +#include + +maildir::maildir(mailfs &fs, Handle h, Inode *p, time_t t) + : DirInode(fs, h, p) +{ + uid = getuid(); + gid = getgid(); + mode = S_IFDIR | 0555; + ifile = NULL; + atime = ctime = mtime = t; +} + +maildir::maildir(mailfs &fs, Handle h, Inode *p, ifstream *ifile, streampos start, int l, time_t t) + : DirInode(fs, h, p), start(start), ifile(ifile) +{ + uid = getuid(); + gid = getgid(); + mode = S_IFDIR | 0555; + length = l; + atime = ctime = mtime = t; +} + +// This constructs the entire directory heirachy for this +// filesystem. +mailtopdir::mailtopdir(mailfs &fs, Handle h, Inode *p) + : maildir(fs, h, p, time(NULL)) +{ +// String mailfn = getenv("MAIL"); + puts("Parsing... "); + mail nmail(fs.file()); + puts("done"); + int i, iform = 0; + Pix a, b; + String name; + char num[16], form[16]; +// DLList &m; +// DLList
&hdr; + DirInode *d; + Inode *f; + ifstream *file; + streampos offset; + int len, body; + time_t tm; + + if(iform > 0) + sprintf(form, "%%0%d.", iform); + else + strcpy(form, "%d."); +// nmail.disp(); + DLList &m = nmail.contents(); + for(i = 1, a = m.first(); a != NULL; m.next(a), i++) + { + sprintf(num, form, i); + name = num + m(a).name(); + + m(a).report(file, offset, len, body, tm); + d = new maildir(fs, fs.genhand(), this, file, offset, len, tm); + link(name, d); + f = new mailfile(fs, fs.genhand(), file, offset + body, len - body, tm); + d->link("body.txt", f); + f = new mailfile(fs, fs.genhand(), file, offset, len, tm); + d->link(".complete.txt", f); + + DLList
&hdr = *(m(a).headers()); + for(b = hdr.first(); b != NULL; hdr.next(b)) + { + hdr(b).report(file, offset, len); + f = new mailfile(fs, fs.genhand(), file, offset, len, tm); + d->link(hdr(b).name(), f); + } + } + puts("MAILFS ready"); + +/* + link("test1", new mailfile(fs, fs.genhand(), "Hello, world!\n")); + link("test2", new mailfile(fs, fs.genhand(), "Wooba wooba...\n")); + + link("link1", new maillink(fs, fs.genhand(), "/usr/bin")); + + DirInode *d1 = new maildir(fs, fs.genhand(), this); + DirInode *d2 = new maildir(fs, fs.genhand(), this); + + link("dir1", d1); + link("dir2", d2); + + Inode *f1 = new mailfile(fs, fs.genhand(), "File with multiple names\n"); + d1->link("linked-file", f1); + d2->link("another-link", f1); + + Inode *f2 = new mailfile(fs, fs.genhand(), "Piffle woodle.\n"); + d2->link("strange", f2); +*/ +} + +int +maildir::do_read(const up_preamble &pre, upp_repl &repl, + const upp_read_s &arg, upp_read_r &ret) +{ + int sz, off; // legth of returned bunch + // Bunch is requested by kernel. Kernel asks for bunch of + // arg.size bytes starting from arg.off + + if(!ifile) + return EISDIR; + +// ret.data.nelem = 0; +// return 0; + + // i = arg.file; + off = arg.off; + sz = arg.size; + // l = arg.ctok; + + if(off >= length) + { + ret.data.nelem = 0; // send EOF + } + else + { + if(off + sz > length) + sz = length - off; + ret.data.alloc(ret.data.nelem = sz); + ifile->seekg(start + off); + ifile->read(ret.data.elems, sz); + } + return 0; +} + Added: trunk/filesystems/mailfs/TODO ============================================================================== --- trunk/filesystems/mailfs/TODO 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/mailfs/TODO 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,15 @@ +[x] 1. cut down RAM usage +[x] 2. Date -> mtime +[x] 3. Replace trouble chars with _ +[x] 4. use zero leading numbers. +[x] 5. Take "From:" name with more sense - care: no "/"! +[x] 6. Use Content-Length to determine how much is in body.txt +[x] 7. Use Lines to determine number of lines in the body.txt +[ ] 8. highlighted file without .txt +[ ] 9. Option for zero-leading numbers. +[x] 10. Update man page +[ ] 11. Safe error if mailfile doesn't exist +[x] 12. Speed up the parser +[ ] 13. Track mail changes +[ ] 14. Send mail +[ ] 15. Read RFC822 Added: trunk/filesystems/mailfs/maillink.h ============================================================================== --- trunk/filesystems/mailfs/maillink.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/mailfs/maillink.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,22 @@ +// -*- C++ -*- + +#ifndef _MAILLINK_H_ +#define _MAILLINK_H_ + +#include +#include +#include + +#pragma interface + +class maillink:public SimpleInode +{ + String str; + + public: + maillink(Filesystem &fs, Handle h, String str); + do_readlink(const up_preamble &, upp_repl &, + const upp_readlink_s &, upp_readlink_r &); +}; + +#endif /* _MAILLINK_H_ */ Added: trunk/filesystems/mailfs/mailfile.cc ============================================================================== --- trunk/filesystems/mailfs/mailfile.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/mailfs/mailfile.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,47 @@ +// -*- C++ -*- + +#pragma implementation + +#include "mailfile.h" +#include +#include +#include + +mailfile::mailfile(Filesystem &fs, Handle h, + ifstream *ifile, streampos start, int l, time_t t) + : SimpleInode(fs, h), start(start), ifile(ifile) +{ + uid = getuid(); + gid = getgid(); + mode = S_IFREG | 0444; + size = l; + atime = ctime = mtime = t; +} + +int +mailfile::do_read(const up_preamble &pre, upp_repl &repl, + const upp_read_s &arg, upp_read_r &ret) +{ + int sz, off; // legth of returned bunch + // Bunch is requested by kernel. Kernel asks for bunch of + // arg.size bytes starting from arg.off + + // i = arg.file; + off = arg.off; + sz = arg.size; + // l = arg.ctok; + + if(off >= size) + { + ret.data.nelem = 0; // send EOF + } + else + { + if(off + sz > size) + sz = size - off; + ret.data.alloc(ret.data.nelem = sz); + ifile->seekg(start + off); + ifile->read(ret.data.elems, sz); + } + return 0; +} Added: trunk/filesystems/mailfs/mail.cc ============================================================================== --- trunk/filesystems/mailfs/mail.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/mailfs/mail.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,455 @@ +// -*- C++ -*- + +#pragma implementation + +#include "mail.h" + +header::header(ifstream *f, String name, streampos begin, int l = 0) +{ + file = f; + n = name; + start = begin; + len = l; +// printf("HEADER STARTED AT %d\n", start); +} + +String +header::full() +{ + if(!file) + puts("FILE NULL POINTER!!!"); + char x[len + 1]; + file->seekg(start); + file->read(x, len); + x[len] = 0; + return x; +}; + +// tests in fact is the ifstream OK +void +header::test() +{ + char staf[200]; + streampos p = file->tellg(); + file->seekg(0); + file->getline(staf, 35); + puts("HEADER TEST"); + puts(staf); + file->seekg(p); +} + +message::message(ifstream *f, streampos begin, int l = 0) +{ + file = f; + start = begin; + len = l; +} + +static Regex + from_left_rx(":.*<"), + alpha_rx("[A-Za-z]"), + rubout_leftsc_rx("^: *"), + rubout_rightless_rx(" *<$"), + inparen_rx("(.*)"), + whitespc_rx("[ \n\t]"), + easyshell_rx("[ /!&@'\"]"), + rubout_leftpar_rx("^.*("), + rubout_rightpar_rx(").*$"); + +void +message::setname(String m) +{ + from_name = m.at(from_left_rx); + if(from_name.index(alpha_rx) >= 0) + { + from_name.del(rubout_leftsc_rx); + from_name.del(rubout_rightless_rx); + m = from_name; + int j = 0; + int i = m.length(); + if(m.at(j, 1) == "\"") + j++; + if(m.at(i-1, 1) == "\"") + i--; + from_name = m.at(j, i - j); // extract name out of "From " header + } + else + { + from_name = m.at(inparen_rx); + if(from_name.index(alpha_rx) >= 0) + { + from_name.del(rubout_leftpar_rx); + from_name.del(rubout_rightpar_rx); + } + else + { + int j = m.index(" ") + 1; + int i = m.index(whitespc_rx, j); + if(i < 0) + i = m.length(); + if(i > j) + { +// from_name = m.at(Regex("<.*>"), j); + for(; m.at(j, 1) == "<" || m.at(j, 1) == "\""; ) + j++; + for(; m.at(i-1, 1) == ">" || m.at(i-1, 1) == "\""; ) + i--; + from_name = m.at(j, i - j); // extract name out of "From " header + } + } + } + from_name.gsub(easyshell_rx, "_"); // it's easier for shells +} + +static Regex num_rx("[0-9]"), capit_rx("[A-Z]"); + +void +message::setdate(String date) +{ + struct tm tms; + char month[8]; + + char *months[] = + { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + +// puts((char *)date); + String dt = date.from(num_rx); + tms.tm_mday = atoi((char *)dt); + dt = dt.from(capit_rx); + int i; + for(i = 11; i >= 0; i--) + if(dt.index(months[i]) >= 0) + break; + tms.tm_mon = i; + dt = dt.from(num_rx); + tms.tm_year = atoi((char *)dt); + if(tms.tm_year >= 1900) + tms.tm_year -= 1900; + dt = dt.after(" "); + tms.tm_hour = atoi((char *)dt); + dt = dt.after(":"); + tms.tm_min = atoi((char *)dt); + dt = dt.after(":"); + tms.tm_sec = atoi((char *)dt); + dt = dt.after(" "); + tms.tm_isdst = -1; + int plus = atoi((char *)dt); + long int pz = (plus % 100) * 60 + (plus / 100) * 3600; + d = mktime(&tms); + d += - pz - timezone; + if(daylight) + d += 3600; +} + +/* +message::message(String msg = "") +{ + int i, j, k, p, r; + Pix a; + + m = msg; + + j = m.index(" ") + 1; + i = m.index(Regex("[ \n\t]"), j); + if(i > j) + { +// from_name = m.at(Regex("<.*>"), j); + if(m.at(j, 1) == "<") + j++; + if(m.at(i-1, 1) == ">") + i--; + from_name = m.at(j, i - j); // extract name out of "From " header + from_name.gsub(Regex("[ /!&@']"), "_"); // it's easier for shells + } + for(k = 0, p = i = m.index("\n") + 1; i < m.length(); i = j + 1, k++ ) + { + j = m.index("\n", i); + if(j < 0) + j = m.length(); // if newline is not found, skip to END of message + + if(m.at(i, 1) != "\t" && m.at(i, 1) != 32) + { // test if line doesn't begin with TAB/SPC + if(i > p) // p is the start of previous header line + { + // Take care - we are adding PREVIOUS line here + // once we get sure current line doesn't begin with TAB + header h = m.at(p, i - p); + for(r = 0, a = hdrs.first(); a != NULL; hdrs.next(a)) + { + if(hdrs(a).name() == h.name()) + { + r++; + hdrs(a).append(h.full()); + break; + } + } + if(!r) + hdrs.append(h); + } + p = i; + } + if(j - i < 1) + break; // this is empty lin + } + b = i; +} +*/ + +String +message::full() +{ + if(!file) + return "FILE: NULL POINTER!!!"; + char x[len + 1]; + file->seekg(start); + file->read(x, len); + x[len] = 0; + return x; +}; + +String +message::body() +{ + if(!file) + return "FILE: NULL POINTER!!!"; + int l = len - b; + char x[l + 1]; + file->seekg(start + b); + file->read(x, l); + x[l] = 0; + return x; +}; + + +void +message::disp() +{ + int i; + Pix a; + String b; + + cout << "----- headers:\n"; + for(i = 0, a = hdrs.first(); a != NULL; hdrs.next(a), i++) + { +// hdrs(a).test(); + cout << i << " " << hdrs(a).full(); + } + b = body(); + cout << "----- body (len = " << b.length() << "):\n" << body() << "-----\n"; +} + +void +message::test() +{ + char staf[200]; + streampos p = file->tellg(); + file->seekg(0); + file->getline(staf, 35); + puts("MESSAGE TEST"); + if(file->eof()) + puts("FILE EOF"); + puts(staf); + file->seekg(p); +} + +mail::mail(ifstream *f) +{ + file = f; + char line[MAX_LINE_LEN + 1]; + String msg, temp; + int i = 0, ic, cont_len = -1, line_num = -1, lines = 0; + streampos st, sp = -1, sn, bm = -1, em, hs = -1; + int state = FSM_NOTHING; + message *m = NULL; + header *h = NULL; + String hname = "", tname; + + if(!file) + return; + for(st = sn = 0; !file->eof(); ) + { + sp = sn; + file->getline(line, MAX_LINE_LEN); + temp = line; +// sn = file->tellg(); +// I gave off on tellg() because it's SLOW and people hate it. +// here's a faster hack, but expect BIG trobles if line is +// longer than MAX_LINE_LEN!!! + sn += temp.length() + 1; + switch(state) + { + case FSM_NOTHING: + if(!memcmp(line, "From ", 5)) + { + if(bm >= 0) // soome message has to exist before we append. + { + m->setlen(sp - bm); + messages.append(*m); + } + state = FSM_HEADERS; + i++; // increment message number + bm = sp; // begin of the message + hs = cont_len = line_num = -1; // clear header start and Contents-Length + m = new message(file, bm); + m->setname(temp); + hname = ""; + } + break; + case FSM_HEADERS: + { +// take care, for the last header to be appended, +// a final header addition shall be done when +// the empty line is seen. + char c = *line; + if(c != '\t' && c != ' ') + { // test if line doesn't begin with TAB/SPC + ic = 0; + int it = temp.index(Regex("[: ]")); + tname = temp.before(it); // establish possible header's name + if(!memcmp(line, "Content-Length:", 15)) + { + cont_len = atoi(line + it + 1); + } + else + if(!memcmp(line, "Lines:", 6)) + { + line_num = atoi(line + it + 1); + } + else + if(!memcmp(line, "From:", 5)) + { + m->setname(temp); + } + else + if(!memcmp(line, "Date:", 5)) + { + m->setdate(temp); + } + if(hs < 0) // header hasn't begun + { + hs = sp; // start the header + if(tname.length() > 0) + { + ic++; // signal - create new header + hname = tname; + } + } + else + { +// potential BUG location: if we have multiple headers with same name, +// but not coming in succession, one after another, we are having a problem. +// we cannot represent header contents file with single offset/length +// because header's contents is split in parts. + if(tname != hname) // just test if the previous isn't the same + { + h->setlen(sp - hs); // header length + m->headers()->append(*h); // append this header, since + // since it probably has a different name + hs = sp; + if(tname.length() > 0) + { + ic++; // signal - create new header + hname = tname; + } + } + } + if(ic) + { // create new header + h = new header(file, hname, hs); + } + } + if( temp.length() < 2) + { + m->setbody(sn - bm); + if(cont_len >= 0) + { + sp += cont_len; + sn += cont_len; + file->seekg(sn); + m->setlen(sn - bm); + messages.append(*m); + state = FSM_NOTHING; + bm = -1; // begin of the message + hs = cont_len = line_num = -1; // clear header start and Contents-Length + i++; // increment message number + } + else + { + state = FSM_BODY; // empty line - start body reading + lines = 0; + } + break; + } + break; + } + case FSM_BODY: + int nxtmsg = 0; + if(!memcmp(line, "From ", 5)) + { + if(bm >= 0) // at least one message has to exist before we append. + { + m->setlen(sp - bm); + messages.append(*m); + } + state = FSM_HEADERS; + bm = sp; // begin of the message + nxtmsg++; + } + else + { + if(line_num >= 0 && ++lines > line_num) + { + if(bm >= 0) // append. + { + m->setlen(sp - bm); + messages.append(*m); + } + state = FSM_NOTHING; + bm = -1; // begin of the message + nxtmsg++; + } + } + if(nxtmsg) + { + hs = cont_len = line_num = -1; // clear header start and Contents-Length + i++; // increment message number + m = new message(file, bm); + m->setname(temp); + hname = ""; + break; + } + break; + } + conta1:; + } + file->clear(); // wipe out eof thing + if(bm >= 0 && bm < sp) + { + m->setlen(sp - bm); + messages.append(*m); // it has to be one message more! + } +} + +void +mail::disp() +{ + int i; + Pix a; + + cout << "----- MAIL messages:\n"; + for(i = 0, a = messages.first(); a != NULL; messages.next(a), i++) + messages(a).disp(); +} + +/* +int main() +{ + ifstream f("davor"); + mail a(&f); + a.disp(); + return 0; +} +*/ Added: trunk/filesystems/mailfs/maildir.h ============================================================================== --- trunk/filesystems/mailfs/maildir.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/mailfs/maildir.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,34 @@ +// -*- C++ -*- + +// Example directory + +#ifndef _MAILDIR_H_ +#define _MAILDIR_H_ + +#pragma interface + +#include +#include +#include + +class mailfs; + +class maildir : public DirInode +{ + streampos start; + ifstream *ifile; + int length; +public: + maildir(mailfs &, Handle, Inode *, ifstream *, streampos, int, time_t); + maildir(mailfs &, Handle, Inode *, time_t); + int do_read(const up_preamble &, upp_repl &, + const upp_read_s &arg, upp_read_r &ret); +}; + +class mailtopdir : public maildir +{ +public: + mailtopdir(mailfs &, Handle, Inode *); +}; + +#endif /* _MAILDIR_H_ */ Added: trunk/filesystems/mailfs/mail.h ============================================================================== --- trunk/filesystems/mailfs/mail.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/mailfs/mail.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,80 @@ +// -*- C++ -*- + +#ifndef _MAIL_H_ +#define _MAIL_H_ + +#pragma interface + +// Header line management + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_LINE_LEN 256 +#define MAX_MSG_LEN 32767 + +enum { ACT_DATE, ACT_FROM, ACT_CONTENTS_LENGTH, ACT_LINES, ACT_N }; +enum { FSM_NOTHING, FSM_HEADERS, FSM_BODY }; + +class header +{ + String n; + ifstream *file; + streampos start; + int len; +public: + header(ifstream *, String, streampos, int); + header() { file = NULL; start = len = 0; }; + String name() { return n; }; + void setlen(int l) { len = l; }; + void test(); + String full(); + void report(ifstream* &rf, streampos &rs, int &rl) + { rf = file; rs = start; rl = len; }; +}; + +class message +{ + DLList
hdrs; + String from_name; + streampos start; + ifstream *file; + time_t d; + int len; + int b; +public: + message() { file = NULL; start = len = 0; }; + message(ifstream *, streampos, int); + void disp(); + String name() { return from_name; }; + String body(); + String full(); + DLList
*headers() { return &hdrs; }; + void clear(streampos p) { hdrs.clear(); start = p; }; + void test(); + void setlen(int l) { len = l; }; + void setbody(int bb) { b = bb; }; + void setname(String); + void report(ifstream* &rf, streampos &rs, int &rl, int &rb, time_t &rt) + { rf = file; rs = start; rl = len; rb = b; rt = d; }; + void setdate(String); +}; + +class mail +{ + DLList messages; + ifstream *file; +public: + mail(ifstream *); + ~mail() { }; + void disp(); + DLList contents() { return messages; }; +}; + +#endif /* _MAIL_H_ */ Added: trunk/filesystems/mailfs/mailfile.h ============================================================================== --- trunk/filesystems/mailfs/mailfile.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/mailfs/mailfile.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,24 @@ +// -*- C++ -*- + +#ifndef _MAILFILE_H_ +#define _MAILFILE_H_ + +#include +#include +#include +#include + +#pragma interface + +class mailfile:public SimpleInode +{ + streampos start; + ifstream *ifile; + + public: + mailfile(Filesystem &, Handle, ifstream *, streampos, int, time_t); + do_read(const up_preamble &, upp_repl &, + const upp_read_s &arg, upp_read_r &ret); +}; + +#endif /* _MAILFILE_H_ */ Added: trunk/filesystems/mailfs/mailfs.1 ============================================================================== --- trunk/filesystems/mailfs/mailfs.1 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/mailfs/mailfs.1 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,165 @@ +.\" Copyright 1994 Davor Jadrijevic +.\" May be distributed under the GNU General Public License +.\" See section COPYING for conditions for redistribution +.TH mailfs 1 "15 May 1994" Mailfs "Linux Manual" +.SH NAME +mailfs \- userfs client to display contents of a mail file +in form of a directory +.SH SYNOPSIS +.RI muserfs +.B mailfs +.I "mount\-point" +.RI \-\- +.I "[options...]" +.SH DESCRIPTION +.B mailfs +is a userfs client which allows to mount messages from mail file +arranged in form of directory. +.PP +.B mailfs +will operate in the directory to where it is mounted. There it will +create one directory for every mail message. Name of the directory +consists from number of the message (lower numbers - recently arrived +messages), and the username in a) +.B From: +header, between +.B : +and +.B < +b) +.B From: +header, between +.B ( +and +.B ) +c) +.B From: +header between two spaces +d) +.B From +header between two spaces. That can +looks like +.B 001.user_name +( problematic characters like +.B !, @ +etc. will be replaced with +.B _ +). In this directory, there will be files. For each header, a file +will be created, named same as the header, and containing full +header text (with name too). Message text is in file +.B body.txt +and full mail message (together with headers) is in file +.B .complete.txt +.PP +Time stamp of files will be calculated from +.B Date: +header, and should represent +the time when message was sent in terms of local time. This is done +by converting +.B Date: +to GMT, and then adding local timezone and 1 hour in case of daylight +saving. +.SH OPTIONS +.TP +.I "\-o n" +Where +.I n +is the file descriptor number the process should write to the kernel on. +.TP +.I "\-i n" +Where +.I n +is the file descriptor to read kernel requests from. +.TP +.I "\-m mpoint" +Where +.I mpoint +is the path of the mountpoint. +.TP +.I "\-f mail-file" +Where +.I mail-file +is the file in which mail messages reside. If you omit this option, then +.B MAIL +environment variable content will be used. This variable shall contain +something like /usr/spool/mail/username +.P +User is not required to invoke any of the options for ordinary operation. +.SH EXAMPLES + + $ muserfs bin/mailfs mnt & + [1] 352 + $ cd mnt + $ ls + 001.sbg_socs.uts.edu.au + 002.Leroy + 003.tlukka_vinkku.hut.fi + $ cat */From + From: sbg@socs.uts.edu.au + From: leroy@socs.uts.edu.au (Leroy) + From: tlukka@vinkku.hut.fi + $ cat */Subject + More things + (none) + That userfs thing +.SH METHOD +.B mailfs +divides the mail file into linked list of messages, +every message is then divided into linked list of headers and body. +A tree-like structure formed that way is used to fill userfs with +representation of the mail in directory. +.PP +Division is made on follwing conditions: In mail file, each message +begins with a line having +.B From +at its beginning, following with space. In message, each header +follows with a line which in turn begins with any character except +whitespace +.B TAB +or +.B SPACE. +Whitespace +at the beginning is used as continuation character for the previous +header. Header's name is string from beginning of the line to the +semicolon ( +.B \: +) character. Headers are divided from message body with empty line. +In case +.B Contents-Length: +is defined, the message body is assumed to be of that length, regardless +of the contents there. +Otherwise, message body is the rest of the message until +.B From +appears. +or until +.B Lines: +number of lines is read (if this header exists). +.SH BUGS +There might be problems if message contains headers of the same +name at random places, i.e. same header names, but not appearing +strictly one after another. +.PP +Also, problems if any line in the mail file exceeds +.B MAX_LINE_LEN +having default value +.B 256 +defined in +.B mail.h +.PP +On +.B longer +mail files, userfs will take some +.B time +to parse the file. +If you enter mounted userfs directory before mailfs is ready, file +operations there will produce +.B No such file or directory +errors after mailfs gets up. +Exiting and reentering userfs directory will solve the problem. +.SH AUTHOR +Davor Jadrijevic +.SH SEE ALSO +.BR muserfs (2), +.BR mount (8), +.BR umount (8), +.BR mail (1) Added: trunk/filesystems/mailfs/README ============================================================================== --- trunk/filesystems/mailfs/README 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/mailfs/README 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,71 @@ + + * * * ** ** ******** ******** + ** ** *** ** ** ******** ********* + *** *** ***** ** ** **** + **** **** ******* ** ** ******** ****** + ***** ***** ********* ** ** ******** **** + *********** *********** ** ******** ** ********* + *********** *********** ** ******** ** ******** + + , + BY DAVOR JADRIJEVIC + + + MAILFS is a client for userfs file system. MAILFS will read +the mail file and arrange it in form of a directory. Each message +is represented by its number, and name of the person From whom +the message arrived. Directory itself behaves as a file; it can +be read, giving message with headers. It can be entered, as a normal +directory, inside of which are files representing headers (each +header in separated file) and message body. + + Message dates are converted to local time, so the time-stamp of +files representing mail is set appropriately. This can be used +for comparing the time (in local units) when messages are written; +useful for time-basis sorting etc. + +Please refer to man page mailfs.1 with e.g. +$ groff -man mailfs.1 | more +for more details. + +--- STATUS OF MAILFS --- + (alpha testing) + +Things to be done: + +1. Dynamics. + +Dynamically read the mail as it arrives in the mailbox. +Possible solutions are under consideration. +For now, MAILFS is static - mail file can be mounted, but +once it's mounted it's not supposed to change (anomalies +are expected if it does). + +2. Speeded-up parser. + +It has been reported that long mail files take very long +time to be parsed. + +3. Proper rfc822 implementation + +It has been implemented a subset of rfc822 recommendation +in a rather simple way, in order to get a useful mailfs +behaviour with rather quick and simple solutions. + +4. Sending mail + +If I get a good idea, maybe I can implemend replying and +sending mail messages, so mailfs will serve as fully qualified +mailer, which can be mounted all the time. + +--- * * * --- + +I wish to thank Jeremy Fitzhardinge for making userfs, +his idea and collaborating on mailfs. + +Mailfs can be handled under the terms of GNU public licence. + +Enjoy it. +-- , +Davor Jadrijevic +Lastovska 5, 41000 Zagreb, Croatia. Added: trunk/filesystems/mailfs/Makefile ============================================================================== --- trunk/filesystems/mailfs/Makefile 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/mailfs/Makefile 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,23 @@ +TOP=../.. +include $(TOP)/rules +FLAGS=-I$(TOP)/kernel -I$(TOP)/lib -I$(TOP)/genser -I/usr/include/g++ +CFLAGS=$(FLAGS) +CXXFLAGS=$(FLAGS) +DEBUG=-O -g -DDEBUG + +LDFLAGS = +PROGS=mailfs + +OBJ=mailfs.o maildir.o mailfile.o maillink.o mail.o + +all:: $(PROGS) + +mailfs: $(OBJ) $(DEPLIBUSERFS) + $(CXX) $(LDFLAGS) -o $@ $(OBJ) $(LIBUSERFS) + +clean:: dummy + rm -f *.o *~ $(PROGS) + +dep depend:: + $(CXX) $(CXXFLAGS) -M *.cc > .depend + Added: trunk/filesystems/example/egfile.cc ============================================================================== --- trunk/filesystems/example/egfile.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/example/egfile.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,96 @@ +// -*- C++ -*- +// +// Files in egfs +// +// This program is distributed under the terms of the +// Free Software Foundation General Public Licence. +// See COPYING for details +// Copyright Jeremy Fitzhardinge 1994,1995 + +#pragma implementation + +#include "egfile.h" + +#include +#include + +// Create a file with some initial content +egfile::egfile(Filesystem &fs, Handle h, char *b, int sz) + : SimpleInode(fs, h) +{ + // Use our invoker's ID rather than the person doing the syscall. + uid = getuid(); + gid = getgid(); + mode = S_IFREG | 0644; + if (sz == -1) + sz = strlen(b); + buf = new char [sz]; + size = sz; + memcpy(buf, b, sz); +} + +// Set the length of the file. Very naive: it just frees the old buffer +// and allocates the new one, without trying to optimise at all. +void +egfile::truncate(off_t off) +{ + char *nb = new char[off]; + + memset(nb, 0, off); + memcpy(nb, buf, off > size ? size : off); + delete buf; + buf = nb; + size = off; +} + +// Not much to reading +int +egfile::do_read(const up_preamble &, upp_repl &, + const upp_read_s &arg, upp_read_r &ret) +{ + size_t sz = size - arg.off; + + // Reads beyond EOF always get 0 bytes + if (sz <= 0) + { + ret.data.nelem = 0; + return 0; + } + + // Read either the amount wanted or to the end of the file. + sz = sz > arg.size ? arg.size : sz; + + // Just point the return to the data + ret.data.nelem = sz; + ret.data.elems = (Uchar *)&buf[arg.off]; + return 0; +} + +// Writing files could be much more efficient. As it is, each write +// which grows the file will cause truncate() to alloc, copy and free +// the buffer with the file contents. +int +egfile::do_write(const up_preamble &, upp_repl &, + const upp_write_s &arg, upp_write_r &ret) +{ + // Writing off the end of the file means we grow it + if (arg.off + arg.data.nelem > size) + truncate(arg.off + arg.data.nelem); + + // Copy the data into place + memcpy(buf+arg.off, arg.data.elems, arg.data.nelem); + + // We can never do partial writes + ret.wrote = arg.data.nelem; + return 0; +} + +// Set the size of the file (truncate is historical; it can also grow +// files) +int +egfile::do_truncate(const up_preamble &, upp_repl &, + const upp_truncate_s &arg) +{ + truncate(arg.size); + return 0; +} Added: trunk/filesystems/example/egdir.h ============================================================================== --- trunk/filesystems/example/egdir.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/example/egdir.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,32 @@ +// -*- C++ -*- + +// Example directory + +#ifndef _EGDIR_H_ +#define _EGDIR_H_ + +#pragma interface + +#include +#include + +class egfs; + +class egdir : public DirInode +{ + egfs &filesys; + +public: + egdir(egfs &, Handle, Inode *); + + int do_create(const up_preamble &, upp_repl &, + const upp_create_s &arg, upp_create_r &ret); +}; + +class egtopdir : public egdir +{ +public: + egtopdir(egfs &, Handle, Inode *); +}; + +#endif /* _EGDIR_H_ */ Added: trunk/filesystems/example/egfile.h ============================================================================== --- trunk/filesystems/example/egfile.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/example/egfile.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,26 @@ +// -*- C++ -*- + +#ifndef _EGFILE_H_ +#define _EGFILE_H_ + +#include +#include + +#pragma interface + +class egfile:public SimpleInode +{ + char *buf; + + public: + egfile(Filesystem &fs, Handle h, char *b, int sz = -1); + int do_read(const up_preamble &, upp_repl &, + const upp_read_s &arg, upp_read_r &ret); + int do_write(const up_preamble &, upp_repl &, + const upp_write_s &arg, upp_write_r &ret); + int do_truncate(const up_preamble &, upp_repl &, + const upp_truncate_s &arg); + void truncate(off_t off); +}; + +#endif /* _EGFILE_H_ */ Added: trunk/filesystems/example/egfs.cc ============================================================================== --- trunk/filesystems/example/egfs.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/example/egfs.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,125 @@ +// -*- C++ -*- +// +// Example filesystem +// +// This program is distributed under the terms of the +// Free Software Foundation General Public Licence. +// See COPYING for details +// Copyright Jeremy Fitzhardinge 1994,1995 + +#pragma implementation + +// Misc headers +#include +#include + +// Filesystem related headers +#include + +#include "egfs.h" +#include "egdir.h" + +// A simple constructor for the filesystem +// All this does is pass the arguments to the base class +// and initialize the inode handle counter. +// The counter is for generating unique handles as required. +// The mechanism used is very simple, because there is a bounded +// number of inodes. +egfs::egfs(const char *mpoint) + : Filesystem(mpoint) +{ + hcount=2; +} + +egfs::~egfs() +{ +} + +// Declare to the kernel which operations we will support. Lots of +// this is entirely done by the base classes in libuserfs (for example, +// up_link is done by DirInode; we don't have to do anything explicitly). +int +egfs::Enquire(up_ops op) +{ + switch(op) + { + case userfs_up_mount: + case userfs_up_iread: + case userfs_up_notify_change: + case userfs_up_readdir: + case userfs_up_multireaddir: + case userfs_up_lookup: + case userfs_up_create: + case userfs_up_unlink: + case userfs_up_link: + case userfs_up_rename: + case userfs_up_truncate: + case userfs_up_read: + case userfs_up_write: + return 0; + default: + break; + } + return Filesystem::Enquire(op); +} + +// Do the mount. This simply returns the handle of the root +// directory and creates the directory. +int +egfs::do_mount(const up_preamble &, upp_repl &, + upp_mount_r &ret) +{ + Inode *root = new egtopdir(*this, genhand(), NULL); + ret.root.handle = root->gethandle(); + return 0; +} + +// Parse the arguments from muserfs and construct the filesystem +// and communications. +int +main(int argc, char **argv) +{ + int optch, err = 0; + int infd, outfd; + const char *mpoint = ""; + + extern char *optarg; + extern int optind, opterr, optopt; + + + infd = outfd = -1; + while((optch = getopt(argc, argv, "i:o:m:")) != EOF) + switch(optch) + { + case 'i': + infd = atoi(optarg); + break; + case 'o': + outfd = atoi(optarg); + break; + case 'm': + mpoint = optarg; + break; + default: + err++; + } + + if (err) + { + fprintf(stderr, "Usage: %s -i infd -o outfd -m mpoint\n", + argv[0]); + exit(1); + } + +#if 0 && DEBUG + printf("pid=%d, return to cont\n", getpid()); + getchar(); +#endif + egfs efs(mpoint); + Comm comm(efs, outfd, infd); + + if (comm.Run() == -1) + fprintf(stderr, "%s: Comm.Run() failed!\n", argv[0]); + + return 0; +} Added: trunk/filesystems/example/egfs.h ============================================================================== --- trunk/filesystems/example/egfs.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/example/egfs.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,27 @@ +// -*- C++ -*- + +// Example filesystem + +#ifndef _EGFS_H_ +#define _EGFS_H_ + +#include + +#pragma interface + +class egfs:public Filesystem +{ + Handle hcount; + + int Enquire(up_ops); + + int do_mount(const up_preamble &, upp_repl &, upp_mount_r &); + +public: + egfs(const char *); + ~egfs(); + + Handle genhand() { return hcount++; } +}; + +#endif /* _EGFS_H_ */ Added: trunk/filesystems/example/Makefile ============================================================================== --- trunk/filesystems/example/Makefile 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/example/Makefile 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,23 @@ +TOP=../.. +FLAGS=-I$(TOP)/kernel -I$(TOP)/lib -I$(TOP)/genser -I/usr/include/g++ \ + -DDEBUG -Wall +CXXFLAGS = $(FLAGS) + +include $(TOP)/rules + +LDFLAGS = -g $(PROF) + +PROGS=egfs + +OBJ=egfs.o egdir.o egfile.o $(TOP)/lib/libuserfs.a -lg++ + +all:: $(PROGS) + +egfs: $(OBJ) $(DEPLIBUSERFS) + $(CXX) $(LDFLAGS) -o $@ $(OBJ) $(LIBUSERFS) + +clean:: dummy + rm -f *.o *~ core $(PROGS) + +dep depend:: + $(CXX) $(CXXFLAGS) -M *.cc > .depend Added: trunk/filesystems/example/egdir.cc ============================================================================== --- trunk/filesystems/example/egdir.cc 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/example/egdir.cc 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,84 @@ +// -*- C++ -*- + +// Directories in egfs +// +// This program is distributed under the terms of the +// Free Software Foundation General Public Licence. +// See COPYING for details +// Copyright Jeremy Fitzhardinge 1994,1995 + +#pragma implementation + +#include "egdir.h" +#include "egfile.h" +#include "egfs.h" + +#include +#include + +// Directories are *easy* +egdir::egdir(egfs &fs, Handle h, Inode *p) + : DirInode(fs, h, p), filesys(fs) +{ + uid = getuid(); + gid = getgid(); + mode = S_IFDIR | 0755; +} + +// This constructs the entire directory hierachy for this +// filesystem (i.e. prime it with silly files) +egtopdir::egtopdir(egfs &fs, Handle h, Inode *p) + : egdir(fs, h, p) +{ + link("test1", new egfile(fs, fs.genhand(), "Hello, world!\n")); + link("test2", new egfile(fs, fs.genhand(), "Wooba wooba...\n")); + + DirInode *d1 = new egdir(fs, fs.genhand(), this); + DirInode *d2 = new egdir(fs, fs.genhand(), this); + + link("dir1", d1); + link("dir2", d2); + + Inode *f1 = new egfile(fs, fs.genhand(), "File with multiple names\n"); + d1->link("linked-file", f1); + d2->link("another-link", f1); + + Inode *f2 = new egfile(fs, fs.genhand(), "Piffle woodle.\n"); + d2->link("strange", f2); +} + +// Handle file creation. We only support files and directories (no links, +// devices, etc) +int +egdir::do_create(const up_preamble &, upp_repl &, + const upp_create_s &arg, upp_create_r &ret) +{ + Inode *ino; + Handle h = filesys.genhand(); + char* buf; + int n; + + if (S_ISREG(arg.mode)) + { + ino = new egfile(filesys, h, NULL, 0); + } + else if (S_ISDIR(arg.mode)) + { + ino = new egdir(filesys, h, this); + } + else + return EINVAL; + + ret.file.handle = ino->gethandle(); + // link(String((char *)arg.name.elems, (int)arg.name.nelem), ino); + + n = (int)arg.name.nelem; + buf = (char *)malloc(n + 1); + strncpy(buf, (char *)arg.name.elems, n); + buf[n] = '\0'; + link(buf, ino); + free(buf); + + return 0; +} + Added: trunk/filesystems/README ============================================================================== --- trunk/filesystems/README 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/README 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,12 @@ +This directory contains contributed work. Briefly, the contents are: + +arcfs - mount compressed tar files and browse them as filesystems +mailfs - a mailreading filesystem +ulrich-dessauer - a C userfs interface library and various filesystems + including a read-only OS/9 filesystem. + +I don't guarentee that things under here work or even compile. Use them +at your own risk. Please report bugs in programs in this directory to +both me and their original authors. + + Jeremy Fitzhardinge Added: trunk/filesystems/arcfs/arcfs.c ============================================================================== --- trunk/filesystems/arcfs/arcfs.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/arcfs/arcfs.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,561 @@ +/* (Read-only) archive filesystem. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include + +#include "arcfs.h" + +static char *mpoint; +static ARC_DIRENT *root; + +/* No point in this being in a seperate file. */ +#include + +static int +myread (int fd, void *buf, int sz) +{ + int rd = 0; + int ret; + + while (sz > 0) + { + ret = read (fd, buf, sz); + + if (ret == -1) + { + if (errno == EINTR) + continue; + + perror ("myread"); + exit (1); + } + + if (ret == 0) + break; + + sz -= ret; + buf += ret; + rd += ret; + } + + return rd; +} + +static int +mywrite (int fd, const void *buf, int sz) +{ + int wr = 0; + int ret; + + while (sz > 0) + { + ret = write (fd, buf, sz); + + if (ret == -1) + { + if (errno == EINTR) + continue; + FAIL ("write"); + exit (1); + } + + if (ret == 0) + { + fprintf (stderr, "write wrote 0 bytes\n"); + break; + } + + sz -= ret; + buf += ret; + wr += ret; + } + + return wr; +} + +static int +readpkt (int fd, up_preamble *pre, unsigned char *buf) +{ + int presz = sizeof_up_preamble (pre); + unsigned int rd; + unsigned char pbuf[presz]; + + memset (pbuf, 0, sizeof (pbuf)); + + rd = myread (fd, pbuf, presz); + if (rd != presz) + { + if (rd == 0) + return 0; + if (rd > 0) + fprintf (stderr, "readpkt, incomplete read (%d, not %d)\n", + rd, presz); + perror ("readpkt, header read"); + return -1; + } + + decode_up_preamble (pre, pbuf); + + if (pre->isreq != UP_ENQ && pre->isreq != UP_REQ) + fprintf (stderr, "pre->isreq = %d\n", pre->isreq); + + if (pre->version != UP_VERSION) + { + fprintf (stderr, "Version mismatch: us=%d them=%d\n", + UP_VERSION, pre->version); + return -1; + } + + if (pre->size != 0) + { + if (myread (fd, buf, pre->size) != pre->size) + { + perror ("readpkt, body read"); + return -1; + } + } + + return 1; +} + +static int +writepkt (int fd, upp_repl *repl, const unsigned char *buf) +{ + int replsz = sizeof_upp_repl (repl); + unsigned char pbuf[replsz]; + unsigned int wr; + unsigned char *p; + + assert (repl->version == UP_VERSION); + assert (repl->isreq == UP_REPL); + + p = encode_upp_repl (repl, pbuf); + + assert (replsz == p - pbuf); + + wr = mywrite (fd, pbuf, replsz); + if (wr != replsz) + { + perror ("writepkt, header write"); + return -1; + } + + if (repl->size > 0 && repl->err_no == 0) + { + if ( mywrite(fd, buf, repl->size) != repl->size) + { + perror ("writepkt, body write"); + return -1; + } + } + + return 1; +} + +static void +genpkt (upp_repl *repl, int seq, up_ops op) +{ + repl->version = UP_VERSION; + repl->seq = seq; + repl->op = op; + repl->isreq = 0; + repl->size = 0; + repl->err_no = 0; +} + +#define DIRINO 1 + +static int +do_iread (unsigned char *buf, upp_repl *repl) +{ + upp_iread_s rcv; + upp_iread_r snd; + time_t t; + + decode_upp_iread_s(&rcv, buf); + + memset(&snd, 0, sizeof(snd)); + + snd.ino.mode = 0444; + snd.handle = rcv.handle; + snd.ino.nlink = 1; + + fprintf(stderr, "do_iread: handle=%ld\n", rcv.handle.handle); + + if (rcv.handle.handle == DIRINO) + { + snd.ino.mode |= S_IFDIR | 0111; + t = time (0); + } + else + { + ARC_DIRENT *ent = (ARC_DIRENT *) rcv.handle.handle; + + if (ent->size != -1) + { + snd.ino.mode |= S_IFREG; + snd.ino.size = ent->size; + /* These numbers seem to be magic for Linux. */ + snd.ino.blksize = 512; + snd.ino.blocks = (ent->data.file.csize + 511) / 512; + } + else + { + snd.ino.mode |= S_IFDIR | 0111; + snd.ino.size = 0; + } + t = 0; + } + + snd.ino.mtime = snd.ino.ctime = t; + snd.ino.atime = time (0); + + repl->size = encode_upp_iread_r(&snd, buf) - buf; + + return 0; +} + +static int +do_lookup (unsigned char *buf, upp_repl *repl) +{ + upp_lookup_s rcv; + upp_lookup_r snd; + ARC_DIRENT *ent; + + decode_upp_lookup_s(&rcv, buf); + + ent = (ARC_DIRENT *) rcv.dir.handle; + if (ent->size != -1) + return ENOTDIR; + + if (rcv.name.nelem == 2 + && rcv.name.elems[0] == '.' && rcv.name.elems[1] == '.') + { + ent = ent->pdir; + } + else if (rcv.name.nelem != 1 || rcv.name.elems[0] != '.') + { + ent = ent->data.dir.first; + while (ent) + { + /* Probably bombs out on prefixes... */ + if (!strncmp(ent->name, rcv.name.elems, rcv.name.nelem)) + break; + ent = ent->next; + } + } + FREE(rcv.name.elems); + if (!ent) + return ENOENT; + + fprintf(stderr, "do_lookup: found %s\n", ent->name); + snd.handle.handle = (Ulong) ent; + + repl->size = encode_upp_lookup_r (&snd, buf) - buf; + + return 0; +} + +static int +do_readdir (unsigned char *buf, upp_repl *repl) +{ + upp_readdir_s rcv; + upp_readdir_r snd; + ARC_DIRENT *ent; + + decode_upp_readdir_s(&rcv, buf); +fprintf(stderr, "do_readdir: dirhandle=%ld off=%d\n", rcv.dir.handle, rcv.off); + + ent = (ARC_DIRENT *) rcv.dir.handle; + if (ent->size != -1) + return ENOTDIR; + + snd.off = 0; + snd.name.nelem = 0; + + if (!rcv.off--) + { + snd.name.elems = "."; + } + else if (!rcv.off--) + { + snd.name.elems = ".."; + ent = ent->pdir; + } + else + { + ent = ent->data.dir.first; + while (ent && rcv.off--) + ent = ent->next; + if (ent) + snd.name.elems = ent->name; + } + + if (ent) + { + snd.off = 1; + snd.name.nelem = strlen (snd.name.elems); + snd.file.handle = (Ulong) ent; + } + + repl->size = encode_upp_readdir_r(&snd, buf) - buf; + + return 0; +} + +static int +do_open (unsigned char *buf, upp_repl *repl) +{ + upp_open_s rcv; + ARC_DIRENT *ent; + + decode_upp_open_s (&rcv, buf); + + ent = (ARC_DIRENT *) rcv.file.handle; + /* Directories are opened here, but read using _readdir instead of _read, + so all we do is return success! */ + if (ent->size == -1) + return 0; + + return a_open (ent); +} + +static int +do_close (unsigned char *buf, upp_repl *repl) +{ + upp_close_s rcv; + ARC_DIRENT *ent; + + decode_upp_close_s (&rcv, buf); + + ent = (ARC_DIRENT *) rcv.file.handle; + if (ent->size == -1) + return 0; + + return a_close (ent); +} + +static int +do_read (unsigned char *mbuf, upp_repl *repl) +{ + upp_read_s rcv; + upp_read_r snd; + ARC_DIRENT *ent; + int rc; + + snd.data.nelem = 0; + + decode_upp_read_s (&rcv, mbuf); + + ent = (ARC_DIRENT *) rcv.file.handle; + if (ent->size == -1) + return EISDIR; + + rc = a_read (ent, rcv.off, rcv.size, &snd.data.nelem, &snd.data.elems); + if (rc) + return rc; + repl->size = encode_upp_read_r (&snd, mbuf) - mbuf; + return 0; +} + +static int +do_mount (unsigned char *buf, upp_repl *repl) +{ + upp_mount_r snd; + + snd.root.handle = (Ulong) root; + repl->size = encode_upp_mount_r(&snd, buf) - buf; + /* INIT */ + repl->size = encode_upp_mount_r(&snd, buf) - buf; + return 0; +} + +static void +run (int wr, int rd) +{ + up_preamble pre; + upp_repl repl; + /* Ah! The bogey man's a-coming to get me! */ + unsigned char buf[4096]; + int error; + + while(readpkt(rd, &pre, buf) == 1) + { + genpkt(&repl, pre.seq, pre.op); + + switch(pre.op) + { +/* +#define DO(op, b, r) case userfs_up_##op: \ + error = (pre.isreq == UP_ENQ ? 0 : do_##op(b, r)); \ + break; + DO(mount, buf, &repl); + DO(iread, buf, &repl); + DO(lookup, buf, &repl); + DO(readdir, buf, &repl); + DO(open, buf, &repl); + DO(close, buf, &repl); + DO(read, buf, &repl); +#undef DO +*/ + case userfs_up_mount: + error = (pre.isreq == UP_ENQ ? 0 : do_mount(buf, &repl)); + break; + case userfs_up_iread: + error = (pre.isreq == UP_ENQ ? 0 : do_iread(buf, &repl)); + break; + case userfs_up_lookup: + error = (pre.isreq == UP_ENQ ? 0 : do_lookup(buf, &repl)); + break; + case userfs_up_readdir: + error = (pre.isreq == UP_ENQ ? 0 : do_readdir(buf, &repl)); + break; + case userfs_up_open: + error = (pre.isreq == UP_ENQ ? 0 : do_open(buf, &repl)); + break; + case userfs_up_close: + error = (pre.isreq == UP_ENQ ? 0 : do_close(buf, &repl)); + break; + case userfs_up_read: + error = (pre.isreq == UP_ENQ ? 0 : do_read(buf, &repl)); + break; + + case userfs_up_write: + fprintf(stderr, "userfs_up_write: some op i don't handle: %d\n", pre.op); + error = ENOSYS; + break; + case userfs_up_create: + fprintf(stderr, "userfs_up_create: some op i don't handle: %d\n", pre.op); + error = ENOSYS; + break; + case userfs_up_followlink: + fprintf(stderr, "userfs_up_followlink: some op i don't handle: %d\n", pre.op); + error = ENOSYS; + break; + case userfs_up_iput: + fprintf(stderr, "userfs_up_iput: some op i don't handle: %d\n", pre.op); + error = ENOSYS; + break; + case userfs_up_iwrite: + fprintf(stderr, "userfs_up_iwrite: some op i don't handle: %d\n", pre.op); + error = ENOSYS; + break; + case userfs_up_link: + fprintf(stderr, "userfs_up_link: some op i don't handle: %d\n", pre.op); + error = ENOSYS; + break; + case userfs_up_multireaddir: + fprintf(stderr, "userfs_up_multireaddir: some op i don't handle: %d\n", pre.op); + error = ENOSYS; + break; + case userfs_up_notify_change: + fprintf(stderr, "userfs_up_notify_change: some op i don't handle: %d\n", pre.op); + error = ENOSYS; + break; + case userfs_up_permission: + fprintf(stderr, "userfs_up_permission: some op i don't handle: %d\n", pre.op); + error = ENOSYS; + break; + case userfs_up_readlink: + fprintf(stderr, "userfs_up_readlink: some op i don't handle: %d\n", pre.op); + error = ENOSYS; + break; + case userfs_up_rename: + fprintf(stderr, "userfs_up_rename: some op i don't handle: %d\n", pre.op); + error = ENOSYS; + break; + case userfs_up_statfs: + fprintf(stderr, "userfs_up_statfs: some op i don't handle: %d\n", pre.op); + error = ENOSYS; + break; + case userfs_up_symlink: + fprintf(stderr, "userfs_up_symlink: some op i don't handle: %d\n", pre.op); + error = ENOSYS; + break; + case userfs_up_truncate: + fprintf(stderr, "userfs_up_truncate: some op i don't handle: %d\n", pre.op); + error = ENOSYS; + break; + case userfs_up_umount: + fprintf(stderr, "userfs_up_umount: some op i don't handle: %d\n", pre.op); + error = ENOSYS; + break; + case userfs_up_unlink: + fprintf(stderr, "userfs_up_unlink: some op i don't handle: %d\n", pre.op); + error = ENOSYS; + break; + + default: + fprintf(stderr, "run: some op i don't handle: %d\n", pre.op); + error = ENOSYS; + break; + } + + repl.err_no = error; + if (error != 0) + repl.size = 0; + + if (writepkt(wr, &repl, buf) != 1) + break; + } +} + +int +main (int argc, char **argv) +{ + int infd = 0; + int outfd = 1; + int c; + + while ((c = getopt (argc, argv, "i:o:m:")) != EOF) + switch(c) + { + case 'i': + infd = atoi(optarg); + break; + case 'o': + outfd = atoi(optarg); + break; + case 'm': + mpoint = optarg; + break; + default: + fprintf (stderr, "%s: bad option\n", argv[0]); + return 1; + } + + if (optind != argc - 1) + { + fprintf (stderr, "%s: no zipfile named\n", argv[0]); + return 1; + } + + root = arc_read (argv[optind++]); + if (!root) + return 1; + + signal (SIGCHLD, SIG_IGN); + + run(outfd, infd); + + return 0; +} Added: trunk/filesystems/arcfs/zip.c ============================================================================== --- trunk/filesystems/arcfs/zip.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/arcfs/zip.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,94 @@ +/* Access ZIP archives. */ + +#include "arcvfs.h" + +#ifdef ARCFMT_ZIP + +/* This is a very quick and dirty hack. It works by simply snarfing the whole + of a file into core and keeping it there until all FDs refering to it are + closed. This is fine for small archived files, tho. */ + +#include +#include +#include + +static const char excmd[] = "unzip -p -qq %s %s"; + +ARC_DIRENT * +arc_read_zip (const char *zipfile) +{ + FILE *fp; + char buf[4096]; + ARC_DIRENT *first = 0; + char *name; + long csize; + + csize = strlen (zipfile); + if (csize < 4 || strcmp (zipfile + csize - 4, ".zip")) + return 0; + + first = create_entry (zipfile, zipfile, 0); + if (!first) + return 0; + first->pdir = first; + first->size = -1; + first->data.dir.first = 0; + first->name = (char *) excmd; + + /* USIZE METHOD CSIZE CF% MM-DD-YY HH:MM CRC NAME */ + sprintf (buf, "unzip -v -qq %s", zipfile); + fp = popen (buf, "r"); + if (!fp) + { + perror (buf); + return 0; + } + while (fgets (buf, sizeof (buf), fp)) + { + long usize; + ARC_DIRENT *ent; + int dir_p; + + name = buf + strlen (buf); + if (name > buf && name[-1] == '\n') + *--name = '\0'; + if (name > buf && name[-1] == '/') + { + *--name = '\0'; + dir_p = 1; + } + else + dir_p = 0; + + usize = strtol (buf, &name, 10); + name = skip_field (name); /* METHOD */ + csize = strtol (name, &name, 10); + name = skip_field (name); /* CF% */ + name = skip_field (name); /* DATE */ + name = skip_field (name); /* TIME */ + name = skip_field (name); /* CRC */ + while (*name == ' ') + ++name; + + ent = create_dirent (name, name, &first->data.dir.first, first); + if (ent) + { + if (dir_p) + { + ent->size = -1; + ent->data.dir.first = 0; + } + else + { + ent->size = usize; + ent->data.file.csize = csize; + ent->data.file.refc = 0; + } + ent->next = 0; + } + } + fclose (fp); + return first; +} + +#endif Added: trunk/filesystems/arcfs/arcfs.h ============================================================================== --- trunk/filesystems/arcfs/arcfs.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/arcfs/arcfs.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,42 @@ +#ifndef _ARCFS_H +#define _ARCFS_H + +#define FAIL(str) fprintf(stderr, "%s:%d %s failed with errno = %s (%d)\n", __FILE__, __LINE__, str, strerror(errno), errno) +#ifdef DEBUG +#include +#include +#define DB(x) {x;} +#else +#define DB(x) /**/ +#endif + +typedef struct tagDIRENT ARC_DIRENT; + +struct tagDIRENT { + ARC_DIRENT *next; + /* The directory to which this belongs (or itself if this is the root + directory). */ + ARC_DIRENT *pdir; + /* -1 for a directory. */ + long size; + union { + struct { + long csize; + unsigned char *buf; + unsigned int refc; /* PRIVATE to `unzip.c'. */ + } file; + struct { + ARC_DIRENT *first; + } dir; + } data; + char *name; + /* Structure is then expanded to whatever... */ + char fullname[1]; /* PRIVATE to `zip.c'. */ +}; + +int a_open (ARC_DIRENT *); +int a_close (ARC_DIRENT *); +int a_read (ARC_DIRENT *, long, long, unsigned long *, unsigned char **); +ARC_DIRENT *arc_read (const char *); + +#endif /* _ARCFS_H */ Added: trunk/filesystems/arcfs/arcvfs.c ============================================================================== --- trunk/filesystems/arcfs/arcvfs.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/arcfs/arcvfs.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,178 @@ +/* Archive VFS layer. */ + +#include +#include +#include +#include + +#include "arcvfs.h" + +ARC_DIRENT * +create_entry (const char *fname, const char *name, ARC_DIRENT *dir) +{ + ARC_DIRENT *ent; + + ent = malloc (sizeof (ARC_DIRENT) + strlen (fname)); + if (ent) + { + strcpy (ent->fullname, fname); + ent->name = ent->fullname + (name - fname); + ent->pdir = dir; + ent->next = 0; +fprintf(stderr, "create_entry(%s, %s)\n", ent->fullname, ent->name); + } + return ent; +} + +ARC_DIRENT * +create_dirent (char *fname, char *name, ARC_DIRENT **p_ent, ARC_DIRENT *dir) +{ + char *s; +fprintf(stderr, "create_dirent(%s, %s)\n", fname, name); + + if (!p_ent) + return 0; + + while ((s = strchr (name, '/')) != 0) + { + *s = '\0'; + while (*p_ent && strcmp (name, (*p_ent)->name)) + p_ent = &(*p_ent)->next; + if (!*p_ent) + { + *p_ent = create_entry (fname, name, dir); + if (!*p_ent) + return 0; + (*p_ent)->size = -1; + (*p_ent)->data.dir.first = 0; + } + /* Check for directory/file clash. */ + if ((*p_ent)->size != -1) + return 0; + dir = *p_ent; + p_ent = &(*p_ent)->data.dir.first; + *s++ = '/'; + name = s; + } + + while (*p_ent) + p_ent = &(*p_ent)->next; + + *p_ent = create_entry (fname, name, dir); + + return *p_ent; +} + +char * +skip_field (char *s) +{ + while (*s == ' ') + ++s; + while (*s != ' ') + ++s; + return s; +} + +static ARC_DIRENT * +root_ent (ARC_DIRENT *ent) +{ + while (ent->pdir != ent) + ent = ent->pdir; + return ent; +} + +/* The generic read/write code. */ + +int +a_open (ARC_DIRENT *ent) +{ + FILE *fp; + char buf[4096]; + ARC_DIRENT *root = root_ent (ent); + + sprintf (buf, root->name, root->fullname, ent->fullname); + fp = popen (buf, "r"); + if (!fp) + return EIO; + ent->data.file.buf = malloc (ent->size); + if (ent->data.file.buf) + { + fread (ent->data.file.buf, ent->size, 1, fp); + fclose (fp); + ++ent->data.file.refc; + return 0; + } + return EFBIG; +} + +int +a_close (ARC_DIRENT *ent) +{ + if (!ent->data.file.refc) + return EBADF; + if (!--ent->data.file.refc) + free (ent->data.file.buf); + return 0; +} + +int +a_read (ARC_DIRENT *ent, long off, long size, + unsigned long *nelem, unsigned char **elems) +{ + char *s; + long n; + + if (!ent->data.file.refc) + return EINVAL; + + s = ent->data.file.buf; + n = ent->size; + + if (off > n) + off = n; + if (size > n - off) + size = n - off; + *elems = s + off; + *nelem = size; + + return 0; +} + +/* The VFS code itself. */ + +struct vfsfn { + ARC_DIRENT *(*fn) (const char *); +} ents[] = { +#ifdef ARCFMT_ZIP + { arc_read_zip }, +#endif +#ifdef ARCFMT_HPACK + { arc_read_hpack }, +#endif +#ifdef ARCFMT_ZOO + { arc_read_zoo }, +#endif +#ifdef ARCFMT_TGZ + { arc_read_tgz }, +#endif + { 0 } +}; + +ARC_DIRENT * +arc_read (const char *zipfile) +{ + int i; + + i = 0; + while (ents[i].fn) + { + ARC_DIRENT *root = ents[i].fn (zipfile); + + if (root) + return root; + ++i; + } + + fprintf (stderr, "%s: not a recognized archive type!\n", zipfile); + return 0; +} Added: trunk/filesystems/arcfs/tgz.c ============================================================================== --- trunk/filesystems/arcfs/tgz.c 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/arcfs/tgz.c 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,95 @@ +/* Access Gzip'd and Compresse'd TARs. */ + +#include "arcvfs.h" + +#ifdef ARCFMT_TGZ + +#include +#include +#include + +static const char excmd[] = "tar xOfz %s %s"; + +ARC_DIRENT * +arc_read_tgz (const char *zipfile) +{ + FILE *fp; + char buf[4096]; + ARC_DIRENT *first = 0; + char *name; + long csize; + + csize = strlen (zipfile); + if (! ( (csize > 4 && !strcmp (zipfile + csize - 4, ".tgz") ) + || (csize > 7 && !strcmp (zipfile + csize - 7, ".tar.gz") ) + || (csize > 6 && !strcmp (zipfile + csize - 6, ".tar.z") ) + || (csize > 6 && !strcmp (zipfile + csize - 6, ".tar.Z") ) + ) + ) + return 0; + + first = create_entry (zipfile, zipfile, 0); + if (!first) + return 0; + first->pdir = first; + first->size = -1; + first->data.dir.first = 0; + first->name = (char *) excmd; + + /* MODE USER/GROUP USIZE MON DD HH:MM YYYY NAME */ + sprintf (buf, "tar tvfz %s", zipfile); + fp = popen (buf, "r"); + if (!fp) + { + perror (buf); + return 0; + } + while (fgets (buf, sizeof (buf), fp)) + { + long usize; + ARC_DIRENT *ent; + int dir_p; + + name = buf + strlen (buf); + if (name > buf && name[-1] == '\n') + *--name = '\0'; + if (name > buf && name[-1] == '/') + { + *--name = '\0'; + dir_p = 1; + } + else + dir_p = 0; + + name = skip_field (buf); /* MODE */ + name = skip_field (name); /* OWNER/GROUP */ + usize = csize = strtol (name, &name, 10); + name = skip_field (name); /* MMM */ + /* name = skip_field (name); */ /* DD */ + name = skip_field (name); /* HH:MM */ + /* name = skip_field (name); */ /* YYYY */ + while (*name == ' ') + ++name; + + ent = create_dirent (name, name, &first->data.dir.first, first); + if (ent) + { + if (dir_p) + { + ent->size = -1; + ent->data.dir.first = 0; + } + else + { + ent->size = usize; + ent->data.file.csize = csize; + ent->data.file.refc = 0; + } + ent->next = 0; + } + } + fclose (fp); + return first; +} + +#endif Added: trunk/filesystems/arcfs/arcvfs.h ============================================================================== --- trunk/filesystems/arcfs/arcvfs.h 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/arcfs/arcvfs.h 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,28 @@ +#ifndef _ARCVFS_H +#define _ARCVFS_H + +#include "arcfs.h" + +#define ARCFMT_ZIP +#undef ARCFMT_HPACK +#undef ARCFMT_ZOO +#define ARCFMT_TGZ + +#ifdef ARCFMT_ZIP +ARC_DIRENT *arc_read_zip (const char *); +#endif +#ifdef ARCFMT_HPACK +ARC_DIRENT *arc_read_hpack (const char *); +#endif +#ifdef ARCFMT_ZOO +ARC_DIRENT *arc_read_zoo (const char *); +#endif +#ifdef ARCFMT_TGZ +ARC_DIRENT *arc_read_tgz (const char *); +#endif + +ARC_DIRENT *create_entry (const char *, const char *, ARC_DIRENT *); +ARC_DIRENT *create_dirent (char *, char *, ARC_DIRENT **, ARC_DIRENT *); +char *skip_field (char *); + +#endif /* _ARCVFS_H */ Added: trunk/filesystems/arcfs/README ============================================================================== --- trunk/filesystems/arcfs/README 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/arcfs/README 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,38 @@ +ArcFS - transparent read-only archive access for Linux + +Copyright (C) 1994 David P Gymer + +Derived in part from code written by Jeremy Fitzhardinge +. + + +This code represents a simple user-level filesystem for Linux using +Jeremy Fitzhardinge's userfs (which must be gotten and installed into +the kernel separately) which presents a zip or tar.gz archive as a +read-only filesystem, allowing one to cd into the archive, use less or +emacs to view files, and ls to view the archive contents. + +It should be easy for even fairly inexperienced C programmers to +extend to other types of archives. + +This code is a quick and dirty hack. It's not meant as anything else; +it works, but it ain't pretty, and it's certainly not bulletproof +(heck, it's not even paper-dart proof!). + +Basic use goes something like this, + "muserfs ./arcfs /mnt/0 ./test.tar.gz" +then you can do + "find /mnt/0 -ls" +and see what's in the archive. After you've finished, make sure no +process has anything in the arhive open (including as it's current +directory; ie. if you did "cd /mnt/0/a.directory", be sure to cd out) +and then hit ^C or send a SIGINT to "arcfs" to kill it and unmount the +archive. + +[I just upgrdaded my copy of umount, and I have to do + "/sbin/umount /mnt/0" +by hand to kill it off completely.] + +-- Dave +dpg@cs.nott.ac.uk (but only til June or July this year :-[ ). +Just Another Linux Hacker Added: trunk/filesystems/arcfs/Makefile ============================================================================== --- trunk/filesystems/arcfs/Makefile 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/filesystems/arcfs/Makefile 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,35 @@ +CC = gcc +CFLAGS = -g -I../../kernel +CPPFLAGS = #-DDEBUG +LDFLAGS = -s + +SRCS = arcfs.c arcvfs.c zip.c tgz.c arcvfs.h arcfs.h +DISTS = $(SRCS) README Makefile + +arcfs : arcfs.o arcvfs.o zip.o tgz.o + +.PHONY : dist dep clean realclean spotless + +dep : .depend +.depend : $(SRCS) + $(CC) $(CFLAGS) -MM *.c > .depend + +dist : $(DISTS) + rm -rf /tmp/arcfs + mkdir /tmp/arcfs + cp -a $(DISTS) /tmp/arcfs + (cd /tmp; tar cfvz - arcfs) >arcfs.tar.gz + rm -rf /tmp/arcfs + +clean : + rm -f *.o core *~ *.orig *.rej arcfs + +realclean : clean + rm -rf arcfs + +spotless : realclean + rm -f .depend + +ifeq (.depend,$(wildcard .depend)) +include .depend +endif Added: trunk/COPYING ============================================================================== --- trunk/COPYING 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/COPYING 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. Added: trunk/Makefile ============================================================================== --- trunk/Makefile 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/Makefile 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,30 @@ +TOP=. +SUBDIRS=genser lwp kernel utils lib + +include rules + +all:: subdirs readmes + +subdirs:: $(DEPEND) + +.depend: depend + touch .depend + +clobber:: clean + find . \( -name .depend -o -name '*~' \) -print | xargs rm -f + +clean:: + rm -f *~ + +install: + insmod kernel/src/userfs.o + +readmes: README README.ps + +README: README.mm + groff -Tascii -mgm $< > $@ || rm -f $@ + +README.ps: README.mm + groff -Tps -mgm $< > $@ || rm -f $@ + +include rules.sub Added: trunk/README.ps ============================================================================== --- trunk/README.ps 2003-05-23 23:51:35 UTC (rev 1) +++ trunk/README.ps 2003-05-29 09:40:42 UTC (rev 2) @@ -0,0 +1,1315 @@ +%!PS-Adobe-3.0 +%%Creator: groff version 1.10 +%%CreationDate: Sat May 24 22:23:42 1997 +%%DocumentNeededResources: font Times-Bold +%%+ font Times-Italic +%%+ font Times-Roman +%%+ font Courier +%%DocumentSuppliedResources: procset grops 1.10 0 +%%Pages: 11 +%%PageOrder: Ascend +%%Orientation: Portrait +%%EndComments +%%BeginProlog +%%BeginResource: procset grops 1.10 0 +/setpacking where{ +pop +currentpacking +true setpacking +}if +/grops 120 dict dup begin +/SC 32 def +/A/show load def +/B{0 SC 3 -1 roll widthshow}bind def +/C{0 exch ashow}bind def +/D{0 exch 0 SC 5 2 roll awidthshow}bind def +/E{0 rmoveto show}bind def +/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def +/G{0 rmoveto 0 exch ashow}bind def +/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def +/I{0 exch rmoveto show}bind def +/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def +/K{0 exch rmoveto 0 exch ashow}bind def +/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def +/M{rmoveto show}bind def +/N{rmoveto 0 SC 3 -1 roll widthshow}bind def +/O{rmoveto 0 exch ashow}bind def +/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def +/Q{moveto show}bind def +/R{moveto 0 SC 3 -1 roll widthshow}bind def +/S{moveto 0 exch ashow}bind def +/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def +/SF{ +findfont exch +[exch dup 0 exch 0 exch neg 0 0]makefont +dup setfont +[exch/setfont cvx]cvx bind def +}bind def +/MF{ +findfont +[5 2 roll +0 3 1 roll +neg 0 0]makefont +dup setfont +[exch/setfont cvx]cvx bind def +}bind def +/level0 0 def +/RES 0 def +/PL 0 def +/LS 0 def +/MANUAL{ +statusdict begin/manualfeed true store end +}bind def +/PLG{ +gsave newpath clippath pathbbox grestore +exch pop add exch pop +}bind def +/BP{ +/level0 save def +1 setlinecap +1 setlinejoin +72 RES div dup scale +LS{ +90 rotate +}{ +0 PL translate +}ifelse +1 -1 scale +}bind def +/EP{ +level0 restore +showpage +}bind def +/DA{ +newpath arcn stroke +}bind def +/SN{ +transform +.25 sub exch .25 sub exch +round .25 add exch round .25 add exch +itransform +}bind def +/DL{ +SN +moveto +SN +lineto stroke +}bind def +/DC{ +newpath 0 360 arc closepath +}bind def +/TM matrix def +/DE{ +TM currentmatrix pop +translate scale newpath 0 0 .5 0 360 arc closepath +TM setmatrix +}bind def +/RC/rcurveto load def +/RL/rlineto load def +/ST/stroke load def +/MT/moveto load def +/CL/closepath load def +/FL{ +currentgray exch setgray fill setgray +}bind def +/BL/fill load def +/LW/setlinewidth load def +/RE{ +findfont +dup maxlength 1 index/FontName known not{1 add}if dict begin +{ +1 index/FID ne{def}{pop pop}ifelse +}forall +/Encoding exch def +dup/FontName exch def +currentdict end definefont pop +}bind def +/DEFS 0 def +/EBEGIN{ +moveto +DEFS begin +}bind def +/EEND/end load def +/CNT 0 def +/level1 0 def +/PBEGIN{ +/level1 save def +translate +div 3 1 roll div exch scale +neg exch neg exch translate +0 setgray +0 setlinecap +1 setlinewidth +0 setlinejoin +10 setmiterlimit +[]0 setdash +/setstrokeadjust where{ +pop +false setstrokeadjust +}if +/setoverprint where{ +pop +false setoverprint +}if +newpath +/CNT countdictstack def +userdict begin +/showpage{}def +}bind def +/PEND{ +clear +countdictstack CNT sub{end}repeat +level1 restore +}bind def +end def +/setpacking where{ +pop +setpacking +}if +%%EndResource +%%IncludeResource: font Times-Bold +%%IncludeResource: font Times-Italic +%%IncludeResource: font Times-Roman +%%IncludeResource: font Courier +grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 +def/PL 792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron +/scaron/zcaron/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/.notdef/.notdef/space/exclam/quotedbl/numbersign/dollar/percent +/ampersand/quoteright/parenleft/parenright/asterisk/plus/comma/hyphen +/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon +/semicolon/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O +/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright/circumflex +/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y +/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase/guillemotleft +/guillemotright/bullet/florin/fraction/perthousand/dagger/daggerdbl +/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut +/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash +/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen +/brokenbar/section/dieresis/copyright/ordfeminine/guilsinglleft +/logicalnot/minus/registered/macron/degree/plusminus/twosuperior +/threesuperior/acute/mu/paragraph/periodcentered/cedilla/onesuperior +/ordmasculine/guilsinglright/onequarter/onehalf/threequarters +/questiondown/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE +/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex +/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis +/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn +/germandbls/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla +/egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis +/eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide/oslash +/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis]def +/Courier@0 ENC0/Courier RE/Times-Roman@0 ENC0/Times-Roman RE +/Times-Italic@0 ENC0/Times-Italic RE/Times-Bold@0 ENC0/Times-Bold RE +%%EndProlog +%%Page: 1 1 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 12/Times-Bold@0 SF(Userfs \255 Filesystems Implemented as User Pr) +155.886 82.031 Q(ocesses)-.216 E/F1 10/Times-Italic@0 SF -.25(Je)204.375 +100.031 S -.37(re).25 G(my F).37 E(itzhar)-.45 E(ding)-.37 E 2.5(e<)-.1 +G(jer)-2.5 E(emy@sw)-.37 E(.oz.au>)-.74 E/F2 10/Times-Roman@0 SF(Softw) +253.095 118.031 Q(ay Pty)-.1 E 2.5(.L)-.65 G(td.)-2.5 E F1 2.5(1. Intr) +72 166.031 R(oduction)-.45 E F2 .156(Userfs is a mechanism by which nor\ +mal user processes can be a Linux \214lesystem.)72 184.031 R .155 +(There are man)5.155 F 2.655(yu)-.15 G .155(ses for)-2.655 F +(this, including:)72 196.031 Q(Prototype \214lesystems)72 214.031 Q .051 +(Prototype ne)97 232.031 R 2.551(wb)-.25 G .052 +(lock allocation algorithms in a user process and deb)-2.551 F .052 +(ug with gdb before going into the)-.2 F(compile-crash-reboot c)97 +244.031 Q(ycle of k)-.15 E(ernel de)-.1 E -.15(ve)-.25 G(lopment.).15 E +(Infrequent use \214lesystems)72 262.031 Q -1.1(Yo)97 280.031 S 3.08(uw) +1.1 G .58(ant to mount "F)-3.18 F .58 +(ooBaz 0X" \214lesystems under Linux, b)-.15 F .579(ut you don')-.2 F +3.079(tw)-.18 G .579(ant it that often, and you)-3.179 F(don')97 292.031 +Q 2.675(tn)-.18 G .175(eed it to be maximum speed.)-2.675 F .176 +(Rather than trying to get the k)5.175 F .176 +(ernel itself to understand, or write)-.1 F +(specialised tools, write a \214lesystem program.)97 304.031 Q +(Add capabilities to e)72 322.031 Q(xisting \214lesystems)-.15 E -.8(Wa) +97 340.031 S .764(nt compression, encryption, A).8 F 3.264(CLs? Ha)-.4 F +1.064 -.15(ve a p)-.2 H .764(rocess to mirror an e).15 F .764 +(xisting \214le tree, b)-.15 F .764(ut with your)-.2 F -.25(ow)97 +352.031 S 2.5(ne).25 G(xtentions and semantics.)-2.65 E +(Completely virtual \214lesystems and ne)72 370.031 Q 2.5(wi)-.25 G +(nterf)-2.5 E(aces)-.1 E .642(Add a \214lesystem-type interf)97 388.031 +R .642(ace to an e)-.1 F .643 +(xisting mechanism, or a \214lesystem interf)-.15 F .643(ace as a ne)-.1 +F 3.143(ww)-.25 G .643(ay of)-3.243 F(representing data.)97 400.031 Q +(Sick of FTP?)5 E(Ho)5 E 2.5(wa)-.25 G(bout)-2.5 E/F3 9/Courier@0 SF 5.4 +($m)122 417.031 S(kdir /ftp/tsx-11.mit.edu)-5.4 E 5.4($c)122 428.031 S +5.4(d/)-5.4 G(ftp/tsx-11.mit.edu/pub/linux)-5.4 E 5.4($c)122 439.031 S +5.4(pR)-5.4 G(EADME $HOME)-5.4 E F2(Or mail?)97 457.031 Q F3 5.4($c)122 +474.031 S 5.4(d/)-5.4 G(mail)-5.4 E 5.4($l)122 485.031 S(s)-5.4 E +(001.sbg@socs.uts.edu.au)122 496.031 Q(002.Leroy)122 507.031 Q +(003.tlukka@vinkku.hut.fi)122 518.031 Q(004.Davor_Jadrijevic)122 529.031 +Q 5.4($c)122 540.031 S(at */From)-5.4 E(From: sbg@socs.uts.edu.au)122 +551.031 Q(From: leroy@socs.uts.edu.au \(Leroy\))122 562.031 Q +(From: tlukka@vinkku.hut.fi)122 573.031 Q +(From: davor%emard.uucp@ds5000.irb.hr \(Davor Jadrijevic\))122 584.031 Q +5.4($c)122 595.031 S(at */Subject)-5.4 E(Subject: More things)122 +606.031 Q(Subject: \(none\))122 617.031 Q(Subject: That userfs thing)122 +628.031 Q(Subject: mailfs again)122 639.031 Q($)122 650.031 Q F2 -1.1 +(Yo)72 668.031 S 2.5(ug)1.1 G(et the idea.)-2.5 E F1 2.5 +(2. Installation)72 692.031 R EP +%%Page: 2 2 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF 2.5(-2-)279.67 48 S/F1 10/Times-Italic@0 SF 2.5 +(2.1 K)72 96 R(ernel)-.35 E F0 .026(First of all, if you ha)72 114 R +.326 -.15(ve i)-.2 H .026(nstalled userfs before, remo).15 F .326 -.15 +(ve t)-.15 H .026(races of pre).15 F .026(vious v)-.25 F .026 +(ersions of userfs: mak)-.15 F 2.526(es)-.1 G .026(ure there)-2.526 F +(are no userfs header \214les in)72 126 Q F1(linux/include/linux)2.5 E +F0(and no userfs patches to an)2.5 E 2.5(yo)-.15 G 2.5(ft)-2.5 G(he k) +-2.5 E(ernel source.)-.1 E 1.171(Otherwise, the k)72 144 R 1.171 +(ernel module should just compile with the rest of the b)-.1 F 1.172 +(uild process.)-.2 F 1.172(Userfs is currently)6.172 F 2.296 +(supported for 2.0.x \(tested up to 2.0.0\), and for 1.3.x.)72 156 R +2.295(It should w)7.295 F 2.295(ork out the k)-.1 F 2.295(ernel v)-.1 F +2.295(ersion you')-.15 F(re)-.5 E .355 +(compiling for and con\214gure itself appropriately)72 168 R 5.355(.T) +-.65 G .355(here are no k)-5.355 F .356 +(ernel patches and compiling userfs into the)-.1 F -.1(ke)72 180 S +(rnel is not supported.).1 E 1.925 -.8(To i)72 198 T .325 +(nstall the module you need the).8 F/F2 10/Times-Bold@0 SF(modutils) +2.825 E F0 .325(package, which should be a)2.825 F -.25(va)-.2 G .324 +(ilable from your local Linux ftp).25 F(archi)72 210 Q -.15(ve)-.25 G +6.414(.I).15 G 3.914(ts)-6.414 G 1.415 +(hould be clear from its documentation what you need to do with)-3.914 F +F1(userfs.o)3.915 E F0 1.415(to get it into the)3.915 F -.1(ke)72 222 S +3.413(rnel. If).1 F .912(you get some w)3.413 F .912 +(arnings about multiply de\214ned symbols, ignore them:)-.1 F .912 +(only unde\214ned symbols)5.912 F(are a problem.)72 234 Q -1.1(Yo)5 G +2.5(uc)1.1 G(an compile the k)-2.5 E +(ernel and module with either ELF or a.out compilers; I used ELF)-.1 E +(.)-.8 E .211(The k)72 252 R .212(ernel module supports modv)-.1 F .212 +(erions, so it generally w)-.15 F(on')-.1 E 2.712(tb)-.18 G 2.712(en) +-2.712 G .212(ecessary to recompile it for e)-2.712 F -.15(ve)-.25 G +.212(ry k).15 F(ernel)-.1 E -.15(ve)72 264 S(rsion;).15 E F1(insmod)2.79 +E F0 .29(will let you kno)2.79 F 2.79(wi)-.25 G 2.79(fy)-2.79 G .29 +(ou need to recompile the userfs module \(with luck - otherwise Linux) +-2.79 F(will helpfully let you kno)72 276 Q 2.5(ww)-.25 G +(ith obscure beha)-2.5 E(viour or k)-.2 E(ernel panics...\).)-.1 E F1 +2.5(2.2 Non-k)72 294 R(ernel Code)-.1 E F0 1.384 +(Building the rest of the code should be a matter of typing "mak)72 312 +R 1.384(e" at the top userfs directory)-.1 F 3.885(.T)-.65 G 1.385 +(his will)-3.885 F .807(generate dependencies and b)72 324 R .807 +(uild the utilities needed \(genser\), the library)-.2 F 3.307(,t)-.65 G +.806(he clients using the library and)-3.307 F(the k)72 336 Q +(ernel module.)-.1 E(There will be some w)5 E(arnings; ignore them.)-.1 +E 3.567(Iu)72 354 S 1.068(sed gcc 2.7.0; you probably need to use the l\ +atest compiler and libraries \(libg++ 2.7.0.1\) for the C++)-3.567 F +(\(though I')72 366 Q .3 -.15(ve a)-.5 H -.2(vo)-.05 G +(ided templates and e).2 E +(xceptions; g++ has enough problems with simple things\).)-.15 E F1 2.5 +(2.3 Mailing)72 384 R(list)2.5 E F0 .694 +(The old USERFS channel on the Linux Acti)72 402 R .693(vists list serv) +-.25 F .693(er is no)-.15 F 3.193(wd)-.25 G 3.193(efunct. There)-3.193 F +.693(is a ne)3.193 F 3.193(wl)-.25 G(ist:)-3.193 E/F3 10/Courier@0 SF +(linux-)3.193 E(userfs@vger.rutgers.edu)72 414 Q F0 5.464(.T)C 2.964(os) +-6.264 G .464(ubscribe, send mail to)-2.964 F F3 +(majordomo@vger.rutgers.edu)2.965 E F0(with)2.965 E(the contents)72 426 +Q/F4 9/Courier@0 SF(subscribe linux-userfs [your email address])97 443 Q +F1 2.5(2.4 Bugs,)72 461 R(comments, etc)2.5 E F0 .361 +(When you \214nd a b)72 479 R .361(ug, tell me.)-.2 F .361 +(Please send me the code you')5.361 F .36(re using, the k)-.5 F .36 +(ernel v)-.1 F .36(ersion, whate)-.15 F -.15(ve)-.25 G 2.86(rc).15 G +(hanges)-2.86 E(you')72 491 Q .808 -.15(ve m)-.5 H .509(ade to userfs k) +.15 F .509(ernel code, and instructions or a script to reproduce the b) +-.1 F 3.009(ug. Don')-.2 F 3.009(tj)-.18 G .509(ust tell me "it)-3.009 F +(brok)72 503 Q(e.")-.1 E 1.174(If you')72 521 R 1.474 -.15(ve m)-.5 H +1.174(ade changes to the k).15 F 1.174 +(ernel code, please send it to me rather than sending it out to the w) +-.1 F(orld.)-.1 E 2.177(Please send me comments, ideas for ne)72 533 R +4.677(wk)-.25 G 2.177(ernel features, or things that you think w)-4.777 +F 2.177(ould mak)-.1 F 4.677(eg)-.1 G(ood)-4.677 E .637(\214lesystems b) +72 545 R .637(ut you can')-.2 F 3.137(td)-.18 G 3.137(or)-3.137 G .637 +(ight no)-3.137 F 4.437 -.65(w. A)-.25 H .636 +(lso feel free to ask questions about either the implementation of).65 F +(my code, ho)72 557 Q 2.5(wt)-.25 G 2.5(ow)-2.5 G(rite your o)-2.5 E +(wn userfs clients, or e)-.25 E -.15(ve)-.25 G 2.5(nj).15 G +(ust to tell me you got it w)-2.5 E(orking.)-.1 E +(Send mail to either me \(Jeremy Fitzhardinge \) or to the mailing list \(see abo)-.65 E -.15(ve)-.15 G(\).) +.15 E F1 2.5(3. Using)72 599 R(clients)2.5 E F0 .337 +(Clients are generally mounted with the)72 617 R F2(muserfs)2.837 E F0 +2.837(command. It')2.837 F 2.837(sq)-.55 G .337(uite simple \255 it') +-2.837 F 2.837(sap)-.55 G .337(rogram which mak)-2.837 F(es)-.1 E 1.893 +(sure the mount point is le)72 629 R -.05(ga)-.15 G 4.393(lf).05 G 1.893 +(or the user to mount on, and mounts the gi)-4.393 F -.15(ve)-.25 G +4.392(np).15 G 1.892(rocess with the user')-4.392 F(s)-.55 E 2.557 +(permissions. Note)72 641 R .057(that an)2.557 F 2.557(yu)-.15 G .057(s\ +er can mount a process, so more checking is done on the mount point tha\ +n for)-2.557 F 2.563(an)72 653 S .063(ormal mount.)-2.563 F .062 +(Unless the user is root, the mount point must be o)5.062 F .062 +(wned by the user and writable.)-.25 F F2(muserfs)5.062 E F0 +(has a man page, which is e)72 665 Q -.15(ve)-.25 G 2.5(nu).15 G 2.5(pt) +-2.5 G 2.5(od)-2.5 G(ate.)-2.5 E(There are a fe)72 683 Q 2.5(wu)-.25 G +(seful or semi-useful clients:)-2.5 E F2(homer)2.5 E F0(,)A F2(ftpfs)2.5 +E F0(,)A F2(mailfs)2.5 E F0(and)2.5 E F2(ar)2.5 E(cfs.)-.18 E F0 +(Homer is)72 701 Q .207(written in C++, and uses the C++ library in the\ + lib directory to do most of its w)2.706 F 2.707(ork. All)-.1 F .207 +(it does is)2.707 F .579(set up a single directory under its mount poin\ +t which contains symbolic links named after each user)97 713 R .464 +(name in the passw)97 725 R .464 +(ord \214le, which points to the associated home directory)-.1 F 5.464 +(.M)-.65 G .464(ounted on /u it mak)-5.464 F .465(es a)-.1 F +(passible replacement for ~ e)97 737 Q(xpansion in a shell \(b)-.15 E +(ut it w)-.2 E(orks for an)-.1 E 2.5(yp)-.15 G(rogram\).)-2.5 E EP +%%Page: 3 3 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF 2.5(-3-)279.67 48 S 1.94(Ftpfs is)72 96 R 1.384 +(an e)3.884 F 1.384(xperimental \214lesystem which allo)-.15 F 1.384 +(ws readonly access to FTP sites, maintaining a long-term)-.25 F .974 +(disk cache.)97 108 R .974(Its intended primarily for anon)5.974 F .975 +(ymous FTP)-.15 F 3.475(,b)-1.11 G .975 +(ut can also be used for authenticated FTP)-3.675 F(sessions.)97 120 Q +(Mailfs is)72 138 Q 1.055(by Da)3.555 F -.2(vo)-.2 G 3.555(rJ).2 G +(adrije)-3.555 E 3.555(vic. It)-.25 F 1.054(is for reading mail.)3.555 F +1.054(Currently its read-only and does not track mailbox)6.054 F +(changes, and is no longer being acti)97 150 Q -.15(ve)-.25 G(ly de).15 +E -.15(ve)-.25 G 2.5(loped. Pester).15 F(Da)2.5 E -.2(vo)-.2 G 2.5(r\() +.2 G(or \214x it yourself\).)-2.5 E .29(Arcfs w)72 168 R .283 +(as written by Da)-.1 F .283(vid Gymer)-.2 F 5.283(.I)-.55 G 2.783(ta) +-5.283 G(llo)-2.783 E .284 +(ws you to mount a compressed tar \214le as a read-only \214lesystem,) +-.25 F .712(and inspect it with normal tools.)97 180 R(It')5.711 E 3.211 +(sp)-.55 G .711(retty neat, b)-3.211 F .711(ut not recommended for hea) +-.2 F .711(vy "production" use,)-.2 F(or for v)97 192 Q(ery lar)-.15 E +(ge \214les.)-.18 E/F1 10/Times-Italic@0 SF 2.5(4. Theory)72 216 R +(of oper)2.5 E(ation)-.15 E F0 .638(The k)72 234 R .638(ernel module re) +-.1 F .638(gisters a ne)-.15 F 3.138<778c>-.25 G .638 +(lesystem type with the k)-3.138 F .638(ernel \("userfs"\).)-.1 F .638 +(The \214lesystem itself is v)5.638 F(ery)-.15 E .754 +(simple; all it does it tak)72 246 R .754(es the normal k)-.1 F .754 +(ernel \214lesystem requests, wraps them up into well-de\214ned pack)-.1 +F(ets)-.1 E 1.107(and squirts them do)72 258 R 1.107 +(wn a \214le descriptor \(presumeably connected to a process\) and w) +-.25 F 1.107(aits for the reply on)-.1 F(another \214le descriptor)72 +270 Q(.)-.55 E 1.588(If the \214lesystem process is on the same machine\ +, then the \214le descriptors are probably ordinary pipes.)72 288 R(Ho) +72 300 Q(we)-.25 E -.15(ve)-.25 G 2.546 -.4(r, u).15 H 1.747 +(serfs just reads and writes on the \214le descriptors, so the).4 F +4.247(yc)-.15 G 1.747(ould be an)-4.247 F 1.747(ything; \214les, sock) +-.15 F(ets,)-.1 E(de)72 312 Q(vices \255 userfs doesn')-.25 E 2.5(tc) +-.18 G(are.)-2.5 E 1.954(The follo)72 330 R 1.954 +(wing is not a comprehensi)-.25 F 2.254 -.15(ve t)-.25 H 1.954 +(utorial on writing \214lesystems, or a detailed "ho).15 F 4.453(wi)-.25 +G 4.453(tw)-4.453 G 1.953(orks" or)-4.553 F 1.862 +(speci\214cation of the e)72 342 R 1.862(xisting code.)-.15 F 1.863 +(It is intended to gi)6.863 F 2.163 -.15(ve s)-.25 H 1.863 +(ome idea of what I w).15 F 1.863(as thinking, and basic)-.1 F +(concepts to bear in mind while poking about in my k)72 354 Q +(ernel or user code.)-.1 E F1 2.5(4.1 Priorities)72 372 R F0 2.5(Ih)72 +390 S(ad a number of goals which I w)-2.5 E +(anted satis\214ed by this thing \(from most to least important\):)-.1 E +(Fle)72 408 Q(xibility)-.15 E 3.607(Iw)97 426 S 1.107 +(ant the process to ha)-3.707 F 1.407 -.15(ve a)-.2 H 3.607(sm).15 G +1.107(uch po)-3.607 F 1.106(wer as a k)-.25 F 1.106 +(ernel-resident \214lesystem as possible.)-.1 F 3.606(Iw)6.106 G 1.106 +(anted to)-3.706 F -.1(ke)97 438 S(ep the interf).1 E +(aces as generic and \215e)-.1 E 2.5(xible. This)-.15 F +(has been mostly achie)2.5 E -.15(ve)-.25 G(d.).15 E(Rob)72 456 Q +(ustness)-.2 E .281(Since I see prototyping and de)97 474 R -.15(ve)-.25 +G .281(lopment a major use for userfs, it seems important to mak).15 F +2.782(es)-.1 G .282(ure that)-2.782 F 1.336(the k)97 486 R 1.336 +(ernel code can')-.1 F 3.836(t\()-.18 G 1.336(at w)-3.836 F 1.336 +(orst\) crash or lock up if the user code f)-.1 F 3.836(ails. As)-.1 F +1.336(it stands, it should be)3.836 F .632 +(impossible for a user process to crash the k)97 498 R .632(ernel, b)-.1 +F .632(ut it is possible for a bad user process to lock up)-.2 F +(processes trying to use the \214lesystem.)97 510 Q 1.668(It is also po\ +ssible for a process to go strange while it is being mounted, lea)97 528 +R 1.667(ving a half-mounted)-.2 F 5.066(\214lesystem. The)97 540 R 2.566 +(mountpoint becomes a nulled out inode, b)5.066 F 2.567(ut the k)-.2 F +2.567(ernel refuses to unmount it)-.1 F .899(\(because it isn')97 552 R +3.398(tm)-.18 G .898(ounted\), and refuses to mount on it \(because it') +-3.398 F 3.398(sb)-.55 G 3.398(usy\). This)-3.598 F .898 +(happens much less)3.398 F .956(often than it used to, because muserfs \ +does a simple check to see if the \214lesystem process is at all)97 564 +R(viable.)97 576 Q -1.27 -.74(Av a)72 594 T +(ilability to users and Security).74 E(I')97 612 Q 3.623(dl)-.5 G(ik) +-3.623 E 3.623(ea)-.1 G 1.423 -.15(ny u)-3.623 H 1.123 +(ser to be able to write a \214lesystem process.).15 F -.35(Tr)6.122 G +(aditionally).35 E 3.622<2c8c>-.65 G 1.122(lesystems are things that) +-3.622 F .25(embody the security of Unix, and are therefore v)97 624 R +.251(ery much superuser)-.15 F .251(-only things.)-.2 F(Ho)5.251 E(we) +-.25 E -.15(ve)-.25 G 1.051 -.4(r, t).15 H .251(here are).4 F 1.259 +(only a couple of really sensiti)97 636 R 1.559 -.15(ve f)-.25 H 1.259 +(eatures that shouldn').15 F 3.759(tb)-.18 G 3.759(ea)-3.759 G 1.259 +(ble to be controlled by an)-3.759 F 3.758(yu)-.15 G 1.258(ser: suid) +-3.758 F -.15(exe)97 648 S 1.156(cutables and de).15 F 1.156 +(vice nodes.)-.25 F 1.156 +(Since a trusted superuser process is still required to call the mount) +6.156 F .99(system call, and that process can set the no-suid and no-de) +97 660 R .989(vice \215ags, the \214lesystem code can')-.25 F 3.489(tu) +-.18 G(se)-3.489 E .35(these as security holes.)97 672 R 2.85(Ic)5.35 G +(an')-2.85 E 2.85(tt)-.18 G .35(hink of an)-2.85 F .35 +(ything else that needs special care from a security point of)-.15 F +(vie)97 684 Q 4.093 -.65(w. H)-.25 H -.25(ow).65 G -2.15 -.25(ev e).25 H +1.093 -.4(r, s).25 H .292(ince the \214lesystem is completely under the\ + control of the process, one can mak).4 F 2.792(en)-.1 G(o)-2.792 E .576 +(assumptions about its contents.)97 696 R -.15(Fo)5.576 G 3.076(re).15 G +.576(xample "." and ".." may not do e)-3.226 F .576 +(xpected things, symlinks may)-.15 F .677 +(point to places other than what readlink returns.)97 708 R .677 +(This mak)5.677 F .677(es na)-.1 F(vig)-.2 E .676 +(ating such \214lesystems a ne)-.05 F 3.176(wa)-.25 G(nd)-3.176 E +(interesting e)97 720 Q(xperience.)-.15 E EP +%%Page: 4 4 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF 2.5(-4-)279.67 48 S(Ef)72 96 Q(\214cienc)-.25 E +(y)-.15 E(Ef)97 114 Q(\214cienc)-.25 E 3.763(yi)-.15 G 3.763(sm)-3.763 G +3.763(yl)-3.763 G -.25(ow)-3.763 G 1.263(est priority).25 F 3.763(,b) +-.65 G 1.264(ut it is still important.)-3.963 F 1.264 +(Unfortunately the other requirements \(as)6.264 F .932(usual\) mak)97 +126 R 3.432(et)-.1 G .932(hings less ef)-3.432 F 3.432(\214cient. The) +-.25 F .932(most signi\214cant inef)3.432 F(\214cienc)-.25 E 3.431(yi) +-.15 G 3.431(st)-3.431 G .931(he conte)-3.431 F .931 +(xt switches between)-.15 F .416(the k)97 138 R .416 +(ernel and the process.)-.1 F 2.916(It)5.416 G .417 +(hink the most bene\214ts can be g)-2.916 F .417 +(ained by reducing the number of these.)-.05 F(There are se)97 150 Q +-.15(ve)-.25 G(ral approaches to this:).15 E/F1 8/Times-Roman@0 SF<83> +114.2 168 Q F0 .037(If the process w)5 F .036(ants a def)-.1 F .036 +(ault beha)-.1 F .036 +(viour for an operation, then it can be done in the k)-.2 F 2.536 +(ernel. The)-.1 F 1.631(best e)122 180 R 1.631 +(xample of this is permission checking - if the process w)-.15 F 1.632 +(ants normal unix permission)-.1 F .667(checking then it doesn')122 192 +R 3.167(tn)-.18 G .666(eed to do it itself.)-3.167 F .666 +(Otherwise it can tak)5.666 F 3.166(ea)-.1 G .666 +(ll the permission requests)-3.166 F 2.037(from the k)122 204 R 2.037 +(ernel, and implement other permission policies.)-.1 F 2.038 +(This is currently implemented.)7.037 F .68 +(When the \214lesystem is \214rst mounted, the k)122 216 R .68 +(ernel asks the process what requests it will accept.)-.1 F .365 +(From that point the k)122 228 R .365(ernel will do sensible def)-.1 F +.366(ault actions for requests that the process doesn')-.1 F(t)-.18 E +-.1(wa)122 240 S(nt to handle rather than sending them do).1 E +(wn the connection.)-.25 E F1<83>114.2 258 Q F0 1.006 +(Group requests commonly issued together into one.)5 F 1.006 +(This is hard, since the main k)6.006 F 1.005(ernel tells)-.1 F 1.172 +(the \214lesystem code v)122 270 R 1.173 +(ery little about what it is doing, so it is hard to kno)-.15 F 3.673 +(ww)-.25 G 1.173(hat to do ne)-3.673 F(xt.)-.15 E(Ho)122 282 Q(we)-.25 E +-.15(ve)-.25 G 1.609 -.4(r, t).15 H .809(here are a couple of single k) +.4 F .808(ernel requests that are implemented in the protocol as)-.1 F +(tw)122 294 Q 2.5(oo)-.1 G 2.5(rm)-2.5 G(ore transactions.)-2.5 E +(This could be \214x)5 E(ed in future.)-.15 E F1<83>114.2 312 Q F0 .767 +(Data can be cached in the k)5 F 3.267(ernel. This)-.1 F .767 +(is the most trick)3.267 F 2.067 -.65(y, s)-.15 H .767(ince k).65 F .767 +(ernel caching or read-ahead)-.1 F .182 +(limits the amount of control the process can ha)122 324 R .482 -.15 +(ve ove)-.2 H 2.682(rt).15 G .182(he data once read.)-2.682 F 2.681(It) +5.181 G .181(hink this could be)-2.681 F .488(optionally implemented, d\ +epending on whether the process says it is OK to do caching, and if)122 +336 R(so what kinds.)122 348 Q 2.067 +(Currently directory readahead is implemented with the)122 366 R/F2 10 +/Times-Bold@0 SF(upp_multir)4.566 E(eaddir)-.18 E F0 4.566 +(operation. This)4.566 F(allo)122 378 Q 1.466 +(ws the \214lesystem process to return as man)-.25 F 3.967(yd)-.15 G +1.467(irectory entries as it lik)-3.967 F 1.467(es, which are then)-.1 F +(sa)122 390 Q -.15(ve)-.2 G 3.139(di).15 G 3.139(nar)-3.139 G .639 +(eadahead b)-3.139 F(uf)-.2 E(fer)-.25 E 5.638(.I)-.55 G 3.138(ft)-5.638 +G(here')-3.138 E 3.138(saf)-.55 G .638 +(uture request which can be satis\214ed by this b)-3.138 F(uf)-.2 E .638 +(fer it)-.25 F .631 +(is, rather than sending another message to the \214lesystem.)122 402 R +.632(In 1.3.x k)5.632 F .632(ernels, userfs can transfer)-.1 F 1.526(th\ +e whole lot to the process reading the directory in one syscall \(assum\ +ing the process has)122 414 R .401(enough space allocated for it\).)122 +426 R .401 +(This is a win if there are lots of linear directory searches \(such) +5.401 F(as shell globbing, ls or pwd\).)122 438 Q F1<83>114.2 456 Q F0 +4.051(Al)5 G(ar)-4.051 E 1.551(ger than 4k maximum pack)-.18 F 1.551 +(et size can be used, no)-.1 F 4.05(wt)-.25 G 1.55(hat the k)-4.05 F +1.55(ernel memory allocator)-.1 F(allo)122 468 Q 2.956(ws lar)-.25 F +2.956(ger than 4k memory allocations.)-.18 F(Ho)7.957 E(we)-.25 E -.15 +(ve)-.25 G 3.757 -.4(r, s).15 H 2.957(ince pipes are the most common).4 +F .26(connection be)122 480 R .26(ween \214lesystems and k)-.25 F .26 +(ernels, and pipes can hold at most 4k of data, there w)-.1 F(ould)-.1 E +1.31(still be a conte)122 492 R 1.311 +(xt switch between \214lesystem code and k)-.15 F 1.311(ernel e)-.1 F +-.15(ve)-.25 G 1.311(ry 4k, so there w).15 F(ouldn')-.1 E 3.811(tb)-.18 +G(e)-3.811 E(much g)122 504 Q(ain.)-.05 E 3.713(An)97 522 S 1.212 +(umber of people ha)-3.713 F 1.512 -.15(ve s)-.2 H 1.212 +(uggested adding shared memory between the k).15 F 1.212 +(ernel and the \214lesystem)-.1 F 2.951(process. This)97 534 R -.1(wo) +2.951 G .451(uld be quite limiting and least lik).1 F .451 +(ely option to impro)-.1 F .751 -.15(ve t)-.15 H 2.952(hings. At).15 F +.452(the moment, the)2.952 F .01(\214lesystem mak)97 546 R .01(es no as\ +sumptions about the nature of the \214le descriptors for talking to the\ + process.)-.1 F -.8(To)5.01 G .028 +(implement shared memory between the k)97 558 R .029 +(ernel and the process w)-.1 F .029(ould require some w)-.1 F .029 +(ay of \214nding the)-.1 F .196 +(process on the other end of the \214le descriptors \(if an)97 570 R +.195(y\), and playing around with memory maps.)-.15 F(This)5.195 E .359 +(still w)97 582 R(ouldn')-.1 E 2.859(tc)-.18 G .359(ut do)-2.859 F .359 +(wn on the number of conte)-.25 F .36(xt switches at all \(it may e)-.15 +F -.15(ve)-.25 G 2.86(ni).15 G .36(ncrease the number of)-2.86 F +(switches because of syncronisation\).)97 594 Q/F3 10/Times-Italic@0 SF +2.5(4.2 Pr)72 612 R(otocol)-.45 E F0 .778 +(The protocol used is machine independent, using netw)72 630 R .778 +(ork byte order and de\214ned type sizes.)-.1 F .778(The code to)5.778 F +.567(do the pack)72 642 R .568(etisation and depack)-.1 F .568 +(etisation is generated automatically by a program, gi)-.1 F -.15(ve) +-.25 G 3.068(nt).15 G .568(he description of)-3.068 F(each pack)72 654 Q +2.5(et. This)-.1 F(is not fully portable, b)2.5 E(ut it a)-.2 E -.2(vo) +-.2 G(ids byte order and structure alignment problems.).2 E 3.654(Ap)72 +672 S(ack)-3.654 E 1.154(et to or from the k)-.1 F 1.154(ernel has tw) +-.1 F 3.654(op)-.1 G 3.654(arts. The)-3.654 F 1.153 +(\214rst is a header that contains a sequence number)3.653 F 3.653(,a) +-.4 G(n)-3.653 E .745(operation type, a pack)72 684 R .746 +(et type, size of the follo)-.1 F .746(wing data, and a protocol v)-.25 +F .746(ersion number)-.15 F 5.746(.T)-.55 G .746(he pack)-5.746 F .746 +(et type)-.1 F 1.126(can either be a request, a reply or an enquiry)72 +696 R 6.126(.R)-.65 G 1.126(equests and enquiries are al)-6.126 F -.1 +(wa)-.1 G 1.125(ys from the k).1 F 1.125(ernel to the)-.1 F .041 +(process, and the process only e)72 708 R -.15(ve)-.25 G 2.541(rs).15 G +.041(ends replies to the k)-2.541 F 2.541(ernel. A)-.1 F(reply')2.541 E +2.541(sh)-.55 G .041(eader has one e)-2.541 F .041 +(xtra \214eld - an error)-.15 F .764 +(\214eld, containing an error number)72 720 R 5.764(.R)-.55 G .764 +(eplies al)-5.764 F -.1(wa)-.1 G .764(ys ha).1 F 1.064 -.15(ve t)-.2 H +.763(he same sequence number as their corresponding).15 F .486 +(request or enquiry)72 732 R 5.486(.I)-.65 G 2.987(ft)-5.486 G .487 +(here w)-2.987 F .487(as an error performing the operation the error \ +\214eld is set to the error number)-.1 F EP +%%Page: 5 5 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF 2.5(-5-)279.67 48 S +(and there is no additional data returned.)72 96 Q +(If there is no error the error \214eld is set to 0.)5 E -.15(Fo)72 114 +S(llo).15 E 1.744(wing a request or reply pack)-.25 F 1.744 +(et is the optional operation-speci\214c data.)-.1 F 1.744 +(This is passed through the)6.744 F +(protocol for interpretation by the operation routines at each end.)72 +126 Q 1.245(The k)72 144 R 1.245(ernel may ha)-.1 F 1.545 -.15(ve m)-.2 +H 1.245(ultiple outstanding requests.).15 F 1.245(In other w)6.245 F +1.245(ords, the k)-.1 F 1.245(ernel may send a ne)-.1 F 3.745(wr)-.25 G +(equest)-3.745 E 1.56(before recei)72 156 R 1.56(ving a reply to a pre) +-.25 F 1.56(vious one.)-.25 F 1.559(This allo)6.56 F 1.559 +(ws the \214lesystem to block one process for a slo)-.25 F(w)-.25 E .718 +(operation while other processes can use the \214lesystem for shorter o\ +perations.)72 168 R .718(This impro)5.718 F -.15(ve)-.15 G 3.218(sp).15 +G(erformance)-3.218 E .839(on, for e)72 180 R .839 +(xample, an ftp \214lesystem, where one process may be using a f)-.15 F +.839(ast local link, and another may be)-.1 F 1.28(using a slo)72 192 R +3.78(wi)-.25 G 1.28(nternational one, and each has to w)-3.78 F 1.28 +(ait for its o)-.1 F 1.28(wn requests to be satis\214ed.)-.25 F 1.28 +(Of course this)6.28 F .163(requires the \214lesystem process to be wri\ +tten with some form of multi-threading.)72 204 R .162 +(If the \214lesystem just reads)5.162 F .613 +(requests, acts on them and replies then it can do so and ignore an)72 +216 R 3.113(yk)-.15 G .613(ernel requests until it is ready to deal) +-3.213 F(with them.)72 228 Q/F1 10/Times-Italic@0 SF 2.5(4.3 Handles)72 +246 R F0 .24(The base element of a \214lesystem is an)72 264 R F1(inode) +2.74 E F0 5.24(.T).18 G .239(here is an e)-5.24 F .239 +(xact one to one relationship between inodes and)-.15 F .626 +(\214les \(where a)72 276 R F1(\214le)3.126 E F0 .626 +(in this case can be an)3.126 F 3.127<798c>-.15 G .627 +(lesystem object, lik)-3.127 F 3.127(ean)-.1 G .627 +(ormal \214le, a directory and so on\).)-3.127 F(The)5.627 E -.1(ke)72 +288 S .373(rnel needs to be able to uniquely identify inodes.).1 F .372 +(Inodes are uniquely numbered within a \214lesystem, b)5.372 F(ut)-.2 E +.727(each mounted \214lesystem has its o)72 300 R .727(wn numbering.) +-.25 F .728(Therefore an inode is completely identi\214ed by an inode) +5.727 F .751(number and a \214lesystem identi\214er \(or)72 312 R F1(de) +3.251 E(vice)-.15 E F0 3.251(,t).18 G .751(hough it doesn')-3.251 F +3.251(tm)-.18 G .75(ean much for a \214lesystem which has no)-3.251 F +(ph)72 324 Q(ysical hardw)-.05 E(are associated with it\).)-.1 E 3.382 +(Ad)72 342 S -.25(ev)-3.382 G .882 +(ice is what distinguishes mounted \214lesystems from one another).25 F +3.382(,a)-.4 G .882(nd an inode is what distinguishes)-3.382 F .286 +(\214les within a \214lesystem from each other)72 354 R 5.286(.I)-.55 G +.286(node numbers are generated by each \214lesystem, and are used by) +-5.286 F 2.67(the k)72 366 R 2.67(ernel to refer to speci\214c \214les \ +to the \214lesystem speci\214c code.)-.1 F 2.67 +(User process \214lesystems are no)7.67 F -.15(ex)72 378 S .824 +(ception: between the k).15 F .824 +(ernel and the \214lesystem process, \214les are refered to by using)-.1 +F F1(handles)3.323 E F0 3.323(,w).27 G .823(hich are)-3.323 F 1.482 +(essentially 32 bit unsigned numbers.)72 390 R 1.482 +(When a \214lesystem \214rst mentions a \214le to the k)6.482 F 1.483 +(ernel, it gi)-.1 F -.15(ve)-.25 G 3.983(si).15 G 3.983(ta)-3.983 G .509 +(handle, which the k)72 402 R .509 +(ernel uses for all later operations on the \214le.)-.1 F .508 +(It the the handle which identi\214es the \214le,)5.508 F .144(rather t\ +han the name, so it is important to use distinct handles for distinct \ +\214les, and ne)72 414 R -.15(ve)-.25 G 2.644(rc).15 G .144 +(hange the handle)-2.644 F(of a \214le once it has been gi)72 426 Q -.15 +(ve)-.25 G 2.5(nt).15 G 2.5(ot)-2.5 G(he k)-2.5 E(ernel.)-.1 E F1 2.5 +(4.4 Random)72 444 R(oper)2.5 E(ation speci\214c advice and blurb)-.15 E +F0 .563(This may e)72 462 R -.15(ve)-.25 G .563 +(ntually accurately describe the whole protocol, b).15 F .563(ut for no) +-.2 F 3.063(wi)-.25 G .563(ts a list of interesting points and)-3.063 F +(things that ha)72 474 Q .3 -.15(ve b)-.2 H(itten me.).15 E .441 +(Normally when writing a \214lesystem you should use the library)72 492 +R F1(lib)2.941 E(userfs)-.2 E F0 .441(\(see belo)2.941 F .442 +(w\), and use the advice in)-.25 F .644(this section as a guide on what\ + kind of things should be put in your userfs operation functions, or fo\ +r idle)72 504 R(curiosity)72 516 Q(.)-.65 E F1 2.5(4.4.1 Mounting)72 534 +R F0 .138(The mount is initiated by a user process calling the mount sy\ +stem call, with the "userfs" \214lesystem type.)72 552 R(In)5.138 E .494 +(the \214lesystem speci\214c data, the process passes tw)72 564 R 2.994 +<6f8c>-.1 G .493(le descriptor numbers for the k)-2.994 F .493 +(ernel to read and write)-.1 F 3.55(to. These)72 576 R 1.05(can by an) +3.55 F 3.55(yk)-.15 G 1.05(ind of \214le descriptor at all.)-3.55 F +1.051(Most commonly the)6.051 F 3.551(yw)-.15 G 1.051 +(ould be pipes or sock)-3.651 F 1.051(ets, b)-.1 F(ut)-.2 E .761 +(there is no restriction.)72 588 R .761(All the k)5.761 F .76(ernel req\ +uires that the one it talks to the process with is writable, and the)-.1 +F(one it gets replies from is readable.)72 600 Q 1.236 +(The most important request is mounting.)72 618 R 1.236 +(Most important, because it is one of the tw)6.236 F 3.736(or)-.1 G +1.236(equests that the)-3.736 F .938 +(process has to implement \(of course, not implementing an)72 630 R .938 +(ything else w)-.15 F .938(ould be completely useless\).)-.1 F(The)5.937 +E .792(request itself is not that comple)72 642 R 3.292(x. All)-.15 F +.792(it does is return a handle of the inode at the root of the \214les\ +ystem.)3.292 F(Most commonly)72 654 Q 2.5(,t)-.65 G +(his will be a directory)-2.5 E 5(.U)-.65 G +(serfs does not enforce this, b)-5 E(ut the k)-.2 E(ernel itself may)-.1 +E(.)-.65 E 1.495(After the process returns the root handle, the k)72 672 +R 1.494(ernel will probe the process to see what operations it is)-.1 F +.458(willing to support.)72 684 R .459 +(This is done by sending a series of enquire pack)5.459 F .459 +(ets to the process.)-.1 F .459(The process should)5.459 F .362 +(reply with normal reply pack)72 696 R .361(ets, with the errno \214eld\ + either set to 0 if it is supported or ENOSYS if it isn')-.1 F(t.)-.18 E +.351(No real operation should be done, and no additional information sh\ +ould be sent in the reply)72 708 R 5.351(.I)-.65 G 2.852(ft)-5.351 G +.352(he process)-2.852 F .209 +(replies ENOSYS to an operation, it will ne)72 720 R -.15(ve)-.25 G +2.709(rr).15 G(ecie)-2.709 E .508 -.15(ve i)-.25 H 2.708(ta).15 G -.05 +(ga)-2.708 G .208(in, and the k).05 F .208 +(ernel will use a sensible def)-.1 F .208(ault for)-.1 F 2.483 +(it \(typically what the k)72 732 R 2.484(ernel w)-.1 F 2.484 +(ould normally do for an in-k)-.1 F 2.484 +(ernel \214lesystem if it doesn')-.1 F 4.984(ts)-.18 G 2.484(upport the) +-4.984 F EP +%%Page: 6 6 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF 2.5(-6-)279.67 48 S 3.323(operation\). Con)72 96 +R -.15(ve)-.4 G(rsely).15 E 3.323(,i)-.65 G 3.322(ft)-3.323 G .822 +(he \214lesystem process doesn')-3.322 F 3.322(tg)-.18 G .822 +(et an enquiry about a particular operation from)-3.322 F .966(the k)72 +108 R .966(ernel, it will ne)-.1 F -.15(ve)-.25 G 3.466(rs).15 G .966 +(ee that operation from the k)-3.466 F 3.466(ernel. The)-.1 F .966 +(\214lesystem process should send 0 for the)3.466 F .239 +(operations it e)72 120 R .239(xplicitly supports, and ENOSYS for e)-.15 +F -.15(ve)-.25 G .238(rything else, so the protocol can be e).15 F .238 +(xtended without)-.15 F(ha)72 132 Q(ving to modify e)-.2 E +(xisting clients.)-.15 E/F1 10/Times-Italic@0 SF 2.5(4.4.2 Reading)72 +162 R(Inodes)2.5 E F0 .415 +(The most common thing for a \214lesystem to be ask)72 180 R .415 +(ed to do is to read inodes.)-.1 F -.15(Fo)5.415 G 2.915(rt).15 G .415 +(he process, this in)-2.915 F -.2(vo)-.4 G(lv).2 E(es)-.15 E .254 +(\214lling out a structure much lik)72 192 R 2.754(et)-.1 G .253(he k) +-2.754 F(ernel')-.1 E 2.753(si)-.55 G .253 +(node structure and the stat structure.)-2.753 F(It')5.253 E 2.753(si) +-.55 G .253(mportant is to mak)-2.753 F(e)-.1 E .963 +(sure the nlinks \214eld is non-zero.)72 204 R .963(This \214eld is the\ + number of names the inode has, that is, the number of)5.963 F .492 +(directory entries in the \214lesystem which refer to this inode.)72 216 +R .492(In theory)5.492 F 2.991(,t)-.65 G .491(his can ne)-2.991 F -.15 +(ve)-.25 G 2.991(rb).15 G 2.991(e0w)-2.991 G .491(hen the k)-2.991 F +(ernel)-.1 E 1.615(asks for the inode, because that means that the k)72 +228 R 1.616(ernel ask)-.1 F 1.616(ed for the inode without e)-.1 F -.15 +(ve)-.25 G 4.116(rs).15 G 1.616(eeing a name)-4.116 F .205 +(referring to it, implying that the \214lesystem ne)72 240 R -.15(ve) +-.25 G 2.705(rt).15 G .205(old the k)-2.705 F .205 +(ernel about the \214le.)-.1 F .204(If it is 0 then the k)5.205 F .204 +(ernel will)-.1 F(ne)72 252 Q -.15(ve)-.25 G 2.5(r").15 G +(put" the inode, and it will mak)-2.5 E 2.5(et)-.1 G +(he \214lesystem un-umountable.)-2.5 E 1.302(When the k)72 270 R 1.302 +(ernel w)-.1 F 1.302(ants an inode from the \214lesystem, it uses the) +-.1 F/F2 10/Times-Bold@0 SF(upp_ir)3.803 E(ead)-.18 E F0 1.303 +(protocol request to fetch it.)3.803 F 1.118 +(This happens if something in the k)72 282 R 1.118 +(ernel asks for the inode, b)-.1 F 1.118(ut it isn')-.2 F 3.618(ta)-.18 +G 1.118(lready in the k)-3.618 F 1.117(ernel inode table.)-.1 F .466 +(Therefore, once the k)72 294 R .466(ernel has ask)-.1 F .466 +(ed the \214lesystem for an inode, it will not ask for it ag)-.1 F .467 +(ain while an)-.05 F(ything)-.15 E(in the k)72 306 Q(ernel is using it.) +-.1 E .71(Once nothing in the k)72 324 R .71 +(ernel is using the inode, the k)-.1 F .71(ernel will issue an)-.1 F F2 +(upp_iput)3.21 E F0 .71(operation, which may be)3.21 F 1.835 +(preceded by an)72 336 R F2(upp_iwrite)4.335 E F0 1.835(if the inode w) +4.335 F 1.835(as modi\214ed in use.)-.1 F 4.335<418c>6.835 G 1.835 +(lesystem need not implement these)-4.335 F +(operations if there is no need to do so.)72 348 Q F1 2.5(4.4.3 Open)72 +366 R(and Close)2.5 E F0 .192 +(Reading and putting inodes are the basic operations: re)72 384 R -.05 +(ga)-.15 G .192(rdless of what an inode is being used for it will be).05 +F .185(read and put.)72 396 R(The)5.185 E F2(upp_open)2.685 E F0(and) +2.686 E F2(upp_close)2.686 E F0 .186 +(operations speci\214cally correspond to the)2.686 F F2(open)2.686 E F0 +.186(\(2\) and)B F2(close)2.686 E F0(\(2\))A .271(system calls.)72 408 R +.271(Normally a \214lesystem doesn')5.271 F 2.771(tn)-.18 G .271 +(eed to perform an)-2.771 F 2.771(ys)-.15 G .27 +(pecial handling for these operations, and)-2.771 F -.1(wo)72 420 S +1.853(uld not normally implement them, e).1 F 1.853(xcept if it w)-.15 F +1.854(ants to kno)-.1 F 4.354(wt)-.25 G 1.854 +(he identity of the process doing the)-4.354 F 3.593(operations. When)72 +432 R 3.593(ap)3.593 G 1.092(rogram issues an open system call for a \ +\214le on the user \214lesystem, the k)-3.593 F 1.092(ernel will)-.1 F +.471(send a)72 444 R F1(upp_open)2.971 E F0 .471(operation for the \214\ +le, which includes complete identifcation for the process which issued) +2.971 F .155(the open.)72 456 R .154 +(When the \214lesystem replies it returns a)5.155 F F1(cr)2.654 E .154 +(edentials tok)-.37 F(en.)-.1 E F0 .154 +(From then on, that credentials tok)5.154 F .154(en is)-.1 F .274(sent \ +to the \214lesystem in all operations which correspond to a system call\ + which tak)72 468 R .275(es a \214le descriptor as an)-.1 F(ar)72 480 Q +(gument, such as)-.18 E F2 -.18(re)2.5 G(ad).18 E F0(,)A F2(write)A F0 +(,)A F2 -.18(re)C(addir).18 E F0(,)A F2(lseek)A F0(and so on.)2.5 E +1.403(This may seem a bit comple)72 498 R 1.403(x: wh)-.15 F 3.903(yn) +-.05 G 1.403(ot just send the uid of the process with the operations?) +-3.903 F -.8(We)6.402 G 1.402(ll, the).8 F .436 +(credentials of a process are quite comple)72 510 R .436(x, since the) +-.15 F 2.936(yi)-.15 G .436(nclude the real, sa)-2.936 F -.15(ve)-.2 G +2.936(da).15 G .436(nd ef)-2.936 F(fecti)-.25 E .736 -.15(ve u)-.25 H +.437(ids and gids of).15 F .44 +(the process, and all the auxillary groups.)72 522 R .439 +(Sending this with each request w)5.44 F .439(ould be quite an o)-.1 F +-.15(ve)-.15 G 2.939(rhead. The).15 F .305(idea is that all the info is\ + sent on a open, and the \214lesystem process can associate it with a t\ +ok)72 534 R .306(en internally)-.1 F(,)-.65 E(and only use the tok)72 +546 Q(en in correspondance with the k)-.1 E(ernel.)-.1 E 1.145(Also not\ +e that the credentials are associated with an open \214le descriptor)72 +564 R 3.644(,n)-.4 G 1.144(ot the process performing the)-3.644 F 3.009 +(operation. Mostly)72 576 R 3.009(ap)3.009 G .509 +(rocess will deal with \214le descriptors it has created itself, b) +-3.009 F .51(ut its quite possible that it)-.2 F 2.473 +(can inherit \214le descriptors from another process with a dif)72 588 R +2.472(ferent set of credentials.)-.25 F 2.472(In this case the)7.472 F +2.658(\214lesystem kno)72 600 R 2.658(ws the original process')-.25 F +5.158(sc)-.55 G 2.658(redentials, b)-5.158 F 2.659 +(ut not for the process which is performing the)-.2 F(operation.)72 612 +Q F1 2.5(4.4.4 Handle)72 630 R(Mana)2.5 E -.1(ge)-.1 G(ment).1 E F0 .403 +(The handle of an inode is only w)72 648 R .403(ay the k)-.1 F .402 +(ernel and the \214lesystem can talk about a \214le.)-.1 F .402 +(An inode may ha)5.402 F -.15(ve)-.2 G .667(more than one name, or no n\ +ames at all, so \214le names are not a good w)72 660 R .667(ay of k)-.1 +F .667(eeping track of a \214le.)-.1 F(Use)5.667 E +(inodes in your \214lesystem code to k)72 672 Q(eep track of \214les, e) +-.1 E -.15(ve)-.25 G 2.5(ni).15 G 2.5(fy)-2.5 G(ou ha)-2.5 E .3 -.15 +(ve a s)-.2 H(imple 1:1 name to \214le mapping.).15 E 1.43 +(Handles must also be consistent.)72 690 R 1.43(Of course you must al) +6.43 F -.1(wa)-.1 G 1.429(ys k).1 F 1.429 +(eep the handles of \214les currently in use)-.1 F .778(consistent, b)72 +702 R .779(ut you must also k)-.2 F .779 +(eep them consistent between uses.)-.1 F .779 +(If a process opens a \214le once, closes it)5.779 F .159 +(and then reopens it, then it will e)72 714 R .159(xpect it to ha)-.15 F +.459 -.15(ve t)-.2 H .158 +(he same inode number if it is supposed to be the same \214le).15 F +(\(which is ho)72 726 Q 2.5(wp)-.25 G +(rocesses using a user \214lesystem will see the \214le handles\).)-2.5 +E EP +%%Page: 7 7 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF 2.5(-7-)279.67 48 S .106(Also, if you e)72 96 R +-.15(ve)-.25 G 2.606(rr).15 G .106 +(efer to a handle in communication with the k)-2.606 F .107 +(ernel, you must be prepared for the k)-.1 F .107(ernel to)-.1 F 1.668 +(ask about it.)72 108 R -.15(Fo)6.668 G 4.168(re).15 G 1.667 +(xample, if the k)-4.318 F 1.667(ernel reads a directory with the)-.1 F +/F1 10/Times-Bold@0 SF(upp_r)4.167 E(eaddir)-.18 E F0(or)4.167 E F1 +(upp_multir)4.167 E(eaddir)-.18 E F0 1.531 +(operations, each entry in the reply will ha)72 120 R 1.831 -.15(ve a n) +-.2 H 1.532(ame and a handle.).15 F 1.532 +(Each of those handles must be the)6.532 F .609 +(handle of the \214le if the k)72 132 R .609 +(ernel looks at the \214le more closely)-.1 F 5.609(.I)-.65 G 3.109(fy) +-5.609 G .609(ou mak)-3.109 F 3.109(et)-.1 G .609 +(hem all the same, for e)-3.109 F(xample,)-.15 E(then a program w)72 144 +Q(ould be entitled to belie)-.1 E .3 -.15(ve t)-.25 H +(hat all the names in the directory refer to one actual \214le.).15 E/F2 +10/Times-Italic@0 SF 2.5(4.4.5 Dealing)72 162 R(with muserfs)2.5 E F0 +.107(Writing a client which can be handled by muserfs is v)72 180 R .107 +(ery easy)-.15 F 5.107(.T)-.65 G .107 +(he important thing to remember is that the)-5.107 F(\214lesystem proce\ +ss can basically ignore muserfs, and ignore issues lik)72 192 Q 2.5(eh) +-.1 G .5 -.25(ow t)-2.5 H 2.5(oq).25 G(uit and so on.)-2.5 E 3.201(Au)72 +210 S .701(serfs \214lesystem process should only terminate under one c\ +ondition: it gets an EOF \(a read of 0 bytes\))-3.201 F .912(from the k) +72 222 R .913 +(ernel on the \214le descriptor its reading operation requests from.)-.1 +F .913(Muserfs will e)5.913 F -.15(xe)-.15 G .913(cute it so that).15 F +1.581(most signals are ignored, so it can handle them itself.)72 234 R +1.58(When the muserfs process is sent a SIGINT or)6.581 F .188 +(SIGTERM it unmounts the \214lesystem mount point with the)72 246 R F1 +(umount)2.688 E F0 .188(\(8\) command \(used so that /etc/mtab is)B +1.106(updated properly\).)72 258 R 1.106(This causes the k)6.106 F 1.106 +(ernel to send the \214lesystem process a)-.1 F F1(upp_umount)3.605 E F0 +3.605(operation. The)3.605 F -.1(ke)72 270 S .513(rnel will close its e\ +nd of the \214le descriptors, and the process is e).1 F .513 +(xpected to do the same, e)-.15 F -.15(ve)-.25 G 3.013(ni).15 G 3.013 +(fo)-3.013 G .513(nly by)-3.013 F -.15(ex)72 282 S 3.06 +(iting. Therefore,).15 F .559(when trying to unmount a userfs \214lesys\ +tem, do not kill the \214lesystem process directly)3.06 F(,)-.65 E +(and do not kill muserfs with SIGKILL.)72 294 Q(Either w)5 E +(ay you should be able to unmount with)-.1 E F1(umount)2.5 E F0 +(as root.)2.5 E F2 2.5(5. Using)72 318 R(lib)2.5 E(userfs)-.2 E(lib)72 +336 Q(userfs)-.2 E F0 .495(is a C++ library designed to mak)2.995 F +2.995(ew)-.1 G .496(riting \214lesystem clients easier)-2.995 F 5.496 +(.I)-.55 G 2.996(ti)-5.496 G 2.996(sd)-2.996 G .496 +(esigned so all the w)-2.996 F(ork)-.1 E 1.215 +(common to almost all \214lesystems is encapsulated into a fe)72 348 R +3.715(wg)-.25 G 1.214(eneric classes, which can be used as base)-3.715 F +(classes for speci\214c \214lesystem functions.)72 360 Q F2 2.5 +(5.1 Basic)72 378 R(Classes)2.5 E F0 .232(The most basic classes,)72 396 +R F1(Comm)2.733 E F0(,)A F1(Filesystem)2.733 E F0(and)2.733 E F1(Inode) +2.733 E F0 .233(implement the basic communication with the k)2.733 F +(ernel)-.1 E(and stub methods for each operation.)72 408 Q 1.018 +(The Comm class reads from the k)72 426 R 1.018 +(ernel and decodes the headers of the operation pack)-.1 F 1.017 +(ets, and passes the)-.1 F .346(remainder to the Filesystem class.)72 +438 R .347 +(The Filesystem performs the operation and returns an unencoded return) +5.346 F(header and the encoded body of the reply)72 450 Q 2.5(,i)-.65 G +2.5(fa)-2.5 G -.15(ny)-2.5 G 5(.A)-.5 G(ll this is not e)-5 E +(xposed to the code using the library)-.15 E(.)-.65 E 1.068 +(Filesystem tak)72 468 R 1.067 +(es each operation and dispatches it to the appropriate place.)-.1 F +1.067(The Filesystem class directly)6.067 F 1.367(handles the operation\ +s which are global to the whole \214lesystem, such as mounting or unmou\ +nting.)72 480 R -.15(Fo)6.368 G(r).15 E 2.035(operation which pertain t\ +o a particular Inode \(such as reading, or looking up a name in a direc\ +tory\),)72 492 R(Filesystem looks up the Inode in its table and dispatc\ +hes the operation to it.)72 504 Q .136 +(The Inode class has all its methods implemented as stubs which f)72 522 +R .137(ail with the "not implemented" error code.)-.1 F .196(It also ha\ +s members for the standard inode properties of mode, type, size, o)72 +534 R .196(wnership, links, timestamps and)-.25 F(so on.)72 546 Q .863 +(These classes are completely useless on their o)72 564 R .863 +(wn, so the)-.25 F 3.363(ym)-.15 G .864 +(ust be used as base classes for other classes)-3.363 F +(with actually do something.)72 576 Q F2(lib)5 E(userfs)-.2 E F0 +(has more speci\214c, b)2.5 E(ut still generally useful classes.)-.2 E +F1(SimpleInode)72 594 Q F0 1.7 +(implements a simple inode with some normally e)4.2 F 1.7(xpected beha) +-.15 F(viour)-.2 E 6.7(.I)-.55 G 4.2(th)-6.7 G 1.7(as a constructor)-4.2 +F .428(which initializes the inode properties to sensible v)72 606 R +.429(alues, and methods which implement simple def)-.25 F .429 +(aults for)-.1 F(the open, close and permissions check operations.)72 +618 Q F1(DirInode,)72 636 Q F0(deri)4.773 E -.15(ve)-.25 G 4.773(df).15 +G 2.272 +(rom SimpleInode, implements all the operations needed for a directory) +-4.773 F 4.772(,i)-.65 G(ncluding)-4.772 E .097(linking and unlinking i\ +nodes to/from names, rename, and directory scanning and lookup.)72 648 R +.098(It tak)5.098 F .098(es v)-.1 F .098(ery little)-.15 F -.15(ex)72 +660 S(tra code to implemement simple directory beha).15 E(viour)-.2 E(.) +-.55 E F2 2.5(5.2 Writing)72 678 R(your own \214lesystem classes)2.5 E +F0 3.199(Ac)72 696 S .699(omplete \214lesystem has tw)-3.199 F 3.199(op) +-.1 G .699(arts: a collection of inodes, one for each \214le, and the \ +\214lesystem structure)-3.199 F .23 +(itself, which holds all the inodes together)72 708 R 5.23(.E)-.55 G +.231(ach inode represents a \214le in the \214lesystem, re)-5.23 F -.05 +(ga)-.15 G .231(rdless of type.).05 F 1.215 +(There is only one inode per \214le in the \214lesystem, e)72 720 R -.15 +(ve)-.25 G 3.715(ni).15 G 3.715(ft)-3.715 G 1.215 +(he \214le appears multiple times under dif)-3.715 F(ferent)-.25 E +(names.)72 732 Q EP +%%Page: 8 8 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF 2.5(-8-)279.67 48 S/F1 10/Times-Italic@0 SF 2.5 +(5.2.1 Ar)72 96 R(guments and r)-.37 E(eturn values of oper)-.37 E +(ation methods)-.15 E F0 .118(Each method with the name)72 114 R/F2 10 +/Times-Bold@0 SF(do_something)2.618 E F0 .118 +(in the Filesystem and Inode classes corresponds to an operation)2.618 F +.378(in the userfs protocol.)72 126 R .378(As a result, the)5.378 F +2.878(ya)-.15 G .378(ll ha)-2.878 F .678 -.15(ve s)-.2 H .378(imilar ar) +.15 F .377(gument structures.)-.18 F .377(All such methods ha)5.377 F +-.15(ve)-.2 G F2(const)3.027 E(up_pr)72 138 Q 1.358(eamble &pr)-.18 F(e) +-.18 E F0(and)3.858 E F2(upp_r)3.858 E 1.358(epl &r)-.18 F(epl)-.18 E F0 +1.359(which are references to the operation reqest and reply pack)3.858 +F(et)-.1 E 2.688(headers. Mostly)72 150 R .188(there is no reason for o\ +peration methods to use them, because their contents are dealt with) +2.688 F(in lo)72 162 Q(wer le)-.25 E -.15(ve)-.25 G(ls of the library) +.15 E 2.5(,b)-.65 G(ut the)-2.7 E 2.5(ya)-.15 G(re there if you w)-2.5 E +(ant them.)-.1 E .395(Each userfs protocol operation may ha)72 180 R +.695 -.15(ve a)-.2 H -.18(rg).15 G .395(uments, return v).18 F .395 +(alues, both or neither)-.25 F 2.895(,a)-.4 G .395 +(nd the method for that)-2.895 F 1.4(operation will ha)72 192 R 1.7 -.15 +(ve c)-.2 H 1.4(orresponding ar).15 F 3.899(guments. F)-.18 F 1.399 +(or an operation named)-.15 F F1(x)3.899 E F0 1.399(the method ar)3.899 +F 1.399(gument with the)-.18 F .783(operation ar)72 204 R .783 +(guments will ha)-.18 F 1.083 -.15(ve t)-.2 H .783(he type).15 F F2 .783 +(const upp_)3.283 F F1(x)A F2(_s)A F0 3.283(,a)C .783(nd the return v) +-3.283 F .783(alues ar)-.25 F .783(gument will ha)-.18 F 1.084 -.15 +(ve t)-.2 H .784(he type).15 F F2(upp_)72 216 Q F1(x)A F2(_r)A F0 2.5 +(,F)C(or e)-2.65 E +(xample, the up_read operation will correspond to the Inode method)-.15 +E/F3 9/Courier@0 SF +(int Inode::do_read\(const up_preamble &pre, upp_repl &repl,)97 233 Q +(const upp_read_s &args, upp_read_r &ret\);)199.6 244 Q F0 1.201(The co\ +ntents of the structures, along with encoding and decoding functions, a\ +re machine generated, and)72 262 R 3.27(therefore ha)72 274 R 3.57 -.15 +(ve a c)-.2 H 3.27(onsistent set of rules.).15 F 3.271 +(Mostly its quite simple, with normal base types directly)8.271 F .707 +(corresponding to C and C++ types.)72 286 R(Ho)5.707 E(we)-.25 E -.15 +(ve)-.25 G 1.507 -.4(r, v).15 H .707(ariable sized types need to ha).15 +F 1.006 -.15(ve b)-.2 H .706(oth a pointer to the data).15 F .413 +(and the size of the data encoded into them.)72 298 R .414 +(Memory for the data is allocated with the C++ ne)5.413 F 2.914(wa)-.25 +G .414(nd delete)-2.914 F 1.552(operators, with the)72 310 R F2(alloc) +4.052 E F0 1.551(method of a v)4.052 F 1.551(ariable sized object.)-.25 +F 1.551(The memory is automatically freed by the)6.551 F(method')72 322 +Q 2.557(sc)-.55 G(aller)-2.557 E 5.057(.F)-.55 G .057(or e)-5.207 F .057 +(xample, if a return v)-.15 F .057 +(alue of a method contains an member called)-.25 F F2(name)2.557 E F0 +.058(representing a)2.557 F(\214lename, it w)72 334 Q +(ould be set with the follo)-.1 E(wing sequence \(assuming)-.25 E F2 +(our)2.5 E(name)-.15 E F0(is a normal 0 terminated string\):)2.5 E F3 +(int namelen = strlen\(ourname\);)97 351 Q 97.2 +(ret.name.alloc\(namelen\); //)97 362 R(Allocate memory)5.4 E +(ret.name.nelem = namelen;)97 373 Q(// Set name length)97.2 E +(memcpy\(&ret.name.elems, ourname, namelen\); // Set name contents)97 +384 Q(// ...)97 395 Q F0(\(alternati)72 413 Q -.15(ve)-.25 G(ly).15 E +3.694(,y)-.65 G 1.194(ou could just point)-3.694 F F1 -.37(re)3.694 G +(t.name).37 E(.elems)-.15 E F0 1.194(directly at)3.694 F F1(ourname) +3.694 E F0 3.694(,b).18 G 1.194(ecause it w)-3.694 F(on')-.1 E 3.694(tt) +-.18 G 1.194(ry and free the)-3.694 F(string if it w)72 425 Q(as ne)-.1 +E -.15(ve)-.25 G 2.5(ra).15 G(llocated\).)-2.5 E 1.837 +(Note that strings are ne)72 443 R -.15(ve)-.25 G 4.337(rz).15 G 1.838 +(ero terminated; the length of the returned string is e)-4.337 F 1.838 +(xactly the number of)-.15 F(characters in the string.)72 455 Q 2.065 +(If the operation the method is performing f)72 473 R 2.065 +(ails, it should return the appropriate error code, or 0 if it)-.1 F +2.772(succeeds. Don')72 485 R 2.773(tr)-.18 G .273 +(eturn -1 unless you mean to \255 it has special meaning \(see belo) +-2.773 F 1.573 -.65(w, i)-.25 H 2.773(n").65 G .273 +(Deferring Replies"\).)-2.773 F F1 2.5(5.2.2 Deriving)72 503 R(fr)2.5 E +(om F)-.45 E(ilesystem)-.45 E F0 +(Filesystem class must implement a number of methods to mak)72 521 Q 2.5 +(et)-.1 G(he \214lesystem viable:)-2.5 E F1(Enquir)72 539 Q(e)-.37 E F0 +1.962(is called when the k)2.5 F 1.962(ernel w)-.1 F 1.961 +(ants to \214nd what operations your \214lesystem supports.)-.1 F -.15 +(Fo)6.961 G 4.461(ra).15 G 1.961(ll the)-4.461 F(operations that an)97 +551 Q 2.5(yi)-.15 G +(node will implement, return 0 and return ENOSYS for the rest.)-2.5 E F1 +(do_mount)72 569 Q F0(tak)2.5 E 1.134(es no ar)-.1 F 1.135(guments and \ +returns the handle for the inode for the root directory \(that is, the \ +top)-.18 F(directory of your \214lesystem\).)97 581 Q(The k)5 E +(ernel immediately does a)-.1 E F2(do_ir)2.5 E(ead)-.18 E F0 +(operation using this handle.)2.5 E -1.1(Yo)72 593 S 3.196(uc)1.1 G .696 +(an also implement)-3.196 F F1(do_statfs)3.196 E F0 .696(which allo) +3.196 F .696(ws the k)-.25 F .696 +(ernel to get space and inode usage statistics, such as)-.1 F 2.278 +(when "df" is e)72 605 R -.15(xe)-.15 G 2.278(cuted, and).15 F F1 +(do_umount)4.778 E F0 2.278 +(so the \214lesystem is formally informed when it is unmounted)4.778 F +(\(normally it just gets an EOF from the k)72 617 Q +(ernel, and Comm::Run returns\).)-.1 E F1 2.5(5.2.3 Deriving)72 635 R +(fr)2.5 E(om Inode)-.45 E F0 .086(Most of the w)72 653 R .086 +(ork of the \214lesystem is done in the inodes.)-.1 F .085 +(All inode classes must be deri)5.085 F -.15(ve)-.25 G 2.585(df).15 G +.085(rom Inode, and)-2.585 F(generally there will be a number of dif)72 +665 Q(ferent Inode based classes.)-.25 E 1.134(It is probably better to\ + use SimpleInode as a base rather than plain Inode, because it implemen\ +ts simple)72 683 R(def)72 695 Q 1.547(aults for some methods, which w) +-.1 F 1.547(ould otherwise f)-.1 F 4.047(ail. If)-.1 F 1.547 +(Filesystem::Enquire says that the \214lesystem)4.047 F +(supports a particular operation, then an)72 707 Q 2.5(yi)-.15 G +(node should be prepared to get that operation from the k)-2.5 E(ernel.) +-.1 E(Similarly)72 725 Q 2.5(,u)-.65 G +(nless you are doing something special, deri)-2.5 E +(ving directories from DirInode sa)-.25 E -.15(ve)-.2 G 2.5(sal).15 G +(ot of w)-2.5 E(ork.)-.1 E(Only)72 743 Q F1(do_ir)3.19 E(ead)-.37 E F0 +.69(need be implemented, b)3.19 F .691(ut ob)-.2 F .691 +(viously the \214lesystem will do nothing interesting unless other)-.15 +F EP +%%Page: 9 9 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF 2.5(-9-)279.67 48 S .452 +(operations are implemented.)72 96 R .452 +(do_iread returns the details of the inode.)5.452 F .452 +(Note that the Filesystem class calls)5.452 F .074 +(the do_iread of the Inode when the operation comes from the k)72 108 R +.074(ernel, so the inode must e)-.1 F .074(xist by the time the)-.15 F +-.1(ke)72 120 S 1.358(rnel asks for it.).1 F 1.357 +(The constructor for Inode automatically re)6.358 F 1.357 +(gisters the inode in the Filesystem')-.15 F 3.857(si)-.55 G(node)-3.857 +E(table; con)72 132 Q -.15(ve)-.4 G(rsely).15 E 2.5(,t)-.65 G +(he destructor remo)-2.5 E -.15(ve)-.15 G 2.5(si).15 G(t.)-2.5 E 2.521(\ +Here are some other useful methods for an Inode; the descriptions are b\ +rief and general, and don')72 150 R(t)-.18 E +(necessarily refer to all the ar)72 162 Q(guments and return v)-.18 E +(alues, which means the)-.25 E 2.5(yc)-.15 G(an be ignored.)-2.5 E/F1 10 +/Times-Italic@0 SF(do_iwrite)72 180 Q F0(is, ob)2.5 E(viously)-.15 E 2.5 +(,t)-.65 G(he opposite of do_iread.)-2.5 E(It simply sets the v)5 E +(arious Inode v)-.25 E(alues.)-.25 E F1(do_iput)72 198 Q F0 1.078 +(is called when the k)2.5 F 1.078(ernel is no longer using the inode.) +-.1 F 1.077(That is, the inode is no longer open, the)6.077 F .21 +(current or root directory of a process, being e)97 210 R -.15(xe)-.15 G +.21(cuted from or being mapped from.).15 F .21(If an inode is iput)5.21 +F(and has no names \(has no name to inode mapping in an)97 222 Q 2.5(yd) +-.15 G(irectory\) it can be destro)-2.5 E(yed.)-.1 E F1(do_r)72 240 Q +(ead)-.37 E F0(allo)2.5 E .472(ws data to be read from the \214le.)-.25 +F .472(The ar)5.472 F .472(guments are the of)-.18 F .471 +(fset in the \214le to start reading from,)-.25 F 1.295 +(and the number of bytes desiried.)97 252 R 1.295 +(The method may return as man)6.295 F 3.795(yb)-.15 G 1.295 +(ytes up to that number as it)-3.795 F(lik)97 264 Q +(es, including 0, which means EOF)-.1 E(.)-.8 E F1(do_write)72 282 Q F0 +.049(does the con)2.5 F -.15(ve)-.4 G .049 +(rse; a block of data and an of).15 F .049 +(fset is passed in, and the method returns the number of)-.25 F +(bytes actually written.)97 294 Q F1(do_lookup)72 312 Q F0 .882 +(translates a name into an inode reference.)2.5 F .882 +(This is typically implemented for directories; if the)5.882 F(name e)97 +324 Q(xists in the directory the method should return the handle of the\ + inode, or f)-.15 E(ail with ENOENT)-.1 E(.)-.74 E F1(do_dirr)72 342 Q +(ead)-.37 E F0 .765(returns the ne)2.5 F .765 +(xt directory entry at the passed of)-.15 F 3.265(fset. It)-.25 F .764 +(returns the name and inode of the ne)3.265 F(xt)-.15 E .043 +(\214le in the directory)97 354 R 2.543(,a)-.65 G .043 +(nd the size of the entry returned. This is added by the k)-2.543 F .043 +(ernel to the current of)-.1 F(fset)-.25 E 1.041 +(in the directory to form the of)97 366 R 1.041(fset of the ne)-.25 F +1.041(xt directory entry for the ne)-.15 F 1.041(xt call.)-.15 F 1.041 +(Since the directory)6.041 F 1.26(entries don')97 378 R 3.76(tc)-.18 G +1.26(orrespond to real \214le storage as in other)-3.76 F 3.76(,m)-.4 G +1.26(ore con)-3.76 F -.15(ve)-.4 G 1.26 +(ntional \214lesystems, a directory).15 F(entry can be re)97 390 Q -.05 +(ga)-.15 G(rded as ha).05 E(ving an of)-.2 E(fset of 1.)-.25 E +(If the end of the directory has been reached, it should return a ne)97 +408 Q 2.5(wo)-.25 G -.25(ff)-2.5 G(set of 0.).25 E F1(do_multir)72 426 Q +(eaddir)-.37 E F0 .606(is similar to do_readdir)2.5 F 3.106(,b)-.4 G +.606(ut can return an)-3.306 F 3.106(yn)-.15 G .605 +(umber of directory entries, which are cached)-3.106 F .495 +(in a readahead b)97 438 R(uf)-.2 E .495(fer in the k)-.25 F 2.995 +(ernel. If)-.1 F 2.995(ap)2.995 G .495 +(rogram asks for a directory entry for an inode which has a)-2.995 F +2.46(cached directory entry then the entry will come from within the k) +97 450 R 2.46(ernel rather than asking the)-.1 F .578 +(\214lesystem process.)97 462 R .579 +(This operation can return only one entry \(and so is lik)5.578 F 3.079 +(ed)-.1 G .579(o_readdir\), or as man)-3.079 F(y)-.15 E .91 +(as will \214t in a return pack)97 474 R .91 +(et \(up to 4k or so of entries\).)-.1 F .909 +(Returning no entries means the end of the)5.909 F .361 +(directory has been reached.)97 486 R .362 +(Returning multiple entries impro)5.361 F -.15(ve)-.15 G 2.862(st).15 G +.362(he performance of directory scans,)-2.862 F +(most frequently done by ls, pwd and shell globbing.)97 498 Q .064(Look\ + at the implementation of DirInode::do_multireaddir for details of ho)97 +516 R 2.563(wt)-.25 G .063(his should be dealt with.)-2.563 F F1(do_cr) +72 534 Q(eate)-.37 E F0 1.01 +(does all \214le creation, whether it be a normal \214le, a directory) +2.5 F 3.51(,a\214)-.65 G 1.01(fo \214le or a de)-3.51 F 1.01(vice node.) +-.25 F(The)6.01 E(mode contains the type of the \214le in same w)97 546 +Q(ay as the stat structure member)-.1 E/F2 10/Times-Bold@0 SF(st_mode.) +2.5 E F1(do_unlink)72 564 Q F0 2.682 +(is the opposite, and is used for unlinking \(remo)2.5 F 2.682 +(ving a name to inode mapping\) \214les and)-.15 F 3.092 +(directories. If)97 576 R .592 +(an inode is not in use and has no links then it can be destro)3.092 F +.593(yed and its handle can be)-.1 F(reused.)97 588 Q F1(do_symlink)72 +606 Q F0(is used to create ne)2.5 E 2.5(ws)-.25 G(ymlink inodes.)-2.5 E +(It returns the handle of the ne)5 E 2.5(wi)-.25 G(node.)-2.5 E F1(do_r) +72 624 Q(eadlink)-.37 E F0 +(returns the pathname which a symbolic link is pointing to.)2.5 E F1 +(do_followlink)72 642 Q F0 .443(returns the pathname of the \214le a sy\ +mbolic link is really referring to.)2.5 F .442(If Filesystem::Enquire) +5.442 F(says the \214lesystem does not support this operation, the read\ +link operation is used instead.)97 654 Q F1(do_open)72 672 Q F0 .34 +(is called when a \214le is actually opened.)2.5 F .341 +(It is only necessary to implement this if it is important to)5.34 F +(kno)97 684 Q 4.045(ww)-.25 G 1.545 +(hether a \214le is being opened as opposed to being used in an)-4.045 F +4.044(yo)-.15 G 1.544(ther w)-4.044 F(ay)-.1 E 6.544(.T)-.65 G 1.544 +(his operation)-6.544 F .96(passes the \214lesystem the complete authen\ +tication credentials of the process doing the open, so that)97 696 R +.048(the \214lesystem can do e)97 708 R .048 +(xtended security checking or change the beha)-.15 F .047 +(viour of the \214le depending on the)-.2 F(user)97 720 Q(.)-.55 E .061 +(This method can return a credential tok)97 738 R .062 +(en, which is a magic number used by the \214lesystem process to)-.1 F +EP +%%Page: 10 10 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF 2.5(-1)277.17 48 S 2.5(0-)-2.5 G .321 +(refer to the set of credentials passed by the k)97 96 R 2.821 +(ernel. The)-.1 F -.1(ke)2.821 G .321 +(rnel attaches this credentials tok).1 F .321(en to each)-.1 F .233(eac\ +h operation generated by system calls on the \214le descriptor generate\ +d by the open \(read\(\), write\(\),)97 108 R .47 +(readdir\(\) and close\(\)\).)97 120 R .47(The credentials tok)5.47 F +.469(en is part of the \214le descriptor)-.1 F 2.969(,s)-.4 G 2.969(oi) +-2.969 G 2.969(si)-2.969 G .469(nhereited unchanged)-2.969 F +(if the descriptor is passed to another process, e)97 132 Q -.15(ve)-.25 +G 2.5(ni).15 G 2.5(fi)-2.5 G 2.5(th)-2.5 G(as dif)-2.5 E +(ferent credentials.)-.25 E .111(When a \214le is opened, a ne)97 150 R +2.611<778c>-.25 G .111(le table entry for the inode is created.)-2.611 F +.111(That \214le table entry has a single)5.111 F .037 +(\214le descriptor referring to it.)97 162 R .036(More \214le descripto\ +rs can be made to refer to the \214le table entry with the)5.037 F/F1 10 +/Times-Bold@0 SF(dup)97 174 Q F0(\(2\) system call, and can be remo)A +-.15(ve)-.15 G 2.5(dw).15 G(ith)-2.5 E F1(close)2.5 E F0(\(2\).)A/F2 10 +/Times-Italic@0 SF(do_close)72 192 Q F0 .293(is called when the last \ +\214le descriptor for a \214le table entry is closed.)2.5 F .293 +(The only ar)5.293 F .294(gument for this is)-.18 F(the credentials tok) +97 204 Q(en for that \214le table entry)-.1 E 2.5(,s)-.65 G 2.5(ot)-2.5 +G(hat the \214lesystem can free all references to it.)-2.5 E F2 +(do_permission)72 222 Q F0 .445 +(is called when the \214lesystem says it w)2.5 F .445 +(ants to do permissions checking.)-.1 F .445(This is called a lot,)5.445 +F 2.026(and can cause man)97 234 R 4.526(ym)-.15 G 2.026 +(ore operations to pass between the k)-4.526 F 2.026 +(ernel and \214lesystem process.)-.1 F 2.026(If the)7.026 F(\214lesyste\ +m does not implement it the normal unix user/group/others checking is p\ +erformed.)97 246 Q F2(do_r)72 264 Q(ename)-.37 E F0(mo)2.5 E -.15(ve) +-.15 G 2.5(sa\214).15 G(le from one directory to a ne)-2.5 E 2.5(wo)-.25 +G(ne \(though it may be the same\).)-2.5 E F2 2.5(5.2.4 Deriving)72 282 +R(fr)2.5 E(om DirInode)-.45 E F0 1.152(DirInode implements a number of \ +userfs operation methods for directories, such as readdir)72 300 R 3.652 +(,m)-.4 G(ultireaddir)-3.652 E .252(and lookup.)72 312 R .252 +(It also automatically constructs directories with "." and "..")5.252 F +.252(entries pointing to the appropriate)5.252 F(places.)72 324 Q .108 +(DirInode deals with strings a lot, and rather than using the normal)72 +342 R F1 .107(char *)2.607 F F0 .107(it uses the libg++)2.607 F F1 +(String)2.607 E F0 .107(class for)2.607 F(all string ar)72 354 Q +(guments to its o)-.18 E(wn methods \(b)-.25 E +(ut not, of course, for the userfs protocol operation methods\).)-.2 E +1.631(DirInode e)72 372 R 1.631 +(xpects a pointer to the parent directory)-.15 F 4.132(,w)-.65 G 1.632 +(hich is also a class deri)-4.132 F -.15(ve)-.25 G 4.132(df).15 G 1.632 +(rom DirInode.)-4.132 F 1.632(If the)6.632 F .418 +(directory is at the top of the \214lesystem')72 384 R 2.917(st)-.55 G +.417(ree, it should be a NULL pointer)-2.917 F 5.417(.T)-.55 G .417 +(he protected member)-5.417 F F1(par)2.917 E(ent)-.18 E F0 +(points the the parent inode, or)72 396 Q F1(this)2.5 E F0 +(for the top one.)2.5 E(It should ne)5 E -.15(ve)-.25 G 2.5(rb).15 G 2.5 +(eN)-2.5 G(ULL.)-2.5 E .897(DirInode k)72 414 R .897 +(eeps a list of \214les in the directory)-.1 F 3.397(,b)-.65 G .898 +(ut does not allo)-3.597 F 3.398(wt)-.25 G .898 +(hat list to be directly visible.)-3.398 F .898(The only)5.898 F +(operations for manipulating the directory contents for a deri)72 426 Q +-.15(ve)-.25 G 2.5(dc).15 G(lass are:)-2.5 E F1 +(int link\(const String name, Inode *\))72 444 Q F0 .344 +(which links a ne)2.5 F 2.844(wn)-.25 G .344(ame into the directory) +-2.844 F 2.843(,u)-.65 G .343(pdating all the reference)-2.843 F +(and link counts;)97 456 Q F1(int unlink\(const String name\))72 474 Q +F0(which does the opposite;)2.5 E F1 +(DirEntry *lookup\(const String name\))72 492 Q F0 3.165 +(which returns a directory entry if it \214nds the \214le, or NULL)2.5 F +(otherwise; and)97 504 Q F1(DirEntry *scan\(DirEntry * &pos\))72 522 Q +F0 .727(which returns the directory entry at)2.5 F F2(pos,)3.227 E F0 +.726(updating it in the process, or)3.227 F +(NULL if there are no more entries.)97 534 Q F1 +(DirEntry *scan\(int &pos\))72 552 Q F0(is the same, e)2.5 E +(xcept it uses an inte)-.15 E(ger of)-.15 E(fset, which is less ef)-.25 +E(\214cient.)-.25 E F2 2.5(5.3 Communications)72 570 R(classes)2.5 E F0 +.299(There are a number of communications classes in the library)72 588 +R 2.799(,w)-.65 G .3(hich pro)-2.799 F .3(vide dif)-.15 F .3(ferent w) +-.25 F .3(ays of multiple)-.1 F(xing)-.15 E(replies.)72 600 Q .396 +(The most simple is the Comm class, which simply tak)72 618 R .395 +(es each request, passes it to the \214lesystem and sends)-.1 F +(back the reply)72 630 Q 5(.T)-.65 G(here are more comple)-5 E 2.5(xc) +-.15 G(omms classes though.)-2.5 E F2 2.5(5.3.1 F)72 648 R +(ile Descriptor Dispatc)-.45 E(her)-.15 E F0(The)72 666 Q F1(CommBase) +3.546 E F0 1.046(class \(base of all comms classes\) pro)3.546 F 1.046 +(vides a dispatcher which allo)-.15 F 1.046(ws classes to re)-.25 F +(gister)-.15 E .575(interest in acti)72 678 R .575 +(vity on \214le descriptors.)-.25 F .575 +(This is used internally to get input from the k)5.575 F .574(ernel, b) +-.1 F .574(ut can be used)-.2 F .07(by a \214lesystem to monitor an)72 +690 R 2.57<798c>-.15 G .07(le descriptor for an)-2.57 F 2.57(yr)-.15 G +2.57(eason. T)-2.57 F 2.57(od)-.8 G 2.57(oi)-2.57 G .07(t, simply deri) +-2.57 F .37 -.15(ve a d)-.25 H .07(ispatcher class from).15 F F1 +(DispatchFD)72 702 Q F0 .942(and call)3.442 F F1 .942 +(struct disp_fd CommBase::addDispatch\(int fd, DispatchFD *, int what\)) +3.442 F F0 3.441(,w)C(here)-3.441 E 1.894(what can be one or more of)72 +714 R F2(DISP_R)4.394 E F0(,).27 E F2(DISP_W)4.974 E F0(or)5.624 E F2 +(DISP_E)4.974 E F0 4.395(,f).73 G 1.895(or interest in read ready)-4.395 +F 4.395(,w)-.65 G 1.895(rite ready or)-4.395 F -.15(ex)72 726 S 3.678 +(ceptions. When).15 F 1.178(an e)3.678 F -.15(ve)-.25 G 1.178 +(nt occurs, the).15 F F1 1.178(DispatchFD::dispatch\(int fd, int what\)) +3.678 F F0 1.178(method is called of the)3.678 F(re)72 738 Q .159 +(gistered class.)-.15 F .159(If it returns 0 then it is remo)5.159 F +-.15(ve)-.15 G 2.659(df).15 G .16(rom the dispatch list.)-2.659 F .16 +(If it returns -1 it indicates an error;)5.16 F EP +%%Page: 11 11 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF 2.5(-1)277.17 48 S 2.5(1-)-2.5 G(it is remo)72 +96 Q -.15(ve)-.15 G(d, and).15 E/F1 10/Times-Bold@0 SF +(CommBase::Run\(\))2.5 E F0 2.5(returns. Returning)2.5 F 2.5(1i)2.5 G +2.5(san)-2.5 G(ormal return.)-2.5 E F1(CommBase::Run\(\))72 114 Q F0 +(returns normally when there are no more entries on the dispatch list.) +2.5 E/F2 10/Times-Italic@0 SF 2.5(5.3.2 Deferring)72 132 R(Replies)2.5 E +F0 .792(In normal operation, the \214lesystem processes one request at \ +a time, so each operation is replied to before)72 150 R .81(the ne)72 +162 R .81(xt is look)-.15 F .81(ed at.)-.1 F .81(This is a con)5.81 F +-.15(ve)-.4 G .81(ntion of the w).15 F .811(ay the user code w)-.1 F +.811(orks, and not something the k)-.1 F(ernel)-.1 E 3.218(enforces. It) +72 174 R .718(just sends requsts as processes using the \214lesystem ne\ +ed them, and the)3.218 F 3.217(yb)-.15 G .717(lock until the reply) +-3.217 F .056(for their particular request is replied to.)72 186 R .056 +(Therefore, it is possible for multiple processes to use the \214lesyst\ +em)5.056 F(at once.)72 198 Q(The)72 216 Q F1(DeferComm)3.31 E F0(and) +3.31 E F1(DeferFilesys)3.31 E F0 .81(classes ha)3.31 F 1.11 -.15(ve a m) +-.2 H .81(ethod called).15 F F1(DeferReply)3.31 E F0 .81 +(\(the DeferFilesys once just)3.31 F 1.606 +(calls the DeferComm one to mak)72 228 R 4.107(ei)-.1 G 4.107(ta)-4.107 +G 1.607(ccessable to things within the \214lesystem\).)-4.107 F 1.607 +(DeferReply forks the)6.607 F .931(\214lesystem; on the child side it r\ +eturns 0 and in the parent it returns the pid of the child.)72 240 R .93 +(If the operation)5.93 F .805(method returns -1 then the Filesystem jus\ +t goes on to processing the ne)72 252 R .806(xt request from the k)-.15 +F 3.306(ernel. When)-.1 F 2.104(the child is ready to reply)72 264 R +4.604(,i)-.65 G 4.604(tc)-4.604 G 2.104(an just return in the normal w) +-4.604 F(ay)-.1 E 7.103(.T)-.65 G 2.103 +(he call to DeferReply sets up the)-7.103 F .321(DeferComm class in the\ + child process to reply though the parent rather than going straight to\ + the k)72 276 R .321(ernel, in)-.1 F .224(order to mak)72 288 R 2.724 +(es)-.1 G .224(ure the replies from multiple processes don')-2.724 F +2.723(tg)-.18 G .223(et jumbled up.)-2.723 F .223 +(When the reply has been sent)5.223 F(back, the child process just e)72 +300 Q(xits.)-.15 E .39 +(Because the child is really a child process, you ha)72 318 R .691 -.15 +(ve t)-.2 H 2.891(od).15 G 2.891(oa)-2.891 G .391 +(ll the changes in \214lesystem state before calling)-2.891 F +(DeferReply)72 330 Q 2.5(,o)-.65 G 2.5(ra)-2.5 G +(rrange for some other mechanism for the parent and children to talk.) +-2.5 E F2 2.5(5.3.3 Multi-thr)72 348 R(eaded \214lesystems)-.37 E F0 +(The)72 366 Q F1(Thr)3.35 E(eadComm)-.18 E F0 .85(class creates a ne) +3.35 F 3.35(wl)-.25 G .85 +(ightweight thread for each request, using the Re)-3.35 F 3.35(xl)-.15 G +.85(wp library \(in)-3.45 F 1.48(the l)72 378 R 1.48(wp directory\).)-.1 +F 1.48(This allo)6.48 F 1.481(ws multiple requests to be handled within\ + the one process, so long as one)-.25 F .856 +(thread does not block the whole process in a system call.)72 390 R .856 +(The \214le descriptor dispatcher in CommBase is)5.856 F(useful for pre) +72 402 Q -.15(ve)-.25 G(nting this: see).15 E F1(ftpfs)2.5 E F0 +(for a complete e)2.5 E(xample of a multithreaded \214lesystem.)-.15 E +EP +%%Trailer +end +%%EOF