[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

manish at oss.oracle.com manish at oss.oracle.com
Thu May 29 10:40:47 CDT 2003


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 at alcatel.com.au or mccormack at 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 <asm/posix_types.h>
+#include <asm/types.h>
+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 <linux/slab.h>
+#    include <linux/mm.h>
+#    include <linux/assert.h>	
+#    define ALLOC(x) kmalloc(x, GFP_KERNEL)
+#    define FREE(x) kfree(x)
+#  else
+#    define ALLOC ALLOC
+#    include <assert.h>
+#    include <stdlib.h>
+#ifdef __GLIBC__
+#include <time.h>
+#include <malloc.h>
+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 <linux/types.h>
+#include <linux/userfs_fs_i.h>
+#include <linux/userfs_fs_f.h>
+#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 <linux/param.h>	/* For NGROUPS */
+#include <linux/userfs_types.h>
+
+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 <linux/fs.h>
+
+#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 <asm/posix_types.h>
+#include <asm/types.h>
+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 <linux/slab.h>
+#    include <linux/mm.h>
+#    include <linux/assert.h>	
+#    define ALLOC(x) kmalloc(x, GFP_KERNEL)
+#    define FREE(x) kfree(x)
+#  else
+#    define ALLOC ALLOC
+#    include <assert.h>
+#    include <stdlib.h>
+#ifdef __GLIBC__
+#include <time.h>
+#include <malloc.h>
+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 <linux/types.h>
+#include <linux/userfs_fs_i.h>
+#include <linux/userfs_fs_f.h>
+#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 <linux/param.h>	/* For NGROUPS */
+#include <linux/userfs_types.h>
+
+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 <linux/fs.h>
+
+#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 <jeremy at sw.oz.au>, 1993-1996
+ */
+
+#include "userfs.h"
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/errno.h>
+#include <linux/locks.h>
+#include <linux/userfs_fs.h>
+#include <linux/userfs_fs_sb.h>
+#include <linux/assert.h>
+#include <asm/segment.h>
+#include <linux/string.h>
+#include <asm/uaccess.h>
+
+/* 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 <jeremy at softway.oz.au>, May 1993
+ */
+
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/errno.h>
+#include <linux/locks.h>
+#include <linux/assert.h>
+#include <linux/string.h>
+#include <linux/file.h>
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+
+#define __NO_VERSION__
+#include <linux/module.h>
+
+#include <linux/userfs_fs.h>
+#include <linux/userfs_fs_sb.h>
+#include <linux/userfs_mount.h>
+
+#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 <jeremy at softway.oz.au>, 1993-1995
+ */
+
+#include "userfs.h"
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/errno.h>
+#include <linux/fcntl.h>
+#include <linux/locks.h>
+#include <linux/userfs_fs.h>
+#include <linux/userfs_fs_sb.h>
+#include <linux/userfs_fs_f.h>
+#include <linux/userfs_mount.h>
+#include <linux/assert.h>
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+
+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 <linux/userfs_types.h>

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 <linux/userfs_types.ty>

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 <linux/kernel.h>
+#include <linux/autoconf.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/userfs_fs.h>
+#include <linux/userfs_fs_sb.h>
+#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 <linux/userfs_types.c>

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 <jeremy at softway.oz.au>, May 1993
+ */
+
+#include "userfs.h"
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/userfs_fs.h>
+#include <linux/userfs_fs_sb.h>
+#include <linux/locks.h>
+#include <linux/slab.h>
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+
+#define DB(x)	x
+
+#include <linux/assert.h>
+
+
+/* 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(&current->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(&current->blocked,SIGKILL);
+	sigaddset(&current->blocked,SIGALRM); */
+        sigfillset(&current->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 <linux/version.h>
+#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 <linux/autoconf.h> */
+/* #include <linux/module.h> */
+
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#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 <linux/userfs_fs.h>
+
+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 <linux/slab.h>
+
+/* 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 <linux/config.h>
+#endif
+
+#include <linux/posix_types.h>
+#include <asm/types.h>
+
+#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 <name> IDENT
+%token <type> TYPE
+%token <num> NUM
+%token <name> STRING
+
+%left '-' '+'
+%left '*' '/'
+
+%type <type> type struct qual_type unsigned signed
+%type <var> type_name varlist typedef c_ident c_id_list type_list
+%type <name> op_ident
+%type <num> 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 <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <assert.h>
+
+#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 <errno.h>
+#include "com.h"
+#include "symtab.h"
+#include "format.h"
+#include "misc.h"
+#include <getopt.h>
+
+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 <getopt.h>
+#include <ctype.h>
+
+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 <stdarg.h>
+
+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);
+
+<comment>[^*\n]+	/* eat up anything up to '*' */
+<comment>"*"+[^*/\n]*	/* eat up rows of '*' not followed by '/' */
+<comment>\n		line++;
+<comment>"*"+"/"	BEGIN(INITIAL);
+
+<string>\\.		*strptr++ = yytext[1];
+<string>\"		*strptr=0; yylval.name = strdup(strbuf); BEGIN(INITIAL); return STRING;
+<string>[^\\\"]+	{char *cp = yytext; while(*cp) *strptr++ = *cp++; }
+
+%%
+
+#include <stdio.h>
+#include <stdarg.h>
+
+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 <stdlib.h>
+#include <string.h>
+#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 <sys/types.h>
+}
+
+This will only generate code and definitions for the types in
+<sys/types.h> 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 <sys/types.h>
+
+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 <jeremy at sw.oz.au>

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 <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/mount.h>
+
+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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h>
+#include <mntent.h>
+#include <pwd.h>
+#include <getopt.h>
+#include <signal.h>
+#include <fcntl.h>
+
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+
+#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 <linux/types.h>
+#include <linux/fs.h>
+#include <linux/userfs_fs.h>
+#include <linux/userfs_mount.h>
+#include <linux/userfs_types.h>
+#include <linux/userfs_fs_sb.h>
+
+#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 <jeremy at sw.oz.au>
+ *
+ * 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 <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#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 <linux/userfs_types.c>

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 <sys/types.h>
+
+#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 <linux/unistd.h>
+
+_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 <jeremy at sw.oz.au>
+.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 at socs.uts.edu.au
+002.Leroy
+003.tlukka at vinkku.hut.fi
+004.Davor_Jadrijevic
+$ cat */From
+From: sbg at socs.uts.edu.au
+From: leroy at socs.uts.edu.au (Leroy)
+From: tlukka at vinkku.hut.fi
+From: davor%emard.uucp at 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 at vger.rutgers.edu\fP.
+To subscribe, send mail to \f(CWmajordomo at 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 <jeremy at sw.oz.au>) 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 <jeremy at sw.oz.au>
+// This code is distributed under the terms of the
+// GNU General Public Licence.  See COPYING for more details.
+
+#pragma implementation
+
+#include <Filesystem.h>
+#include <Comm.h>
+#include <io.h>
+#include <stdio.h>
+
+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 <jeremy at sw.oz.au> 1993
+
+#ifndef __COMM_H_SEEN__
+#define __COMM_H_SEEN__
+
+#pragma interface
+
+#include <CommBase.h>
+
+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 <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <assert.h>
+#include <sys/time.h>
+
+#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<void>  (( 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 <stdio.h>
+#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 <jeremy at sw.oz.au> 1993
+
+#pragma implementation
+
+#include "Inode.h"
+#include "Filesystem.h"
+
+#include <stdio.h>
+
+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 <SimpleInode.h>
+
+#include <sys/types.h>
+#include <string>
+
+#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 <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#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<void>  (( 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 <jeremy at sw.oz.au>

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 <Inode.h>
+
+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 <jeremy at sw.oz.au>
+// This code is distributed under the terms of the
+// GNU General Public Licence.  See COPYING for more details.
+
+#include <Filesystem.h>
+#include <ThreadComm.h>
+#include <LWP.h>
+#include <io.h>
+#include <linux/userfs_fs.h>
+#include <stdio.h>
+
+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 <DeferFilesys.h>

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 <jeremy at sw.oz.au>
+// 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 <jeremy at sw.oz.au>
+ *
+ * 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 <Filesystem.h>
+
+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 <jeremy at sw.oz.au> 1993
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <unistd.h>
+
+#pragma implementation
+
+#include "CommBase.h"
+#include "Filesystem.h"
+
+#define _SYS_SELECT_H	1
+#include <bits/select.h>
+
+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 <jeremy at sw.oz.au> 1993
+
+#ifndef __FILESYSTEM_H_SEEN__
+#define __FILESYSTEM_H_SEEN__
+
+#include <errno.h>
+
+#include <userfs_types.h>
+#include <linux/userfs_fs.h>
+
+#include <Inode.h>
+#include <CommBase.h>
+
+#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 <jeremy at sw.oz.au> 1993
+
+#ifndef __COMMBASE_H_SEEN__
+#define __COMMBASE_H_SEEN__
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#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 at 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 <jeremy at sw.oz.au>
+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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <utime.h>
+#include <dirent.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <getopt.h>
+#include <assert.h>
+
+#include <time.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+
+#include <linux/fs.h>
+#include <linux/userfs_fs.h>
+
+#include <assert.h>
+
+#include "tarfs.h"
+
+static char *mpoint;
+static TAR_DIRENT *root;
+
+/* No point in this being in a seperate file.  */
+#include <linux/userfs_types.c>
+
+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 <stdio.h>
+#include <stdlib.h>
+#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<stdio.h>
+#include<stdlib.h>
+
+#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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+#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
+<jeremy at sw.oz.au> 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 <stdio.h>
+#include <stdlib.h>
+#include <utime.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <getopt.h>
+#include <assert.h>
+
+#include <time.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+
+#include <linux/fs.h>
+#include <linux/userfs_fs.h>
+
+#include <unistd.h>
+#include <linux/dirent.h>
+#include <linux/unistd.h>
+
+#include <assert.h>
+
+#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 <linux/userfs_types.c>
+
+#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(n<len) 
+      {
+        if(strcmp(de->d_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 <string>
+#include <sys/types.h>
+#include <time.h>
+
+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 <jeremy at sw.oz.au>
+// This code is distributed under the terms of the
+// GNU General Public Licence.  See COPYING for more details.
+
+#pragma implementation
+
+#include "Path.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <assert.h>
+#include <string>
+
+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 <jeremy at sw.oz.au>
+// This code is distributed under the terms of the
+// GNU General Public Licence.  See COPYING for more details.
+
+#pragma implementation
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string>
+
+#include <unistd.h>
+#include <netdb.h>
+#include <stdio.h>
+
+#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 <jeremy at sw.oz.au>
+// 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 <string>
+
+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 <jeremy at sw.oz.au>
+// 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 <jeremy at sw.oz.au>
+// 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 <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <string>
+
+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 <jeremy at sw.oz.au>
+// 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 <string>
+#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 <jeremy at sw.oz.au>
+// This code is distributed under the terms of the
+// GNU General Public Licence.  See COPYING for more details.
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include <ThreadComm.h>
+#include <LWP.h>
+
+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 <jeremy at sw.oz.au>
+# 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 <jeremy at sw.oz.au>
+// 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 <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <string>
+
+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 <time.h>
+#include <sys/timeb.h>
+
+/*
+**  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 <jeremy at sw.oz.au>
+// This code is distributed under the terms of the
+// GNU General Public Licence.  See COPYING for more details.
+
+#pragma implementation
+
+#include <getopt.h>
+#include <stdio.h>
+
+#include <ThreadComm.h>
+#include "ftpfs.h"
+#include "topdir.h"
+
+#include <sys/param.h>
+#include <unistd.h>
+
+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 <jeremy at sw.oz.au>
+// This code is distributed under the terms of the
+// GNU General Public Licence.  See COPYING for more details.
+
+// Dos ftp server support by marcus at ee.pdx.edu (Marcus Daniels)
+
+#pragma implementation
+
+#include "dos_host.h"
+#include "serv_port.h"
+#include "ftpconn.h"
+#include "getdate.h"
+#include <io.h>
+
+#include <unistd.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <string>
+#include <stdio.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+
+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("^\\([^ /]+\\) *\\([<DIR>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("^.*/\\([^ /]+\\) *\\([<DIR>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 <jeremy at sw.oz.au>
+// 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 <sys/socket.h>
+#include <string>
+#include <netinet/in.h>
+
+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 <jeremy at sw.oz.au>
+// This code is distributed under the terms of the
+// GNU General Public Licence.  See COPYING for more details.
+
+#include "pushd.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+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 <netdb.h>
+#include <stdio.h>
+
+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 <jeremy at sw.oz.au>
+// 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 <jeremy at sw.oz.au>
+// 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 <jeremy at sw.oz.au>
+// 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 <SimpleInode.h>
+#include <LWP.h>
+
+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 <jeremy at sw.oz.au>
+ * 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 <jeremy at sw.oz.au>
+// 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 <jeremy at sw.oz.au>
+// This code is distributed under the terms of the
+// GNU General Public Licence.  See COPYING for more details.
+
+#pragma implementation
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <errno.h>
+
+#include <string>
+#include <iostream.h>
+#include <fstream.h>
+
+#include "ftpdir.h"
+#include "ftpconn.h"
+#include "ftplink.h"
+#include "ftpfile.h"
+#include "pushd.h"
+#include "ConfFile.h"
+#include <regex.h>
+
+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 <jeremy at sw.oz.au>
+// 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 <string>
+
+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 <smb at research.att.com> while
+**  at the University of North Carolina at Chapel Hill.  Later tweaked by
+**  a couple of people on Usenet.  Completely overhauled by Rich $alz
+**  <rsalz at bbn.com> and Jim Berets <jberets at bbn.com> 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 <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/timeb.h>
+#include <ctype.h>
+#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	<Number>	tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
+%type	<Number>	tSEC_UNIT tSNUMBER tUNUMBER tZONE
+%type	<Meridian>	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 <stdio.h>
+/* 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 <jeremy at sw.oz.au>
+// 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 <netdb.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string>
+#include <ctype.h>
+#include <arpa/telnet.h>
+#include <arpa/inet.h>
+#include <assert.h>
+
+#include <fstream.h>
+#include <obstack.h>
+
+#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 = "<<d/60<<"hr "<<d%60<<"min\n";
+		timezone = diff;
+		need_tz = 0;
+	}
+		
+	if ((ctlsock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+	{
+		perror("ftpconn::connect socket() failed");
+		return Bad;
+	}
+
+	if (::connect(ctlsock, (struct sockaddr *)&addr, sizeof(addr)) == -1)
+	{
+		perror("ftpconn::connect connect() failed");
+		::close(ctlsock);
+		return Bad;
+	}
+
+	int len = sizeof (myaddr);
+	if (getsockname(ctlsock, (struct sockaddr *)&myaddr, (socklen_t *)&len) < 0)
+	{
+		perror("ftpconn::connect getsockname() failed");
+		::close(ctlsock);
+		return Bad;
+	}
+
+	inbuf = new ifstream(ctlsock);
+	inbuf->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 <jeremy at sw.oz.au>
+// This code is distributed under the terms of the
+// GNU General Public Licence.  See COPYING for more details.
+
+#pragma implementation
+
+#include <fstream.h>
+
+#include "conninfo.h"
+#include "ftpconn.h"
+
+#include <sys/stat.h>
+
+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.off<<" arg.size="<<arg.size<<" str="<<s<<"\n";
+	
+	int sz = s.length() - arg.off;
+
+	if (sz <= 0)
+		sz = 0;
+
+	sz = sz > 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 <jeremy at sw.oz.au>
+// 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 <string>
+#include <netinet/in.h>
+
+#include "LWP.h"
+#include "ConfFile.h"
+
+enum ftpstate_t {
+	Unresolved,
+	Resolved,
+	Connected,
+	LoggedIn,
+	Listening,
+	Transfer,
+	Bad
+};
+
+#include <sys/types.h>
+#include <time.h>
+
+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 <jeremy at sw.oz.au>
+// 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 <string>
+
+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 <jeremy at sw.oz.au>
+// 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 <sys/types.h>
+#include <string>
+#include <netinet/in.h>
+
+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 <jeremy at sw.oz.au>
+// 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 <io.h>
+
+#include <unistd.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <string>
+#include <stdio.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+
+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 "<<asctime(tm);
+	return rtime;
+}
+
+// Parse a date from "ls" - its about the only thing getdate won't handle
+static time_t
+parsedate(const string &date, time_t timezone)
+{
+	string parts[3];
+
+	if (split(date, parts, 3, RXwhite) != 3)
+		return -1;
+	
+	static const string months[13] = { "xxx",
+		"Jan", "Feb", "Mar",
+		"Apr", "May", "Jun",
+		"Jul", "Aug", "Sep",
+		"Oct", "Nov", "Dec"
+		};
+
+	static const Regex rx_time("[012]?[0-9]:[0-5][0-9]");
+	static const Regex rx_year("[0-9][0-9][0-9][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;
+	
+	for(int i = 1; i < 13; i++)
+		if (parts[0] == months[i])
+		{
+			month = i;
+			break;
+		}
+	if (month == -1)
+		return 0;
+	
+	if (!parts[1].matches(rx_day))
+		return 0;
+	day = atoi(parts[1]);
+	
+	if (parts[2].matches(rx_year))
+		year = atoi(parts[2]);
+	else
+	{
+		string hm[2];
+		if (!parts[2].matches(rx_time))
+			return 0;
+		if (split(parts[2], hm, 2, string(":")) != 2)
+			return 0;
+		hours = atoi(hm[0]);
+		mins = atoi(hm[1]);
+	}
+
+	time_t now = time(0);
+
+	struct tm *tm = gmtime(&now);
+	
+	return Convert(month, day,
+		       year == -1 ? tm->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 <jeremy at sw.oz.au>
+// 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 <DirInode.h>
+#include <string>
+#include <LWP.h>
+#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 <jeremy at sw.oz.au>
+// This code is distributed under the terms of the
+// GNU General Public Licence.  See COPYING for more details.
+
+// Dos ftp server support by marcus at ee.pdx.edu (Marcus Daniels)
+
+#ifndef _DOS_HOST_H_
+#define _DOS_HOST_H_
+
+#pragma interface
+
+#include "host.h"
+#include <sys/socket.h>
+#include <string>
+#include <netinet/in.h>
+
+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 <jeremy at sw.oz.au>
+// 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 <Filesystem.h>
+#include <string>
+
+// 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 <jeremy at sw.oz.au>
+// 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 <string>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <fstream.h>
+#include <strstream.h>
+
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <regex.h>
+
+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(&regex, "^\\([a-zA-Z_]+\\):[ \t]*\\(.*\\)$", 0)==0)
+{
+    if (regexec(&regex, 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(&regex);
+}
+
+}
+
+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 <jeremy at sw.oz.au>
+// 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 <jeremy at sw.oz.au>
+// 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 <string>
+#include <unistd.h>
+#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 <LWP.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <utime.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string>
+#include <assert.h>
+#include <stdio.h>
+
+#include <iostream.h>
+
+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 <jeremy at sw.oz.au>
+// 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 <sys/time.h>
+
+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 <SimpleInode.h>
+#include <string>
+
+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 <DeferComm.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+
+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 <string>
+#include <SimpleInode.h>
+
+#include <sys/types.h>
+
+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 <mount-point> <base-dir>
+
+The <base-dir> 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 at 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 <string>
+#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 <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+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 <DeferComm.h>
+#include <GetOpt.h>
+#include <stdio.h>
+
+#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 <DeferFilesys.h>
+#include <string>
+
+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 <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <errno.h>
+#include <stdio.h>
+
+#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 <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#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 <string>
+#include <DirInode.h>
+
+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 <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+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 <DirInode.h>
+#include <string>
+
+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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <utime.h>
+#include <dirent.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <getopt.h>
+#include <assert.h>
+
+#include <time.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+
+#include <linux/fs.h>
+
+#include <linux/userfs_fs.h>
+#include <linux/unistd.h>
+
+#include <assert.h>
+#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 <linux/userfs_types.c>
+
+#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<stdio.h>
+#include<linux/errno.h>
+#include<sys/stat.h>
+#include<sys/types.h>
+#include<fcntl.h>
+#include<unistd.h>
+#include<string.h>
+
+#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) && (data[i]!='\n') && (data[i]!=0) )
+		i++;
+		
+	if(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 <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#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) && !end; i++)
+		{
+			if(saw_esc)
+			{
+				if(line[i]!='@')
+					end = 1;
+				else
+					count++;
+				saw_esc = 0;
+			}
+			else
+			{
+				if(line[i]=='@')
+					saw_esc = 1;
+				else
+					count++;
+			}
+		}
+	}
+	return count;
+}
+
+/*
+ * Read a single line into the buffer
+ * if the line is longer than the buffer, only the end will be read
+ */
+int ReadLine(int fd, unsigned char *buffer, int bsize)
+{
+	int n,i;
+
+	/* keep reading until we find a cr then go back */
+	do {
+		n = read(fd,buffer,bsize);
+		if(n<=0)
+			return 1;
+		for(i=0; i<n; i++)
+			if(buffer[i]=='\n')
+				break;
+	}
+	while (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<n) && !end; i++,total++)
+		{
+			if(!saw_esc && ((count%CVSBLOCK)==0))
+			{
+				offsets[count/CVSBLOCK]=start+total;
+				/* printf("%x -> %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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <utime.h>
+#include <dirent.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <getopt.h>
+#include <assert.h>
+
+#include <time.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+
+#include <linux/fs.h>
+
+#include <linux/userfs_fs.h>
+#include <linux/unistd.h>
+
+#include <assert.h>
+#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(n<len) 
+      {
+        if(strcmp(de->d_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
+	<the install userfs and start cvsfs>
+	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 <linux/userfs_types.h>
+
+#define FAIL(str)	fprintf(stderr, "%s:%d %s failed with errno = %s (%d)\n", __FILE__, __LINE__, str, strerror(errno), errno)
+#ifdef DEBUG
+#include <stdio.h>
+#include <stdlib.h>
+#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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <utime.h>
+#include <dirent.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <getopt.h>
+#include <assert.h>
+
+#include <time.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+
+#include <linux/fs.h>
+#include <linux/userfs_fs.h>
+
+#include <assert.h>
+
+/* #include <gnome.h> */
+#include <libgnomevfs/gnome-vfs.h>
+
+#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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <utime.h>
+#include <dirent.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <getopt.h>
+#include <assert.h>
+
+#include <time.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+
+#include <linux/fs.h>
+#include <linux/userfs_fs.h>
+
+#include <assert.h>
+
+#include "vfsbase.h"
+
+/* No point in this being in a seperate file.  */
+#include <linux/userfs_types.c>
+
+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 <stdlib.h>
+#include <string.h>
+
+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 <Comm.h>
+#include <Filesystem.h>
+#include <DirInode.h>
+#include <SimpleInode.h>
+#include "homer.h"
+#include "password.h"
+#include <sys/stat.h>
+#include <getopt.h>
+#include <signal.h>
+#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 <GetOpt.h>
+
+// Filesystem related headers
+#include <Comm.h>
+#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 <Filesystem.h>
+#include <String.h>
+#include <fstream.h>
+
+#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 <unistd.h>
+#include <sys/stat.h>
+
+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 <sys/stat.h>
+#include <unistd.h>
+
+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<message> &m;
+// DLList<header> &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<message> &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<header> &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 <SimpleInode.h>
+#include <String.h>
+#include <time.h>
+
+#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 <unistd.h>
+#include <sys/stat.h>
+#include <fstream.h>
+
+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 <DirInode.h>
+#include <time.h>
+#include <fstream.h>
+
+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 <stdio.h>
+#include <unistd.h>
+#include <String.h>
+#include <DLList.h>
+#include <sys/file.h>
+#include <stdlib.h>
+#include <fstream.h>
+#include <time.h>
+
+#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<header> 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<header> *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<message> messages;
+ ifstream *file;
+public:
+ mail(ifstream *);
+ ~mail() { };
+ void disp();
+ DLList<message> 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 <SimpleInode.h>
+#include <String.h>
+#include <fstream.h>
+#include <time.h>
+
+#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 <davor%emard.uucp at ds5000.irb.hr>
+.\" 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 at socs.uts.edu.au
+ From: leroy at socs.uts.edu.au (Leroy)
+ From: tlukka at 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 <davor%emard.uucp at ds5000.irb.hr>
+.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 <davj at ds5000.irb.hr>
+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 <jeremy at sw.oz.au> 1994,1995
+
+#pragma implementation
+
+#include "egfile.h"
+
+#include <unistd.h>
+#include <sys/stat.h>
+
+// 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 <string>
+#include <DirInode.h>
+
+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 <SimpleInode.h>
+#include <string.h>
+
+#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 <jeremy at sw.oz.au> 1994,1995
+
+#pragma implementation
+
+// Misc headers
+#include <getopt.h>
+#include <stdio.h>
+
+// Filesystem related headers
+#include <Comm.h>
+
+#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 <Filesystem.h>
+
+#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 <jeremy at sw.oz.au> 1994,1995
+
+#pragma implementation
+
+#include "egdir.h"
+#include "egfile.h"
+#include "egfs.h"
+
+#include <sys/stat.h>
+#include <unistd.h>
+
+// 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <utime.h>
+#include <dirent.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <getopt.h>
+#include <assert.h>
+
+#include <time.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+
+#include <linux/fs.h>
+#include <linux/userfs_fs.h>
+
+#include <assert.h>
+
+#include "arcfs.h"
+
+static char *mpoint;
+static ARC_DIRENT *root;
+
+/* No point in this being in a seperate file.  */
+#include <linux/userfs_types.c>
+
+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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+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 <stdio.h>
+#include <stdlib.h>
+#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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+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
+<jeremy at sw.oz.au>.
+
+
+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 at 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.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    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.
+
+  <signature of Ty Coon>, 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 at 0 ENC0/Courier RE/Times-Roman at 0 ENC0/Times-Roman RE
+/Times-Italic at 0 ENC0/Times-Italic RE/Times-Bold at 0 ENC0/Times-Bold RE
+%%EndProlog
+%%Page: 1 1
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 12/Times-Bold at 0 SF(Userfs \255 Filesystems Implemented as User Pr)
+155.886 82.031 Q(ocesses)-.216 E/F1 10/Times-Italic at 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 at sw)-.37 E(.oz.au>)-.74 E/F2 10/Times-Roman at 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 at 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 at socs.uts.edu.au)122 496.031 Q(002.Leroy)122 507.031 Q
+(003.tlukka at 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 at socs.uts.edu.au)122
+551.031 Q(From: leroy at socs.uts.edu.au \(Leroy\))122 562.031 Q
+(From: tlukka at vinkku.hut.fi)122 573.031 Q
+(From: davor%emard.uucp at 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 at 0 SF 2.5(-2-)279.67 48 S/F1 10/Times-Italic at 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 at 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 at 0 SF
+(linux-)3.193 E(userfs at 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 at vger.rutgers.edu)2.965 E F0(with)2.965 E(the contents)72 426
+Q/F4 9/Courier at 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 <jeremy at sw)72 575 Q
+(.oz.au>\) 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 0 SF 2.5(-8-)279.67 48 S/F1 10/Times-Italic at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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



More information about the Userfs-commits mailing list