summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorprovos <provos@openbsd.org>2000-06-17 17:16:04 +0000
committerprovos <provos@openbsd.org>2000-06-17 17:16:04 +0000
commite992cbe461beb200ab4a608f15221ab77469ac6f (patch)
tree396d8bca32faf371a2a7330a5b07e23144b8f5d4
parentsome silly error repairs (diff)
downloadwireguard-openbsd-e992cbe461beb200ab4a608f15221ab77469ac6f.tar.xz
wireguard-openbsd-e992cbe461beb200ab4a608f15221ab77469ac6f.zip
initial import of tcfs.
-rw-r--r--sys/conf/files17
-rw-r--r--sys/kern/vfs_conf.c15
-rw-r--r--sys/miscfs/tcfs/tcfs.h89
-rw-r--r--sys/miscfs/tcfs/tcfs_attr.c129
-rw-r--r--sys/miscfs/tcfs/tcfs_cipher.h84
-rw-r--r--sys/miscfs/tcfs/tcfs_cipher_BLOWFISH.c40
-rw-r--r--sys/miscfs/tcfs/tcfs_cipher_TDES.c73
-rw-r--r--sys/miscfs/tcfs/tcfs_cipher_conf.c21
-rw-r--r--sys/miscfs/tcfs/tcfs_cipher_none.c18
-rw-r--r--sys/miscfs/tcfs/tcfs_cmd.c205
-rw-r--r--sys/miscfs/tcfs/tcfs_cmd.h17
-rw-r--r--sys/miscfs/tcfs/tcfs_crypto.c38
-rw-r--r--sys/miscfs/tcfs/tcfs_dir.c188
-rw-r--r--sys/miscfs/tcfs/tcfs_fileinfo.c75
-rw-r--r--sys/miscfs/tcfs/tcfs_fileinfo.h34
-rw-r--r--sys/miscfs/tcfs/tcfs_interp.c128
-rw-r--r--sys/miscfs/tcfs/tcfs_keytab.c457
-rw-r--r--sys/miscfs/tcfs/tcfs_keytab.h97
-rw-r--r--sys/miscfs/tcfs/tcfs_mount.h39
-rw-r--r--sys/miscfs/tcfs/tcfs_rw.c616
-rw-r--r--sys/miscfs/tcfs/tcfs_rw.h52
-rw-r--r--sys/miscfs/tcfs/tcfs_subr.c355
-rw-r--r--sys/miscfs/tcfs/tcfs_version.h3
-rw-r--r--sys/miscfs/tcfs/tcfs_vfsops.c329
-rw-r--r--sys/miscfs/tcfs/tcfs_vnops.c435
-rw-r--r--sys/sys/mount.h3
-rw-r--r--sys/sys/vnode.h4
27 files changed, 3556 insertions, 5 deletions
diff --git a/sys/conf/files b/sys/conf/files
index 396c56abcb8..9fbf1874a92 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1,4 +1,4 @@
-# $OpenBSD: files,v 1.168 2000/06/12 17:23:49 itojun Exp $
+# $OpenBSD: files,v 1.169 2000/06/17 17:16:04 provos Exp $
# $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@@ -434,6 +434,21 @@ file miscfs/kernfs/kernfs_vnops.c kernfs
file miscfs/nullfs/null_subr.c nullfs
file miscfs/nullfs/null_vfsops.c nullfs
file miscfs/nullfs/null_vnops.c nullfs
+file miscfs/tcfs/tcfs_subr.c tcfs
+file miscfs/tcfs/tcfs_vfsops.c tcfs
+file miscfs/tcfs/tcfs_vnops.c tcfs
+file miscfs/tcfs/tcfs_attr.c tcfs
+file miscfs/tcfs/tcfs_cipher_TDES.c tcfs
+file miscfs/tcfs/tcfs_cipher_BLOWFISH.c tcfs
+file miscfs/tcfs/tcfs_cipher_conf.c tcfs
+file miscfs/tcfs/tcfs_cipher_none.c tcfs
+file miscfs/tcfs/tcfs_cmd.c tcfs
+file miscfs/tcfs/tcfs_crypto.c tcfs
+file miscfs/tcfs/tcfs_dir.c tcfs
+file miscfs/tcfs/tcfs_fileinfo.c tcfs
+file miscfs/tcfs/tcfs_interp.c tcfs
+file miscfs/tcfs/tcfs_keytab.c tcfs
+file miscfs/tcfs/tcfs_rw.c tcfs
file miscfs/portal/portal_vfsops.c portal
file miscfs/portal/portal_vnops.c portal
file miscfs/procfs/procfs_ctl.c procfs
diff --git a/sys/kern/vfs_conf.c b/sys/kern/vfs_conf.c
index a08299bdaca..96c7a45c921 100644
--- a/sys/kern/vfs_conf.c
+++ b/sys/kern/vfs_conf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vfs_conf.c,v 1.14 2000/02/07 04:53:33 assar Exp $ */
+/* $OpenBSD: vfs_conf.c,v 1.15 2000/06/17 17:16:05 provos Exp $ */
/* $NetBSD: vfs_conf.c,v 1.21.4.1 1995/11/01 00:06:26 jtc Exp $ */
/*
@@ -151,6 +151,10 @@ extern struct vfsops ext2fs_vfsops;
extern struct vfsops xfs_vfsops;
#endif
+#ifdef TCFS
+extern struct vfsops tcfs_vfsops;
+#endif
+
/*
* Set up the filesystem operations for vnodes.
*/
@@ -239,6 +243,10 @@ static struct vfsconf vfsconflist[] = {
{ &kernfs_vfsops, MOUNT_KERNFS, 11, 0, 0, NULL, NULL },
#endif
+#ifdef TCFS
+ { &tcfs_vfsops, MOUNT_TCFS, 22, 0, 0, NULL, NULL },
+#endif
+
};
@@ -285,6 +293,7 @@ extern struct vnodeopv_desc ext2fs_vnodeop_opv_desc;
extern struct vnodeopv_desc ext2fs_specop_opv_desc;
extern struct vnodeopv_desc ext2fs_fifoop_opv_desc;
extern struct vnodeopv_desc xfs_vnodeop_opv_desc;
+extern struct vnodeopv_desc tcfs_vnodeop_opv_desc;
struct vnodeopv_desc *vfs_opv_descs[] = {
&sync_vnodeop_opv_desc,
@@ -361,5 +370,9 @@ struct vnodeopv_desc *vfs_opv_descs[] = {
#ifdef XFS
&xfs_vnodeop_opv_desc,
#endif
+#ifdef TCFS
+ &tcfs_vnodeop_opv_desc,
+#endif
+
NULL
};
diff --git a/sys/miscfs/tcfs/tcfs.h b/sys/miscfs/tcfs/tcfs.h
new file mode 100644
index 00000000000..d801376fe37
--- /dev/null
+++ b/sys/miscfs/tcfs/tcfs.h
@@ -0,0 +1,89 @@
+#ifndef _TCFS_MOUNT_H_
+#include "tcfs_mount.h"
+#endif
+
+#ifdef _KERNEL
+/*
+ * A cache of vnode references
+ */
+struct tcfs_node {
+ LIST_ENTRY(tcfs_node) tcfs_hash; /* Hash list */
+ struct vnode *tcfs_lowervp; /* VREFed once */
+ struct vnode *tcfs_vnode; /* Back pointer */
+};
+
+extern int tcfs_node_create __P((struct mount *mp, struct vnode *target, struct vnode **vpp, int lockit));
+
+#define MOUNTTOTCFSMOUNT(mp) ((struct tcfs_mount *)((mp)->mnt_data))
+#define VTOTCFS(vp) ((struct tcfs_node *)(vp)->v_data)
+#define TCFSTOV(xp) ((xp)->tcfs_vnode)
+#ifdef TCFS_DIAGNOSTIC
+extern struct vnode *tcfs_checkvp __P((struct vnode *vp, char *fil, int lno));
+#define TCFSVPTOLOWERVP(vp) tcfs_checkvp((vp), __FILE__, __LINE__)
+#else
+#define TCFSVPTOLOWERVP(vp) (VTOTCFS(vp)->tcfs_lowervp)
+#endif
+
+#define TCFS_VP2UKT(vp) ((MOUNTTOTCFSMOUNT(((vp)->v_mount)))->tcfs_uid_kt)
+#define TCFS_VP2GKT(vp) ((MOUNTTOTCFSMOUNT(((vp)->v_mount)))->tcfs_gid_kt)
+
+#define tcfs_fhtovp ((int (*) __P((struct mount *, struct fid *, \
+ struct vnode **)))eopnotsupp)
+#define tcfs_vptofh ((int (*) __P((struct vnode *, struct fid *)))eopnotsupp)
+
+extern int (**tcfs_vnodeop_p) __P((void *));
+extern struct vfsops tcfs_vfsops;
+
+int tcfs_init __P((struct vfsconf *));
+
+#define BLOCKSIZE 1024
+#define SBLOCKSIZE 8
+
+#define ABS(a) ((a)>=0?(a):(-a))
+
+/* variabili esterne */
+
+
+/* prototyphes */
+
+int tcfs_bypass __P((void *));
+int tcfs_open __P((void *));
+int tcfs_getattr __P((void *));
+int tcfs_setattr __P((void *));
+int tcfs_inactive __P((void *));
+int tcfs_reclaim __P((void *));
+int tcfs_print __P((void *));
+int tcfs_strategy __P((void *));
+int tcfs_bwrite __P((void *));
+int tcfs_lock __P((void *));
+int tcfs_unlock __P((void *));
+int tcfs_islocked __P((void *));
+int tcfs_read __P((void *));
+int tcfs_readdir __P((void *));
+int tcfs_write __P((void *));
+int tcfs_create __P((void *));
+int tcfs_mknod __P((void *));
+int tcfs_mkdir __P((void *));
+int tcfs_link __P((void *));
+int tcfs_symlink __P((void *));
+int tcfs_rename __P((void *));
+int tcfs_lookup __P((void *));
+
+void *tcfs_getukey(struct ucred *, struct proc *, struct vnode *);
+void *tcfs_getpkey(struct ucred *, struct proc *, struct vnode *);
+void *tcfs_getgkey(struct ucred *, struct proc *, struct vnode *);
+int tcfs_checkukey(struct ucred *, struct proc *, struct vnode *);
+int tcfs_checkpkey(struct ucred *, struct proc *, struct vnode *);
+int tcfs_checkgkey(struct ucred *, struct proc *, struct vnode *);
+int tcfs_exec_cmd(struct tcfs_mount*, struct tcfs_args *);
+int tcfs_init_mp(struct tcfs_mount*, struct tcfs_args *);
+int tcfs_set_status(struct tcfs_mount *, struct tcfs_args *, int);
+
+#define TCFS_CHECK_AKEY(c,p,v) (\
+ tcfs_checkukey((c),(p),(v)) || \
+ tcfs_checkpkey((c),(p),(v)) || \
+ tcfs_checkgkey((c),(p),(v)) )
+
+#endif /* _KERNEL */
+
+
diff --git a/sys/miscfs/tcfs/tcfs_attr.c b/sys/miscfs/tcfs/tcfs_attr.c
new file mode 100644
index 00000000000..de5efa2aa8f
--- /dev/null
+++ b/sys/miscfs/tcfs/tcfs_attr.c
@@ -0,0 +1,129 @@
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#include <miscfs/tcfs/tcfs.h>
+#include "tcfs_rw.h"
+
+int
+tcfs_getattr(v)
+ void *v;
+{
+ struct vop_getattr_args *ap = v;
+ int error;
+ tcfs_fileinfo i;
+ if ((error = tcfs_bypass(ap)) != 0)
+ return (error);
+ /* Requires that arguments be restored. */
+
+ ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
+ i.flag=ap->a_vap->va_flags;
+ ap->a_vap->va_size-=FI_SPURE(&i);
+
+ return (0);
+}
+
+
+int
+tcfs_setattr(v)
+void *v;
+{
+ struct vop_setattr_args *a = v;
+ struct vattr *ap;
+ u_quad_t size=0;
+ tcfs_fileinfo i,n;
+ int error,sp=0;
+
+
+ i=tcfs_xgetflags(a->a_vp,a->a_p,a->a_cred);
+ ap=a->a_vap;
+
+ if(FI_GSHAR(&i))
+ {
+ if(!tcfs_getgkey(a->a_cred,a->a_p,a->a_vp))
+ {
+ return EACCES;
+ }
+ }
+ else
+ {
+ if (!tcfs_getpkey(a->a_cred,a->a_p,a->a_vp))
+ if (!tcfs_getukey(a->a_cred,a->a_p,a->a_vp))
+ {
+ return EACCES;
+ }
+ }
+
+ if ((ap->va_flags)!=VNOVAL)
+ {
+
+
+ n.flag=ap->va_flags;
+ n.end_of_file=i.end_of_file;
+
+ if((FI_CFLAG(&n)&&FI_GSHAR(&i))||(FI_GSHAR(&n)&&FI_CFLAG(&i)))
+ {
+ return EACCES;
+ }
+
+ if(FI_SPURE(&n)!=FI_SPURE(&i))
+ {
+ /* le spure no (le settano solo write e trunc) */
+ return EACCES;
+ }
+
+ if(FI_CFLAG(&n)&&(!FI_CFLAG(&i)))
+ {
+ sp=tcfs_ed(a->a_vp, a->a_p, a->a_cred, &n);
+ FI_SET_SP(&n,sp);
+ }
+
+ if((!FI_CFLAG(&n))&&FI_CFLAG(&i))
+ {
+ sp=tcfs_ed(a->a_vp, a->a_p, a->a_cred, &n);
+ FI_SET_SP(&n,0);
+ }
+
+ if(FI_GSHAR(&n)&&(!FI_GSHAR(&i)))
+ {
+ sp=tcfs_ed(a->a_vp, a->a_p, a->a_cred, &n);
+ FI_SET_SP(&n,sp);
+ }
+
+ if((!FI_GSHAR(&n))&&FI_GSHAR(&i))
+ {
+ sp=tcfs_ed(a->a_vp, a->a_p, a->a_cred, &n);
+ FI_SET_SP(&n,0);
+ }
+
+
+ ap->va_flags=i.flag=n.flag;
+ if(a->a_vp->v_type==VREG)
+ {
+ ap->va_size=FI_ENDOF(&i)+sp;
+ error=tcfs_xsetflags(a->a_vp, a->a_p,a->a_cred,&i);
+ }
+ return tcfs_bypass((void*)v);
+ }
+ if ((ap->va_size)!=VNOVAL)
+ {
+
+ if(ap->va_size == 0)
+ size=0;
+ else
+ size=(u_quad_t)(D_PFOFF(ap->va_size)+1);
+
+ FI_SET_SP(&i,(size-ap->va_size));
+ ap->va_size=size;
+ error=tcfs_xsetflags(a->a_vp, a->a_p,a->a_cred,&i);
+ }
+
+ return tcfs_bypass((void*)v);
+}
+
diff --git a/sys/miscfs/tcfs/tcfs_cipher.h b/sys/miscfs/tcfs/tcfs_cipher.h
new file mode 100644
index 00000000000..cb09bfd6d29
--- /dev/null
+++ b/sys/miscfs/tcfs/tcfs_cipher.h
@@ -0,0 +1,84 @@
+#ifndef _TCFS_MOUNT_H_
+#include "tcfs_mount.h"
+#endif
+
+#define _TCFS_CIPHER_H_
+#define MaxNumOfCipher 8
+#define MaxCipherNameLen 8
+
+enum {
+ C_TDES=0,C_BLOW=2
+ } ;
+
+struct tcfs_cipher
+ {
+ char cipher_desc[MaxCipherNameLen];
+ int cipher_version;
+ int cipher_keysize;
+ void *(*init_key)(char*);
+ void (*cleanup_key)(void*);
+ void (*encrypt)(char*, int, void*);
+ void (*decrypt)(char*, int, void*);
+ };
+
+extern struct tcfs_cipher tcfs_cipher_vect[MaxNumOfCipher];
+
+#define TCFS_MP_CIPHER(mp) (((struct tcfs_mount*)(mp))->tcfs_cipher_num)
+
+#define TCFS_CIPHER_KEYSIZE(mp)\
+ (tcfs_cipher_vect[TCFS_MP_CIPHER((mp))].cipher_keysize)
+
+#define TCFS_CIPHER_VERSION(mp)\
+ (tcfs_cipher_vect[TCFS_MP_CIPHER((mp))].cipher_version)
+
+#define TCFS_CIPHER_DESC(mp)\
+ (tcfs_cipher_vect[TCFS_MP_CIPHER((mp))].cipher_desc)
+
+static __inline void *TCFS_INIT_KEY(struct tcfs_mount *,char *);
+static __inline void *TCFS_INIT_KEY(struct tcfs_mount *mp, char *tok)
+{
+ return (tcfs_cipher_vect[TCFS_MP_CIPHER((mp))].init_key((tok)));
+}
+
+static __inline void TCFS_CLEANUP_KEY(struct tcfs_mount*,void*);
+static __inline void TCFS_CLEANUP_KEY(struct tcfs_mount* mp,void* tok)
+{
+ (tcfs_cipher_vect[TCFS_MP_CIPHER((mp))].cleanup_key((tok)));
+ return;
+}
+static __inline void TCFS_ENCRYPT(struct tcfs_mount*,char*,int,void*);
+static __inline void TCFS_ENCRYPT(struct tcfs_mount *mp,char *blk,int len,void *key)
+{
+ (tcfs_cipher_vect[TCFS_MP_CIPHER((mp))].encrypt((blk),(len),(key)));
+ return;
+}
+static __inline void TCFS_DECRYPT(struct tcfs_mount*,char*,int,void*);
+static __inline void TCFS_DECRYPT(struct tcfs_mount *mp,char *blk,int len,void *key)
+{
+ (tcfs_cipher_vect[TCFS_MP_CIPHER((mp))].decrypt((blk),(len),(key)));
+ return;
+}
+
+void mkencrypt (struct tcfs_mount *, char *, int, void*);
+void mkdecrypt (struct tcfs_mount *, char *, int, void*);
+
+/* prototipi funzioni */
+
+void *cnone_init_key(char *);
+void cnone_cleanup_key(void*);
+void cnone_encrypt(char *, int , void*);
+void cnone_decrypt(char *, int , void*);
+#define NONE_KEYSIZE 0
+
+void *TDES_init_key(char *);
+void TDES_cleanup_key(void*);
+void TDES_encrypt(char *, int , void*);
+void TDES_decrypt(char *, int , void*);
+#define TDES_KEYSIZE 8
+
+void *BLOWFISH_init_key(char *);
+void BLOWFISH_cleanup_key(void*);
+void BLOWFISH_encrypt(char *, int , void*);
+void BLOWFISH_decrypt(char *, int , void*);
+#define BLOWFISH_KEYSIZE 8
+
diff --git a/sys/miscfs/tcfs/tcfs_cipher_BLOWFISH.c b/sys/miscfs/tcfs/tcfs_cipher_BLOWFISH.c
new file mode 100644
index 00000000000..dc1424edbac
--- /dev/null
+++ b/sys/miscfs/tcfs/tcfs_cipher_BLOWFISH.c
@@ -0,0 +1,40 @@
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include "tcfs_cipher.h"
+#include "crypto/blf.h"
+
+
+void *
+BLOWFISH_init_key (char *key)
+{
+ blf_ctx *ks=NULL;
+
+ ks=(blf_ctx *)malloc (sizeof (blf_ctx), M_FREE, M_NOWAIT);
+ if (!ks)
+ return NULL;
+
+ blf_key (ks, key, BLOWFISH_KEYSIZE);
+
+ return (void *)ks;
+}
+
+void
+BLOWFISH_cleanup_key(void *k)
+{
+ free((blf_ctx *)k, M_FREE);
+}
+
+void
+BLOWFISH_encrypt(char *block, int nb, void *key)
+{
+ char iv[] = {'\0','\0','\0','\0','\0','\0','\0','\0'};
+ blf_cbc_encrypt((blf_ctx *)key, iv, block, nb);
+}
+
+void
+BLOWFISH_decrypt(char *block, int nb, void *key)
+{
+ char iv[] = {'\0','\0','\0','\0','\0','\0','\0','\0'};
+ blf_cbc_decrypt((blf_ctx *)key, iv, block, nb);
+}
diff --git a/sys/miscfs/tcfs/tcfs_cipher_TDES.c b/sys/miscfs/tcfs/tcfs_cipher_TDES.c
new file mode 100644
index 00000000000..b7e77dd84e8
--- /dev/null
+++ b/sys/miscfs/tcfs/tcfs_cipher_TDES.c
@@ -0,0 +1,73 @@
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include "tcfs_cipher.h"
+#include <crypto/des_locl.h>
+#include <crypto/des.h>
+
+void *TDES_init_key (char *key)
+{
+ des_key_schedule *ks;
+
+ ks=(des_key_schedule *)malloc (2*sizeof (des_key_schedule), M_FREE,M_NOWAIT);
+ if (!ks)
+ return NULL;
+
+ des_set_key ((des_cblock *)key, ks[0]);
+ des_set_key ((des_cblock *)(key+8), ks[1]);
+
+ return (void *)ks;
+}
+
+void TDES_cleanup_key(void *k)
+{
+/* tcfs_keytab_dispnode does it
+ free((des_key_schedule*)k,M_FREE);
+*/
+}
+
+void TDES_encrypt(char *block, int nb, void *key)
+{
+ unsigned long * xi;
+ int i;
+ char *tmp;
+ des_key_schedule *ks=(des_key_schedule *)key;
+ xi=(long *)block;
+ tmp=block;
+ des_ecb3_encrypt((des_cblock *)tmp,(des_cblock *)tmp,ks[0],ks[1],ks[0],DES_ENCRYPT);
+ tmp+=8;
+ for (i=1;i<nb/8;i++) {
+ *(xi+2)^=*xi;
+ *(xi+3)^=*(xi+1);
+ des_ecb3_encrypt((des_cblock *)tmp,(des_cblock *)tmp,ks[0],ks[1],ks[0],DES_ENCRYPT);
+ tmp+=8;
+ xi+=2;
+ }
+}
+
+void TDES_decrypt(char *block, int nb, void *key)
+{
+ unsigned long * xi,xo[2],xa[2];
+ int i;
+ char *tmp;
+ des_key_schedule *ks=(des_key_schedule *)key;
+
+ xi=(long *)block;
+ tmp=block;
+ xo[0]=*xi; xo[1]=*(xi+1);
+ des_ecb3_encrypt((des_cblock *)tmp,(des_cblock *)tmp,ks[0],ks[1],ks[0],DES_DECRYPT);
+ tmp+=8;
+ xi=(long *)tmp;
+ for (i=1;i<nb/8;i++) {
+ xa[0]=*xi; xa[1]=*(xi+1);
+ des_ecb3_encrypt((des_cblock *)tmp,(des_cblock *)tmp,ks[0],ks[1],ks[0],DES_DECRYPT);
+ *(xi)^=xo[0];
+ *(xi+1)^=xo[1];
+ xo[0]=xa[0];
+ xo[1]=xa[1];
+ tmp+=8;
+ xi+=2;
+ }
+}
+
+
diff --git a/sys/miscfs/tcfs/tcfs_cipher_conf.c b/sys/miscfs/tcfs/tcfs_cipher_conf.c
new file mode 100644
index 00000000000..bd86f8b2c00
--- /dev/null
+++ b/sys/miscfs/tcfs/tcfs_cipher_conf.c
@@ -0,0 +1,21 @@
+#include "tcfs_cipher.h"
+
+struct tcfs_cipher tcfs_cipher_vect[]={
+ {"3des",0,TDES_KEYSIZE,TDES_init_key,TDES_cleanup_key,
+ TDES_encrypt,TDES_decrypt},
+ {"none",0,0,cnone_init_key,cnone_cleanup_key,
+ cnone_encrypt,cnone_decrypt},
+ {"bfish",0,BLOWFISH_KEYSIZE,BLOWFISH_init_key,BLOWFISH_cleanup_key,
+ BLOWFISH_encrypt,BLOWFISH_decrypt},
+ {"none",0,0,cnone_init_key,cnone_cleanup_key,
+ cnone_encrypt,cnone_decrypt},
+ {"none",0,0,cnone_init_key,cnone_cleanup_key,
+ cnone_encrypt,cnone_decrypt},
+ {"none",0,0,cnone_init_key,cnone_cleanup_key,
+ cnone_encrypt,cnone_decrypt},
+ {"none",0,0,cnone_init_key,cnone_cleanup_key,
+ cnone_encrypt,cnone_decrypt},
+ {"none",0,0,cnone_init_key,cnone_cleanup_key,
+ cnone_encrypt,cnone_decrypt},
+};
+
diff --git a/sys/miscfs/tcfs/tcfs_cipher_none.c b/sys/miscfs/tcfs/tcfs_cipher_none.c
new file mode 100644
index 00000000000..fd107ab228f
--- /dev/null
+++ b/sys/miscfs/tcfs/tcfs_cipher_none.c
@@ -0,0 +1,18 @@
+#include "tcfs_cipher.h"
+
+void *cnone_init_key (char *key)
+{
+ return (void *)key;
+}
+
+void cnone_cleanup_key(void *k)
+{
+}
+
+void cnone_encrypt(char *block, int nb, void *key)
+{
+}
+
+void cnone_decrypt(char *block, int nb, void *key)
+{
+}
diff --git a/sys/miscfs/tcfs/tcfs_cmd.c b/sys/miscfs/tcfs/tcfs_cmd.c
new file mode 100644
index 00000000000..d8da2b8d221
--- /dev/null
+++ b/sys/miscfs/tcfs/tcfs_cmd.c
@@ -0,0 +1,205 @@
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#include <miscfs/tcfs/tcfs.h>
+#include "tcfs_rw.h"
+#ifndef _TCFS_KEYTAB_H_
+#include "tcfs_keytab.h"
+#endif
+#include "tcfs_cmd.h"
+#include "tcfs_cipher.h"
+
+int tcfs_init_mp(struct tcfs_mount *mp, struct tcfs_args *req)
+{
+ int result=0;
+ int status=0;
+
+ if (!(mp->tcfs_uid_kt=tcfs_keytab_init()))
+ {
+ result= ENOMEM;
+ status= ALLOCATION_FAILED;
+ }
+ else
+ {
+ if (!(mp->tcfs_gid_kt=tcfs_keytab_init()))
+ {
+ tcfs_keytab_dispose(mp->tcfs_uid_kt);
+ status= ALLOCATION_FAILED;
+ result= ENOMEM;
+ }
+ else
+ {
+ if ((req->cipher_num>=MaxNumOfCipher)||
+ (tcfs_cipher_vect[req->cipher_num].cipher_keysize==0))
+ {
+ result=EINVAL;
+ status=BAD_CIPHER_NUMBER;
+ tcfs_keytab_dispose(mp->tcfs_uid_kt);
+ tcfs_keytab_dispose(mp->tcfs_gid_kt);
+ }
+ else
+ mp->tcfs_cipher_num=req->cipher_num;
+ }
+ }
+
+ (void)tcfs_set_status(mp,req,status);
+ return result;
+}
+
+int tcfs_exec_cmd(struct tcfs_mount *mp, struct tcfs_args *req)
+{
+ void *ks;
+ int result=0;
+ int status=0;
+
+
+ switch (req->cmd)
+ {
+ case TCFS_PUT_UIDKEY:
+ ks=TCFS_INIT_KEY(mp,req->tcfs_key);
+ if(!ks)
+ {
+ result= ENOMEM;
+ status= ALLOCATION_FAILED;
+ break;
+ }
+ result=tcfs_keytab_push_uid(mp->tcfs_uid_kt,req->user,ks);
+ if(result)
+ {
+ TCFS_CLEANUP_KEY(mp,ks);
+ status=PUSHKEY_ERROR;
+ }
+ break;
+
+ case TCFS_RM_UIDKEY:
+ result = tcfs_keytab_rm_uid(mp->tcfs_uid_kt,req->user);
+ status=(result?RMKEY_ERROR:TCFS_OK);
+ break;
+
+ case TCFS_PUT_PIDKEY:
+ ks=TCFS_INIT_KEY(mp,req->tcfs_key);
+ if(!ks)
+ {
+ result= ENOMEM;
+ status= ALLOCATION_FAILED;
+ break;
+ }
+ result=tcfs_keytab_push_pid(mp->tcfs_uid_kt,req->user,req->proc,ks);
+ if(result)
+ {
+ TCFS_CLEANUP_KEY(mp,ks);
+ status=PUSHKEY_ERROR;
+ }
+ break;
+
+ case TCFS_RM_PIDKEY:
+ result=tcfs_keytab_rm_pid(mp->tcfs_uid_kt,req->user,req->proc);
+ status=(result?RMKEY_ERROR:TCFS_OK);
+ break;
+
+ case TCFS_PUT_GIDKEY:
+ result=tcfs_keytab_push_gid(mp,mp->tcfs_gid_kt,req->user,req->group,req->treshold,req->tcfs_key);
+
+ status=(result?PUSHKEY_ERROR:TCFS_OK);
+ break;
+
+ case TCFS_RM_GIDKEY:
+ result= tcfs_keytab_rm_gid(mp->tcfs_gid_kt,req->user,req->group);
+ status=(result?RMKEY_ERROR:TCFS_OK);
+ break;
+
+ case TCFS_GET_STATUS:
+ return tcfs_set_status(mp,req,TCFS_OK);
+ }
+ (void)tcfs_set_status(mp,req,status);
+ return result;
+}
+
+int tcfs_set_status(struct tcfs_mount *mp, struct tcfs_args *req, int error)
+{
+ req->st.status=error;
+ req->st.tcfs_version=TCFS_VERSION_NUM;
+
+ if(error!=TCFS_OK)
+ return error;
+
+ req->st.n_ukey=mp->tcfs_uid_kt->cnt;
+ req->st.n_gkey=mp->tcfs_gid_kt->cnt;
+ strncpy(req->st.cipher_desc,TCFS_CIPHER_DESC(mp),MaxCipherNameLen);
+ req->st.cipher_keysize=TCFS_CIPHER_KEYSIZE(mp);
+ req->st.cipher_version=TCFS_CIPHER_VERSION(mp);
+
+ return error;
+}
+
+int tcfs_checkukey(struct ucred *c, struct proc *p, struct vnode *vp)
+{
+ return tcfs_keytab_check_uid(TCFS_VP2UKT(vp),c->cr_uid);
+}
+
+void *tcfs_getukey(struct ucred *c, struct proc *p, struct vnode *vp)
+{
+ tcfs_keytab_node *n;
+
+ n=tcfs_keytab_fetch_uid(TCFS_VP2UKT(vp),c->cr_uid);
+
+ if(n)
+ return n->kn_key;
+ else
+ {
+ return (void*)NULL;
+ }
+}
+int tcfs_checkpkey(struct ucred *c, struct proc *p, struct vnode *vp)
+{
+ struct proc *cp;
+ if(!p)
+ cp=curproc;
+ else
+ cp=p;
+
+ return tcfs_keytab_check_pid(TCFS_VP2UKT(vp),c->cr_uid,cp->p_pid);
+}
+
+void *tcfs_getpkey(struct ucred *c, struct proc *p, struct vnode *vp)
+{
+ tcfs_keytab_node *n;
+ struct proc *cp;
+
+ if(!p)
+ cp=curproc;
+ else
+ cp=p;
+
+ n=tcfs_keytab_fetch_pid(TCFS_VP2UKT(vp),c->cr_uid,cp->p_pid);
+
+ if(n)
+ return n->kn_key;
+ else
+ return (void*)NULL;
+}
+
+int tcfs_checkgkey(struct ucred *c, struct proc *p, struct vnode *vp)
+{
+ return tcfs_keytab_check_uid(TCFS_VP2GKT(vp),c->cr_gid);
+}
+
+void *tcfs_getgkey(struct ucred *c, struct proc *p, struct vnode *vp)
+{
+ tcfs_keytab_node *n;
+
+ n=tcfs_keytab_fetch_gid(TCFS_VP2GKT(vp),c->cr_gid);
+
+ if(n)
+ return n->kn_key;
+ else
+ return (void*)NULL;
+}
+
diff --git a/sys/miscfs/tcfs/tcfs_cmd.h b/sys/miscfs/tcfs/tcfs_cmd.h
new file mode 100644
index 00000000000..a4b7d841dbc
--- /dev/null
+++ b/sys/miscfs/tcfs/tcfs_cmd.h
@@ -0,0 +1,17 @@
+/* tcfs commands */
+#define TCFS_PUT_UIDKEY 1
+#define TCFS_RM_UIDKEY 2
+#define TCFS_PUT_PIDKEY 3
+#define TCFS_RM_PIDKEY 4
+#define TCFS_PUT_GIDKEY 5
+#define TCFS_RM_GIDKEY 6
+#define TCFS_GET_STATUS 7
+
+/* tcfs errors */
+#define TCFS_OK 0
+#define UNKNOWN_COMMAND 1
+#define BAD_CIPHER_NUMBER 2
+#define PUSHKEY_ERROR 3
+#define RMKEY_ERROR 3
+#define ALLOCATION_FAILED 4
+
diff --git a/sys/miscfs/tcfs/tcfs_crypto.c b/sys/miscfs/tcfs/tcfs_crypto.c
new file mode 100644
index 00000000000..e9d1782ffa3
--- /dev/null
+++ b/sys/miscfs/tcfs/tcfs_crypto.c
@@ -0,0 +1,38 @@
+#include "tcfs_cipher.h"
+
+#define BLOCKSIZE 1024
+#define SBLOCKSIZE 8
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#define D_NOBLK(o) ((o)/BLOCKSIZE+(o%BLOCKSIZE?1:0))
+
+
+void mkencrypt(struct tcfs_mount *mp,char *block,int nb, void* ks)
+{
+ int i,r;
+ char *tmp;
+
+ tmp=block;
+ r=nb;
+ for(i=0;i<D_NOBLK(nb)&&r>0;i++)
+ {
+ TCFS_ENCRYPT(mp,tmp,MIN(BLOCKSIZE,r),ks);
+ tmp+=BLOCKSIZE;
+ r-=BLOCKSIZE;
+ }
+}
+
+void mkdecrypt(struct tcfs_mount *mp,char *block,int nb,void* ks)
+{
+ int i,r;
+ char *tmp;
+
+ tmp=block;
+ r=nb;
+ for(i=0;i<D_NOBLK(nb)&&r>0;i++)
+ {
+ TCFS_DECRYPT(mp, tmp,MIN(BLOCKSIZE,r),ks);
+ tmp+=BLOCKSIZE;
+ r-=BLOCKSIZE;
+ }
+}
+
diff --git a/sys/miscfs/tcfs/tcfs_dir.c b/sys/miscfs/tcfs/tcfs_dir.c
new file mode 100644
index 00000000000..f58ae871056
--- /dev/null
+++ b/sys/miscfs/tcfs/tcfs_dir.c
@@ -0,0 +1,188 @@
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#include <sys/dirent.h>
+#include <miscfs/tcfs/tcfs.h>
+#include "tcfs_rw.h"
+
+int tcfs_new_direntry (void *, tcfs_fileinfo *);
+
+int tcfs_new_direntry(void *v , tcfs_fileinfo *i)
+{
+ struct vop_create_args *x;
+ struct ucred *cr;
+ struct proc *pr;
+ int err;
+
+ x=(struct vop_create_args *)v;
+ cr=x->a_cnp->cn_cred;
+ pr=x->a_cnp->cn_proc;
+
+ if(!TCFS_CHECK_AKEY(cr,pr,x->a_dvp))
+ return tcfs_bypass(v);
+
+ /* Per i file speciali e per i link, niente flags (per ora)*/
+ if((x->a_desc==VDESC(vop_mknod))||
+ (x->a_desc==VDESC(vop_symlink))||
+ (x->a_desc==VDESC(vop_link)))
+ {
+ err=tcfs_bypass(v);
+ return err;
+ }
+
+ if(!(err=tcfs_bypass(v)))
+ err=tcfs_xsetflags(*(x->a_vpp),pr,cr,i);
+
+ return err;
+}
+
+int tcfs_create(v)
+void *v;
+{
+ struct vop_create_args *x;
+ struct ucred *cr;
+ struct proc *pr;
+ tcfs_fileinfo i;
+
+ x=(struct vop_create_args *)v;
+ cr=x->a_cnp->cn_cred;
+ pr=x->a_cnp->cn_proc;
+ i=tcfs_xgetflags(x->a_dvp,pr,cr);
+
+ if(FI_CFLAG(&i)||FI_GSHAR(&i))
+ return tcfs_new_direntry(v,&i);
+ else
+ return tcfs_bypass(v);
+}
+
+int tcfs_mknod(v)
+void *v;
+{
+ struct vop_mknod_args *x;
+ struct ucred *cr;
+ struct proc *pr;
+ tcfs_fileinfo i;
+
+ x=(struct vop_mknod_args *)v;
+ cr=x->a_cnp->cn_cred;
+ pr=x->a_cnp->cn_proc;
+ i=tcfs_xgetflags(x->a_dvp,pr,cr);
+
+ if(FI_CFLAG(&i)||FI_GSHAR(&i))
+ return tcfs_new_direntry(v,&i);
+ else
+ return tcfs_bypass(v);
+}
+
+int tcfs_mkdir(v)
+void *v;
+{
+ struct vop_mkdir_args *x;
+ struct ucred *cr;
+ struct proc *pr;
+ tcfs_fileinfo i;
+
+ x=(struct vop_mkdir_args *)v;
+ cr=x->a_cnp->cn_cred;
+ pr=x->a_cnp->cn_proc;
+ i=tcfs_xgetflags(x->a_dvp,pr,cr);
+
+ if(FI_CFLAG(&i)||FI_GSHAR(&i))
+ return tcfs_new_direntry(v,&i);
+ else
+ return tcfs_bypass(v);
+}
+
+int tcfs_link(v)
+void *v;
+{
+ struct vop_link_args *x;
+ struct ucred *cr;
+ struct proc *pr;
+ tcfs_fileinfo i;
+
+ x=(struct vop_link_args *)v;
+ cr=x->a_cnp->cn_cred;
+ pr=x->a_cnp->cn_proc;
+ i=tcfs_xgetflags(x->a_dvp,pr,cr);
+
+ if(FI_CFLAG(&i)||FI_GSHAR(&i))
+ return tcfs_new_direntry(v,&i);
+ else
+ return tcfs_bypass(v);
+}
+
+int tcfs_symlink(v)
+void *v;
+{
+ struct vop_symlink_args *x;
+ struct ucred *cr;
+ struct proc *pr;
+ tcfs_fileinfo i;
+
+ x=(struct vop_symlink_args *)v;
+ cr=x->a_cnp->cn_cred;
+ pr=x->a_cnp->cn_proc;
+ i=tcfs_xgetflags(x->a_dvp,pr,cr);
+
+ if(FI_CFLAG(&i)||FI_GSHAR(&i))
+ return tcfs_new_direntry(v,&i);
+ else
+ return tcfs_bypass(v);
+}
+
+int tcfs_readdir(v)
+void *v;
+{
+/*
+ tcfs_fileinfo i;
+ struct vop_readdir_args *a=(struct vop_readdir_args*)v;
+ struct dirent *s,*d,*e;
+ char *p;
+ int err;
+ off_t offset;
+ int req,resid;
+
+
+ i=tcfs_xgetflags(a->a_vp,a->a_uio->uio_procp,a->a_cred);
+ offset=a->a_uio->uio_offset;
+ req=a->a_uio->uio_resid;
+ p=a->a_uio->uio_iov->iov_base;
+
+ err=tcfs_bypass(v);
+ resid=a->a_uio->uio_resid;
+
+ s=(struct dirent*)p;
+ e=(struct dirent*)a->a_uio->uio_iov->iov_base;
+
+ if( (!FI_CFLAG(&i)) && (!FI_GSHAR(&i)) )
+ return err;
+
+ for(d=s; d<e && d->d_reclen;d=(struct dirent*)((char*)d+d->d_reclen))
+ {
+ if(!d->d_fileno)
+ continue;
+ if((d->d_namlen==1 && d->d_name[0]=='.') ||
+ (d->d_namlen==2 && d->d_name[0]=='.' && d->d_name[1]=='.'))
+ continue;
+
+ if(d->d_namlen)
+ d->d_name[0]--;
+ }
+ return err;
+*/
+ return tcfs_bypass(v);
+}
+
+int tcfs_rename(v)
+void *v;
+{
+ return tcfs_bypass(v);
+}
diff --git a/sys/miscfs/tcfs/tcfs_fileinfo.c b/sys/miscfs/tcfs/tcfs_fileinfo.c
new file mode 100644
index 00000000000..7077ee8f134
--- /dev/null
+++ b/sys/miscfs/tcfs/tcfs_fileinfo.c
@@ -0,0 +1,75 @@
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#include <sys/stat.h>
+#include <miscfs/tcfs/tcfs.h>
+#include "tcfs_rw.h"
+
+
+tcfs_fileinfo tcfs_xgetflags(struct vnode *v, struct proc *p, struct ucred *c)
+{
+ tcfs_fileinfo r;
+ struct vop_getattr_args x;
+ struct vattr att;
+ int retval;
+
+ att=va_null;
+ x.a_desc=VDESC(vop_getattr);
+ x.a_vp=v;
+ x.a_vap=&att;
+ x.a_cred=c;
+ x.a_p=p;
+
+ retval=tcfs_bypass((void*)&x);
+ r.flag=(unsigned long)(x.a_vap->va_flags);
+ r.end_of_file=x.a_vap->va_size;
+
+ return r;
+}
+
+int tcfs_xsetflags(struct vnode *v, struct proc *p, struct ucred *c, tcfs_fileinfo *i)
+{
+ struct vop_setattr_args x;
+ struct vattr att;
+ int retval;
+
+ att=va_null;
+
+ att.va_flags=i->flag;
+
+ x.a_desc=VDESC(vop_setattr);
+ x.a_vp=v;
+ x.a_vap=&att;
+ x.a_cred=c;
+ x.a_p=p;
+
+ retval=tcfs_bypass((void*)&x);
+ return retval;
+}
+
+
+
+tcfs_fileinfo tcfs_get_fileinfo(void *a)
+{
+ struct vop_read_args *arg;
+
+ arg=(struct vop_read_args*)a;
+ return tcfs_xgetflags(arg->a_vp,arg->a_uio->uio_procp,arg->a_cred);
+}
+
+
+int tcfs_set_fileinfo(void *a, tcfs_fileinfo *i)
+{
+ struct vop_read_args *arg;
+
+ arg=(struct vop_read_args*)a;
+ return tcfs_xsetflags(arg->a_vp, arg->a_uio->uio_procp,arg->a_cred,i); ;
+}
+
diff --git a/sys/miscfs/tcfs/tcfs_fileinfo.h b/sys/miscfs/tcfs/tcfs_fileinfo.h
new file mode 100644
index 00000000000..e64eff4fc75
--- /dev/null
+++ b/sys/miscfs/tcfs/tcfs_fileinfo.h
@@ -0,0 +1,34 @@
+/* Gestione informazioni sui files cifrati
+*/
+
+
+typedef struct {
+ unsigned long flag;
+ unsigned int end_of_file;
+ } tcfs_fileinfo;
+
+#define MBFLAG 0x00000010
+#define SPFLAG 0x000000e0
+#define GSFLAG 0x00000100
+
+#define FI_CFLAG(x) (((x)->flag&MBFLAG)>>4)
+#define FI_SPURE(x) (((x)->flag&SPFLAG)>>5)
+#define FI_GSHAR(x) (((x)->flag&GSFLAG)>>8)
+#define FI_ENDOF(x) ((x)->end_of_file)
+
+#define FI_SET_CF(x,y) ((x)->flag=\
+ ((x)->flag & (~MBFLAG))|((y<<4)&MBFLAG))
+
+#define FI_SET_SP(x,y) ((x)->flag=\
+ ((x)->flag & (~SPFLAG))|((y<<5)&SPFLAG))
+
+#define FI_SET_GS(x,y) ((x)->flag=\
+ ((x)->flag & (~GSFLAG))|((y<<8)&GSFLAG))
+
+/* prototipi */
+
+tcfs_fileinfo tcfs_get_fileinfo(void *);
+tcfs_fileinfo tcfs_xgetflags(struct vnode *,struct proc *,struct ucred*);
+int tcfs_set_fileinfo(void *, tcfs_fileinfo *);
+int tcfs_xsetflags(struct vnode *, struct proc *, struct ucred *, tcfs_fileinfo *);
+
diff --git a/sys/miscfs/tcfs/tcfs_interp.c b/sys/miscfs/tcfs/tcfs_interp.c
new file mode 100644
index 00000000000..3647a046be6
--- /dev/null
+++ b/sys/miscfs/tcfs/tcfs_interp.c
@@ -0,0 +1,128 @@
+#include<sys/types.h>
+#include<sys/malloc.h>
+#include<sys/errno.h>
+#include "tcfs_keytab.h"
+#include "tcfs_cipher.h"
+
+int interp(tcfs_grp_data *,unsigned char *);
+void doinverse(void);
+
+static int inverse[]={
+ 0,1,129,86,193,103,43,147,225,200,180,187,150,178,
+ 202,120,241,121,100,230,90,49,222,190,75,72,89,238,
+ 101,195,60,199,249,148,189,235,50,132,115,145,45,163,
+ 153,6,111,40,95,175,166,21,36,126,173,97,119,243,179,248,
+ 226,61,30,59,228,102,253,87,74,234,223,149,246,181,25,
+ 169,66,24,186,247,201,244,151,165,210,96,205,127,3,65,
+ 184,26,20,209,176,152,216,46,83,53,139,135,18,28,63,5,
+ 215,164,177,245,188,224,250,44,218,116,124,38,113,134,
+ 159,54,15,17,158,140,114,220,51,85,255,2,172,206,37,143,
+ 117,99,240,242,203,98,123,144,219,133,141,39,213,7,33,69,
+ 12,80,93,42,252,194,229,239,122,118,204,174,211,41,105,
+ 81,48,237,231,73,192,254,130,52,161,47,92,106,13,56,10,
+ 71,233,191,88,232,76,11,108,34,23,183,170,4,155,29,198,
+ 227,196,31,9,78,14,138,160,84,131,221,236,91,82,162,217,
+ 146,251,104,94,212,112,142,125,207,22,68,109,8,58,197,
+ 62,156,19,168,185,182,67,35,208,167,27,157,136,16,137,
+ 55,79,107,70,77,57,32,110,214,154,64,171,128,256
+};
+
+union bobbit {
+ unsigned char byte;
+ struct {
+ unsigned char b1:1;
+ unsigned char b2:1;
+ unsigned char b3:1;
+ unsigned char b4:1;
+ unsigned char b5:1;
+ unsigned char b6:1;
+ unsigned char b7:1;
+ unsigned char b8:1;
+ } bf;
+};
+
+#define mod(a) ((unsigned int)((a)%257))
+/*
+unsigned int mod(long a)
+{
+ return (unsigned int) a%257;
+}
+*/
+
+int interp(tcfs_grp_data *gd,unsigned char *gidkey)
+{
+ unsigned int tp,kkk;
+ int i=0,j,l,idx;
+ tcfs_grp_uinfo ktmp[MAXUSRPERGRP],*gui;
+ unsigned int inv,ttt;
+ union bobbit obits;
+ int k;
+
+ k=gd->gd_k;
+
+ for (i=0;i<MAXUSRPERGRP && i<k;i++)
+ {
+ gui=&(gd->gd_part[i]);
+ if(!IS_SET_GUI(*gui))
+ continue;
+ ktmp[i].gui_uid=gui->gui_uid;
+
+ for(l=0;l<KEYSIZE/8;l++){
+ obits.byte=gui->gui_tcfskey[9*l+8];
+ ktmp[i].gui_tcfskey[8*l+0]=mod(obits.bf.b1<<8 | gui->gui_tcfskey[9*l+0]);
+ ktmp[i].gui_tcfskey[8*l+1]=mod(obits.bf.b2<<8 | gui->gui_tcfskey[9*l+1]);
+ ktmp[i].gui_tcfskey[8*l+2]=mod(obits.bf.b3<<8 | gui->gui_tcfskey[9*l+2]);
+ ktmp[i].gui_tcfskey[8*l+3]=mod(obits.bf.b4<<8 | gui->gui_tcfskey[9*l+3]);
+ ktmp[i].gui_tcfskey[8*l+4]=mod(obits.bf.b5<<8 | gui->gui_tcfskey[9*l+4]);
+ ktmp[i].gui_tcfskey[8*l+5]=mod(obits.bf.b6<<8 | gui->gui_tcfskey[9*l+5]);
+ ktmp[i].gui_tcfskey[8*l+6]=mod(obits.bf.b7<<8 | gui->gui_tcfskey[9*l+6]);
+ ktmp[i].gui_tcfskey[8*l+7]=mod(obits.bf.b8<<8 | gui->gui_tcfskey[9*l+7]);
+ }
+
+ i++;
+ }
+
+ for (idx=0;idx<KEYSIZE;idx++) {
+ kkk=0;
+ for (i=0;i<k;i++) {
+ tp=1;
+ for (j=0;j<k;j++) {
+ if (j!=i) {
+ inv = inverse[mod(ktmp[i].gui_uid-ktmp[j].gui_uid)];
+ ttt = mod(inv * mod(-ktmp[j].gui_uid));
+ tp = mod(tp * ttt);
+ }
+ }
+ tp *= mod(ktmp[i].gui_tcfskey[idx]);
+ kkk=(tp+kkk);
+ }
+ gidkey[idx]=(unsigned char)mod(kkk);
+ }
+ return 0;
+}
+
+void doinverse(void)
+{
+ int i,j;
+ for (i=0;i<257;i++) {
+ for (j=0;j<257;j++) {
+ if (mod((i*j))==1)
+ inverse[i]=j;
+ }
+ }
+}
+
+int tcfs_interp(struct tcfs_mount *mp, tcfs_keytab_node* x)
+{
+ void *ks;
+ char key[KEYSIZE];
+
+ interp(x->kn_data,key);
+ ks=TCFS_INIT_KEY(mp,key);
+ if (!ks)
+ return ENOMEM;
+
+ x->kn_key=ks;
+ return TCFS_OK;
+}
+
diff --git a/sys/miscfs/tcfs/tcfs_keytab.c b/sys/miscfs/tcfs/tcfs_keytab.c
new file mode 100644
index 00000000000..89fbfa9f602
--- /dev/null
+++ b/sys/miscfs/tcfs/tcfs_keytab.c
@@ -0,0 +1,457 @@
+#include<sys/errno.h>
+#include<sys/types.h>
+#include<sys/systm.h>
+#ifndef _TCFS_KEYTAB_H_
+#include "tcfs_keytab.h"
+#endif
+#include<sys/malloc.h>
+
+tcfs_keytab_node *tcfs_keytab_newnode()
+{
+ tcfs_keytab_node *n;
+
+ n=(tcfs_keytab_node*)malloc(sizeof(tcfs_keytab_node),M_FREE,M_NOWAIT);
+ if(!n)
+ return n;
+
+ n->kn_key=(void*)0;
+ n->kn_data=(tcfs_grp_data*)0;
+ n->kn_type=CLEAN;
+ n->kn_n=n->kn_p=NIL;
+ return n;
+}
+
+tcfs_keytab_node *tcfs_keytab_newgidnode()
+{
+ tcfs_keytab_node *n;
+ tcfs_grp_data *gd;
+ int i;
+
+ n=tcfs_keytab_newnode();
+ if(!n)
+ return n;
+
+ gd=(tcfs_grp_data*)malloc(sizeof(tcfs_grp_data),M_FREE,M_NOWAIT);
+ if(!gd)
+ {
+ tcfs_keytab_dispnode(n);
+ return NIL;
+ }
+ gd->gd_n=0;
+ gd->gd_k=0;
+ for(i=0;i<MAXUSRPERGRP;i++);
+ {
+ gd->gd_part[i].gui_flag=GUI_CLEAN;
+ gd->gd_part[i].gui_uid=65535; /* nobody */
+ }
+
+ n->kn_data=gd;
+ n->kn_type=GID_KEY;
+ n->kn_key=(void*)0;
+
+ return n;
+}
+
+
+
+void tcfs_keytab_dispnode(tcfs_keytab_node *n)
+{
+ if(n->kn_key)
+ free(n->kn_key,M_FREE);
+
+
+ if(n->kn_data)
+ free(n->kn_data,M_FREE);
+
+ if(n)
+ free(n,M_FREE);
+}
+
+
+
+tcfs_keytab *tcfs_keytab_init()
+{
+ tcfs_keytab *x;
+ int i;
+
+ x=(tcfs_keytab*)malloc(sizeof(tcfs_keytab),M_FREE,M_NOWAIT);
+ if (!x)
+ return x;
+
+ x->cnt=0;
+
+ for(i=0;i<KEYTABSIZE;i++) /*una bzero o simile magari */
+ x->node[i]=NIL;
+
+ return x;
+}
+
+void tcfs_keytab_dispose(tcfs_keytab *kt)
+{
+ tcfs_keytab_node *p,*q;
+ int i=0;
+
+ if(kt->cnt)
+ for(i=0;i<KEYTABSIZE;i++)
+ {
+ p=kt->node[i];
+ while(p!=NIL)
+ {
+ q=p->kn_n;
+ tcfs_keytab_dispnode(p);
+ p=q;
+ }
+ }
+
+ free(kt,M_FREE);
+}
+
+int tcfs_keytab_check_uid(tcfs_keytab *t, uid_t uid)
+{
+ int pos;
+ tcfs_keytab_node *p;
+
+ pos=tcfs_keytab_hash(uid);
+ p=t->node[pos];
+
+ while(p!=NIL)
+ {
+ if (IS_UID_NODE(p) && p->kn_uid==uid)
+ return 1;
+ p=p->kn_n;
+ }
+ return 0;
+}
+
+
+tcfs_keytab_node *tcfs_keytab_fetch_uid(tcfs_keytab *t, uid_t uid)
+{
+ tcfs_keytab_node *p;
+ int pos;
+
+ pos=tcfs_keytab_hash(uid);
+ p=t->node[pos];
+ while(p!=NIL)
+ {
+ if(IS_UID_NODE(p) && p->kn_uid==uid)
+ break;
+ p=p->kn_n;
+ }
+ return p;
+}
+
+int tcfs_keytab_check_gid(tcfs_keytab *t, gid_t gid)
+{
+ tcfs_keytab_node *p;
+ int pos;
+
+ pos=tcfs_keytab_hash(gid);
+ p=t->node[pos];
+
+ while (p!=NIL)
+ {
+ if(IS_GID_NODE(p) && p->kn_gid==gid && IS_READY_GD(p->kn_data))
+ return 1;
+ p=p->kn_n;
+ }
+ return 0;
+}
+
+
+tcfs_keytab_node *tcfs_keytab_fetch_gid(tcfs_keytab *t, gid_t gid)
+{
+ tcfs_keytab_node *p;
+ int pos;
+
+ pos=tcfs_keytab_hash(gid);
+ p=t->node[pos];
+ while(p!=NIL)
+ {
+ if(IS_GID_NODE(p) && p->kn_gid==gid)
+ break;
+ p=p->kn_n;
+ }
+ return p;
+}
+
+
+
+int tcfs_keytab_check_pid(tcfs_keytab *t, uid_t uid, pid_t pid)
+{
+ int pos;
+ tcfs_keytab_node *p;
+
+ pos=tcfs_keytab_hash(pid);
+ p=t->node[pos];
+
+ while(p!=NIL)
+ {
+ if (IS_PID_NODE(p) && p->kn_pid==pid && p->kn_uid==uid)
+ return 1;
+ p=p->kn_n;
+ }
+ return 0;
+}
+
+tcfs_keytab_node *tcfs_keytab_fetch_pid(tcfs_keytab *t, uid_t uid, pid_t pid)
+{
+ tcfs_keytab_node *p;
+ int pos;
+
+ pos=tcfs_keytab_hash(pid);
+ p=t->node[pos];
+
+ while(p!=NIL)
+ {
+ if(IS_PID_NODE(p) && p->kn_pid==pid && p->kn_uid==uid)
+ break;
+ p=p->kn_n;
+ }
+ return p;
+}
+
+int tcfs_keytab_push_pid(tcfs_keytab *t, uid_t uid, pid_t pid, void *ks)
+{
+ int pos=0;
+ tcfs_keytab_node *p,*q;
+
+ if(tcfs_keytab_fetch_pid(t,uid,pid)!=NIL)
+ return EINVAL;
+
+ q=tcfs_keytab_newnode();
+ if(!q)
+ return ENOMEM;
+
+ pos=tcfs_keytab_hash(pid);
+
+ p=t->node[pos];
+ q->kn_n=p;
+ if(p!=NIL)
+ p->kn_p=q;
+ t->node[pos]=q;
+ t->cnt++;
+
+ q->kn_uid=uid;
+ q->kn_pid=pid;
+ q->kn_key=ks;
+ q->kn_type=PID_KEY;
+
+ return TCFS_OK;
+}
+
+int tcfs_keytab_push_uid(tcfs_keytab *t, uid_t uid, void *key)
+{
+ int pos=0;
+ tcfs_keytab_node *p,*q;
+
+
+ if(tcfs_keytab_fetch_uid(t,uid)!=NIL)
+ return EINVAL;
+
+ q=tcfs_keytab_newnode();
+ if(!q)
+ return ENOMEM;
+
+ pos=tcfs_keytab_hash(uid);
+
+ p=t->node[pos];
+ q->kn_n=p;
+ if(p!=NIL)
+ p->kn_p=q;
+ t->node[pos]=q;
+ t->cnt++;
+
+ q->kn_uid=uid;
+ q->kn_pid=0;
+ q->kn_key=key;
+ q->kn_type=UID_KEY;
+
+ return TCFS_OK;
+}
+
+int tcfs_keytab_push_gidpart(struct tcfs_mount *mp,tcfs_keytab_node *kn,uid_t uid, gid_t gid, int k,char *key)
+{
+ int i=0;
+ int first=-1;
+ tcfs_grp_data *p;
+
+ p=kn->kn_data;
+
+ if(IS_FULL_GD(p))
+ return EINVAL;
+
+ for (i=0;i<MAXUSRPERGRP;i++)
+ {
+ if(first<0 && !IS_SET_GUI(p->gd_part[i]))
+ {
+ first=i;
+ continue;
+ }
+ if(IS_SET_GUI(p->gd_part[i]) &&
+ p->gd_part[i].gui_uid==uid)
+ return EINVAL;
+ }
+
+ p->gd_part[first].gui_uid=uid;
+ p->gd_part[first].gui_flag=GUI_SET;
+ memcpy(p->gd_part[first].gui_tcfskey,key,KEYPARTSIZE);
+ if(IS_CLEAN_GD(p))
+ p->gd_k=k;
+
+ p->gd_n++;
+
+ if(IS_READY_GD(p)&&(!kn->kn_key))
+ tcfs_interp(mp,kn);
+
+ return TCFS_OK;
+}
+
+int tcfs_keytab_rm_gidpart(tcfs_keytab_node *kn, uid_t uid, gid_t gid)
+{
+ int i=0;
+ tcfs_grp_data *p;
+
+ p=kn->kn_data;
+
+ if(IS_CLEAN_GD(p))
+ return EINVAL;
+
+ for (i=0;i<MAXUSRPERGRP;i++)
+ if(IS_SET_GUI(p->gd_part[i]))
+ if(p->gd_part[i].gui_uid==uid)
+ {
+ p->gd_part[i].gui_flag=GUI_CLEAN;
+ break;
+ }
+
+ if (i==MAXUSRPERGRP)
+ return EINVAL;
+
+ p->gd_n--;
+
+ if(!IS_READY_GD(p))
+ if(kn->kn_key)
+ {
+ free(kn->kn_key,M_FREE);
+ kn->kn_key=(void*)0;
+ }
+
+ return TCFS_OK;
+}
+
+int tcfs_keytab_push_gid(struct tcfs_mount *mp,tcfs_keytab *t, uid_t uid, gid_t gid, int k, char* key)
+{
+ int pos=0;
+ tcfs_keytab_node *p,*q,*r;
+
+ q=r=tcfs_keytab_fetch_gid(t,gid);
+
+ if(r==NIL)
+ {
+ q=tcfs_keytab_newgidnode();
+ if(!q)
+ return ENOMEM;
+
+ pos=tcfs_keytab_hash(gid);
+
+ p=t->node[pos];
+ q->kn_n=p;
+ if(p!=NIL)
+ p->kn_p=q;
+ t->node[pos]=q;
+ t->cnt++;
+
+ q->kn_gid=gid;
+ q->kn_pid=0;
+ q->kn_uid=0;
+ }
+
+ return tcfs_keytab_push_gidpart(mp,q,uid,gid,k,key);
+}
+
+int tcfs_keytab_rm_uid(tcfs_keytab *t, uid_t uid)
+{
+ int pos=0;
+ tcfs_keytab_node *p;
+
+ p=tcfs_keytab_fetch_uid(t,uid);
+ if(p==NIL)
+ return EINVAL;
+
+ if(p->kn_p==NIL)
+ {
+ pos=tcfs_keytab_hash(uid);
+ t->node[pos]=p->kn_n;
+ }
+ else
+ p->kn_p->kn_n=p->kn_n;
+
+ if(p->kn_n!=NIL)
+ p->kn_n->kn_p=p->kn_p;
+
+ t->cnt--;
+ tcfs_keytab_dispnode(p);
+
+ return TCFS_OK;
+}
+
+int tcfs_keytab_rm_pid(tcfs_keytab *t, uid_t uid, pid_t pid)
+{
+ int pos=0;
+ tcfs_keytab_node *p;
+
+ p=tcfs_keytab_fetch_pid(t,uid,pid);
+ if(p==NIL)
+ return EINVAL;
+
+ if(p->kn_p==NIL)
+ {
+ pos=tcfs_keytab_hash(pid);
+ t->node[pos]=p->kn_n;
+ }
+ else
+ p->kn_p->kn_n=p->kn_n;
+
+ if(p->kn_n!=NIL)
+ p->kn_n->kn_p=p->kn_p;
+
+ t->cnt--;
+ tcfs_keytab_dispnode(p);
+
+ return TCFS_OK;
+}
+
+int tcfs_keytab_rm_gid(tcfs_keytab *t, uid_t uid, gid_t gid)
+{
+ int pos=0,ret=0;
+ tcfs_keytab_node *p;
+
+ p=tcfs_keytab_fetch_gid(t,gid);
+ if(p==NIL)
+ return EINVAL;
+
+ ret=tcfs_keytab_rm_gidpart(p,uid,gid);
+
+ if (ret)
+ return ret;
+
+ if(!IS_CLEAN_GD(p->kn_data))
+ return TCFS_OK;
+
+ if(p->kn_p==NIL)
+ {
+ pos=tcfs_keytab_hash(gid);
+ t->node[pos]=p->kn_n;
+ }
+ else
+ p->kn_p->kn_n=p->kn_n;
+
+ if(p->kn_n!=NIL)
+ p->kn_n->kn_p=p->kn_p;
+
+ t->cnt--;
+ tcfs_keytab_dispnode(p);
+
+ return TCFS_OK;
+}
+
diff --git a/sys/miscfs/tcfs/tcfs_keytab.h b/sys/miscfs/tcfs/tcfs_keytab.h
new file mode 100644
index 00000000000..6da7ce49e82
--- /dev/null
+++ b/sys/miscfs/tcfs/tcfs_keytab.h
@@ -0,0 +1,97 @@
+#ifndef _SYS_TYPES_H_
+#include "sys/types.h"
+#endif
+#ifndef _TCFS_MOUNT_H_
+struct tcfs_mount;
+#endif
+
+#define _TCFS_KEYTAB_H_
+#define KEYTABSIZE 20
+#define KEYSIZE 8
+#define KEYPARTSIZE (KEYSIZE+KEYSIZE/8)
+
+#define CLEAN 0x00
+#define PID_BIT 0x01
+#define UID_KEY 0x02
+#define GID_KEY 0x04
+#define PID_KEY (PID_BIT|UID_KEY)
+
+#define IS_GID_NODE(np) (((np)->kn_type)&GID_KEY)
+#define IS_UID_NODE(np) (((np)->kn_type)&UID_KEY)
+#define IS_PID_NODE(np) ((((np)->kn_type)&PID_BIT)&&(IS_UID_NODE((np))))
+
+#ifndef TCFS_OK
+#define TCFS_OK 0
+#endif
+
+#define MAXUSRPERGRP 10
+
+typedef struct
+ {
+ unsigned char gui_flag;
+ uid_t gui_uid;
+ unsigned char gui_tcfskey[KEYPARTSIZE];
+ } tcfs_grp_uinfo;
+
+#define GUI_CLEAN 0
+#define GUI_SET 1
+#define IS_SET_GUI(gui) ((gui).gui_flag==GUI_SET)
+
+typedef struct _grp_data {
+ int gd_flag;
+ int gd_n;
+ int gd_k;
+ tcfs_grp_uinfo gd_part[MAXUSRPERGRP];
+ } tcfs_grp_data;
+
+#define IS_CLEAN_GD(gd) ((gd)->gd_n==0)
+#define IS_FULL_GD(gd) ((gd)->gd_n==MAXUSRPERGRP)
+#define IS_READY_GD(gd) (((gd)->gd_n)>=((gd)->gd_k))
+
+typedef struct _kn {
+ pid_t kn_pid;
+ uid_t kn_uid;
+ gid_t kn_gid;
+ unsigned int kn_type;
+
+ void *kn_key;
+ tcfs_grp_data *kn_data;
+
+ struct _kn *kn_n;
+ struct _kn *kn_p;
+} tcfs_keytab_node;
+
+typedef struct _kt {
+ unsigned int cnt;
+ tcfs_keytab_node* node[KEYTABSIZE];
+ } tcfs_keytab;
+
+#define NIL ((tcfs_keytab_node*)0)
+
+#ifdef _HAVE_HASH_
+int _tcfs_keytab_hash(unsigned int);
+#define tcfs_keytab_hash(x) _tcfs_keytab_hash((unsigned int)(x))
+#else
+#define tcfs_keytab_hash(u) ((u)%KEYTABSIZE)
+#endif
+
+tcfs_keytab_node *tcfs_keytab_newnode(void);
+tcfs_keytab_node *tcfs_keytab_newgidnode(void);
+void tcfs_keytab_dispnode(tcfs_keytab_node*);
+tcfs_keytab *tcfs_keytab_init(void);
+void tcfs_keytab_dispose(tcfs_keytab*);
+tcfs_keytab_node *tcfs_keytab_fetch_uid(tcfs_keytab *, uid_t);
+int tcfs_keytab_push_gidpart(struct tcfs_mount *,tcfs_keytab_node *,uid_t, gid_t,int,char*);
+tcfs_keytab_node *tcfs_keytab_fetch_gid(tcfs_keytab *, gid_t);
+tcfs_keytab_node *tcfs_keytab_fetch_pid(tcfs_keytab *, uid_t, pid_t);
+int tcfs_keytab_push_uid(tcfs_keytab*, uid_t, void* );
+int tcfs_keytab_push_pid(tcfs_keytab*, uid_t, pid_t, void* );
+int tcfs_keytab_push_gid(struct tcfs_mount *,tcfs_keytab*, uid_t, gid_t,int,char*);
+int tcfs_keytab_rm_uid(tcfs_keytab*, uid_t);
+int tcfs_keytab_rm_pid(tcfs_keytab*, uid_t, pid_t);
+int tcfs_keytab_rm_gidpart(tcfs_keytab_node *,uid_t, gid_t);
+int tcfs_keytab_rm_gid(tcfs_keytab*, uid_t, gid_t);
+int tcfs_interp(struct tcfs_mount *, tcfs_keytab_node*);
+int tcfs_keytab_check_uid(tcfs_keytab *, uid_t);
+int tcfs_keytab_check_pid(tcfs_keytab *, uid_t, pid_t);
+int tcfs_keytab_check_gid(tcfs_keytab *, gid_t);
diff --git a/sys/miscfs/tcfs/tcfs_mount.h b/sys/miscfs/tcfs/tcfs_mount.h
new file mode 100644
index 00000000000..59e863f3482
--- /dev/null
+++ b/sys/miscfs/tcfs/tcfs_mount.h
@@ -0,0 +1,39 @@
+#ifndef _TCFS_KEYTAB_H_
+#include "tcfs_keytab.h"
+#endif
+#define _TCFS_MOUNT_H_
+
+#ifndef _TCFS_VERSION_H_
+#include "tcfs_version.h"
+#endif
+
+#define MaxCipherNameLen 8
+struct tcfs_status {
+ int status;
+ int n_ukey;
+ int n_gkey;
+ int tcfs_version;
+ char cipher_desc[MaxCipherNameLen];
+ int cipher_keysize;
+ int cipher_version;
+ };
+struct tcfs_args {
+ char *target; /* Target of loopback */
+ char *tcfs_key; /* chiave */
+ int cipher_num;
+ int cmd; /* direttiva */
+ uid_t user; /* utente */
+ pid_t proc; /* processo */
+ gid_t group; /* gruppo */
+ int treshold; /* soglia grpkey */
+ struct tcfs_status st;
+};
+
+struct tcfs_mount {
+ struct mount *tcfsm_vfs;
+ struct vnode *tcfsm_rootvp; /* Reference to root tcfs_node */
+ void* ks;
+ tcfs_keytab *tcfs_uid_kt;
+ tcfs_keytab *tcfs_gid_kt;
+ int tcfs_cipher_num;
+};
diff --git a/sys/miscfs/tcfs/tcfs_rw.c b/sys/miscfs/tcfs/tcfs_rw.c
new file mode 100644
index 00000000000..7b11e12bc16
--- /dev/null
+++ b/sys/miscfs/tcfs/tcfs_rw.c
@@ -0,0 +1,616 @@
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#include <miscfs/tcfs/tcfs.h>
+#include "tcfs_rw.h"
+#include "tcfs_cipher.h"
+
+tcfs_opinfo tcfs_get_opinfo(void *a)
+{
+ struct vop_read_args *arg;
+ tcfs_opinfo r;
+ tcfs_fileinfo *i;
+ int iscr=0;
+
+
+ arg=(struct vop_read_args*)a;
+
+ r.i=tcfs_get_fileinfo(a);
+ i=&(r.i);
+
+ iscr=FI_CFLAG(i)||FI_GSHAR(i);
+
+ if(!iscr)
+ {
+ r.tcfs_op_desc=TCFS_NONE;
+ return r;
+ }
+
+
+ r.off=arg->a_uio->uio_offset;
+ r.req=arg->a_uio->uio_resid;
+
+ if(arg->a_uio->uio_rw==UIO_READ)
+ {
+ if(r.off<FI_ENDOF(i)-FI_SPURE(i))
+ {
+ r.tcfs_op_desc=TCFS_READ_C1;
+ r.out_boff=BOFF(&r);
+ r.out_foff=
+ (LAST(&r)>FI_ENDOF(i)-FI_SPURE(i)?FI_ENDOF(i):P_FOFF(&r));
+ r.in_boff=r.out_boff;
+ r.in_foff=r.out_foff;
+ return r;
+ }
+ else
+ {
+ r.tcfs_op_desc=TCFS_READ_C2;
+ r.out_boff=0;
+ r.out_foff=0;
+ return r;
+ }
+ }
+ if(arg->a_uio->uio_rw==UIO_WRITE)
+ {
+ if(arg->a_ioflag&IO_APPEND)
+ {
+ r.off=FI_ENDOF(i)-FI_SPURE(i);
+ arg->a_ioflag&=~(IO_APPEND);
+ }
+ if(LAST(&r)<FI_ENDOF(i)-FI_SPURE(i))
+ {
+ if (FI_ENDOF(i)-FI_SPURE(i)-LAST(&r)>BLOCKSIZE)
+ {
+ r.tcfs_op_desc=TCFS_WRITE_C1;
+ r.out_boff=BOFF(&r);
+ r.out_foff=FOFF(&r);
+ r.in_boff=r.out_boff;
+ r.in_foff=r.out_foff;
+ return r;
+ }
+ else
+ {
+ r.tcfs_op_desc=TCFS_WRITE_C2;
+ r.out_boff=BOFF(&r);
+ r.out_foff=FI_ENDOF(i)-1;
+ r.in_boff=r.out_boff;
+ r.in_foff=r.out_foff;
+ return r;
+ }
+ }
+ if(LAST(&r)>=FI_ENDOF(i)-FI_SPURE(i))
+ {
+ r.out_boff=BOFF(&r);
+ r.out_foff=P_FOFF(&r);
+ if (r.off<=FI_ENDOF(i)-FI_SPURE(i))
+ {
+ r.tcfs_op_desc=TCFS_WRITE_C3;
+ r.in_boff=r.out_boff;
+ r.in_foff=r.out_foff;
+ return r;
+ }
+ else
+ if(D_BOFF(FI_ENDOF(i))==D_BOFF(r.off))
+ {
+ r.tcfs_op_desc=TCFS_WRITE_C4;
+ r.in_boff=r.out_boff;
+ r.in_foff=r.out_foff;
+ return r;
+ }
+ else
+ {
+ r.tcfs_op_desc=TCFS_WRITE_C5;
+ r.in_boff=D_BOFF(FI_ENDOF(i));
+ r.in_foff=D_FOFF(FI_ENDOF(i));
+ r.out_boff=BOFF(&r);
+ r.out_foff=P_FOFF(&r);
+ return r;
+ }
+ }
+ }
+ return r;
+}
+
+char *tcfs_new_uio_obs(struct uio *old, struct uio **new, int off, int bufsize)
+{
+ char *buffer;
+ struct uio *u;
+ struct iovec *n;
+
+ u=malloc(sizeof(struct uio),M_FREE,M_NOWAIT);
+ if(!u)
+ return (char*)0;
+ n=malloc(sizeof(struct iovec),M_FREE,M_NOWAIT);
+ if(!n)
+ {
+ free(u,M_FREE);
+ return (char*)0;
+ }
+ buffer=malloc(bufsize,M_FREE,M_NOWAIT);
+ if(!buffer)
+ {
+ free(u,M_FREE);
+ free(n,M_FREE);
+ return (char*)0;
+ }
+
+
+ u->uio_offset=off;
+ u->uio_resid=bufsize;
+ u->uio_iovcnt=1;
+ u->uio_segflg=UIO_SYSSPACE;
+ u->uio_rw=old->uio_rw;
+ u->uio_procp=old->uio_procp;
+ u->uio_iov=n;
+ n->iov_base=buffer;
+ n->iov_len=bufsize;
+
+
+ *new=u;
+ return buffer;
+}
+
+char *tcfs_new_uio_i(struct uio *old, struct uio **new,tcfs_opinfo *r)
+{
+ int bufsize;
+ char *buffer=NULL;
+
+
+ switch(r->tcfs_op_desc)
+ {
+ case TCFS_READ_C2:
+ buffer=(char*)0;
+ return buffer;
+ default:
+ case TCFS_READ_C1:
+ case TCFS_WRITE_C1:
+ case TCFS_WRITE_C2:
+ case TCFS_WRITE_C3:
+ bufsize=r->in_foff-r->in_boff+1;
+ break;
+ }
+
+ return tcfs_new_uio_obs(old,new,r->in_boff,bufsize);
+}
+
+
+void tcfs_dispose_new_uio(struct uio *vec)
+{
+ void *p,*q;
+ p=(void*)vec;
+ q=(void*)vec->uio_iov;
+
+ free(p,M_FREE);
+ free(q,M_FREE);
+}
+
+int
+tcfs_read(v)
+ void *v;
+{
+ char *buffer, /* buffer per la read interna */
+ *buffp, /* puntatore all'inizio dei dati utili */
+ *buffpf; /* puntatore alla fine dei dati utili */
+
+ int bufsize=0; /* taglia del buffer allocato */
+
+ struct uio
+ *new, /* puntatore all'uio rifatto */
+ *old; /* puntatore all'uio originale */
+
+ int terr, /* val. ritorno read interna */
+ chdap, /* caratteri da passare */
+ chread, /* caratteri letti dalla read int. */
+ r_off, /* offset raggiunto */
+ e_spure; /* spure effettivamente letti */
+
+ struct vop_read_args *arg;
+ tcfs_opinfo f;
+ tcfs_fileinfo *i;
+
+ struct ucred *ucred;
+ struct proc *procp;
+
+ struct tcfs_mount *mp;
+ void *ks;
+
+
+ f=tcfs_get_opinfo(v);
+
+ if(f.tcfs_op_desc==TCFS_NONE)
+ return tcfs_bypass(v);
+
+ i=&(f.i);
+
+ arg=(struct vop_read_args *)v;
+ mp=MOUNTTOTCFSMOUNT(arg->a_vp->v_mount);
+ ucred=arg->a_cred;
+ procp=arg->a_uio->uio_procp;
+
+ if(FI_GSHAR(i))
+ {
+ ks=tcfs_getgkey(ucred,procp,arg->a_vp);
+ if(!ks)
+ {
+ return EACCES;
+ }
+ }
+ else
+ {
+ ks=tcfs_getpkey(ucred,procp,arg->a_vp);
+ if (!ks)
+ ks=tcfs_getukey(ucred,procp,arg->a_vp);
+ if (!ks)
+ return EACCES;
+ }
+
+ old=arg->a_uio;
+ buffer=tcfs_new_uio_i(old,&new,&f);
+
+ if (buffer==(char*)0)
+ return 0;
+
+ arg->a_uio=new;
+ bufsize=f.out_foff-f.out_boff+1;
+
+ terr=tcfs_bypass(arg);
+ chread=bufsize-new->uio_resid;
+
+
+ mkdecrypt(mp,buffer,chread,ks);
+
+
+ r_off=f.out_boff+chread;
+
+ if(r_off>=FI_ENDOF(i))
+ e_spure=FI_SPURE(i);
+ else
+ if(r_off>FI_ENDOF(i)-FI_SPURE(i))
+ e_spure=FI_SPURE(i)-FI_ENDOF(i)+r_off;
+ else
+ e_spure=0;
+
+ buffp=buffer+ROFF(&f);
+ if (chread>ROFF(&f))
+ {
+ chdap=MIN(f.req,chread-ROFF(&f)-e_spure);
+ buffpf=buffp+chdap;
+
+ uiomove(buffp,chdap,old);
+ }
+ arg->a_uio=old;
+ tcfs_dispose_new_uio(new);
+ free(buffer,M_FREE);
+
+ return terr;
+}
+
+int
+tcfs_write(v)
+ void *v;
+{
+ char *buffer, /* buffer per la read interna */
+ *buffp, /* puntatore all'inizio dei dati utili */
+ *buffpf; /* puntatore alla fine dei dati utili */
+
+ struct uio
+ *tmp, /* uio per la dimensione di un blocco */
+ *old; /* puntatore all'uio originale della chiamata */
+
+
+ int bufsize, /* num. caratteri req. read interna */
+ terr, /* val. ritorno read interna */
+ chdap, /* caratteri da passare */
+ chread=0, /* caratteri letti dalla read int. */
+ chwrote,e_chwrote,
+ spure=0; /* ho scritto fino a qui */
+
+ tcfs_opinfo f;
+ tcfs_fileinfo *i;
+
+ struct vop_read_args *arg;
+ struct ucred *ucred;
+ struct proc *procp;
+ void *ks;
+ struct tcfs_mount *mp;
+
+ int e;
+
+
+ arg=(struct vop_read_args *)v;
+ ucred=arg->a_cred;
+ procp=arg->a_uio->uio_procp;
+ mp=MOUNTTOTCFSMOUNT(arg->a_vp->v_mount);
+
+
+ f=tcfs_get_opinfo(arg);
+
+ if (f.tcfs_op_desc==TCFS_NONE)
+ return tcfs_bypass(v);
+
+ i=&(f.i);
+
+ if(FI_GSHAR(i))
+ {
+ ks=tcfs_getgkey(ucred,procp,arg->a_vp);
+ if(!ks)
+ return EACCES;
+ }
+ else
+ {
+ ks=tcfs_getpkey(ucred,procp,arg->a_vp);
+ if (!ks)
+ ks=tcfs_getukey(ucred,procp,arg->a_vp);
+ if (!ks)
+ return EACCES;
+ }
+
+ old=arg->a_uio;
+
+ buffer=(char*)tcfs_new_uio_i(old,&tmp,&f);
+ if (buffer==(char*)0)
+ return EFAULT;
+
+ arg->a_uio=tmp;
+ arg->a_desc=VDESC(vop_read);
+ arg->a_uio->uio_rw=UIO_READ;
+
+ bufsize=f.in_foff-f.in_boff+1;
+
+
+
+ terr=tcfs_bypass(arg);
+
+ switch(f.tcfs_op_desc)
+ {
+ case TCFS_WRITE_C1:
+ case TCFS_WRITE_C2:
+ if(tmp->uio_resid!=0)
+ goto ret;
+
+ chread=bufsize;
+ break;
+
+ case TCFS_WRITE_C3:
+ case TCFS_WRITE_C4:
+ if(tmp->uio_resid!=(P_FOFF(&f)-FI_ENDOF(i)+1))
+ goto ret;
+
+ chread=bufsize;
+ break;
+
+ case TCFS_WRITE_C5:
+ if(tmp->uio_resid!=(D_FOFF(FI_ENDOF(i))-FI_ENDOF(i)+1))
+ goto ret;
+ chread=bufsize;
+ }
+
+ mkdecrypt(mp,buffer,chread,ks);
+
+
+ if(f.tcfs_op_desc==TCFS_WRITE_C4)
+ {
+
+ for(e=FI_ENDOF(i)-FI_SPURE(i);e<f.off;e++)
+ *(buffer+e-f.out_boff)='\0';
+
+ }
+
+
+ if(f.tcfs_op_desc!=TCFS_WRITE_C5)
+ {
+
+ buffp=buffer+ROFF(&f);
+ chdap=f.req;
+ buffpf=buffp+chdap;
+
+ uiomove(buffp,chdap,old);
+
+ } /*if not TCFS_WRITE_C5 */
+ else
+ {
+ for(e=FI_ENDOF(i)-FI_SPURE(i)-f.in_boff;e<bufsize;e++)
+ *(buffer+e)='\0';
+ }
+
+ mkencrypt(mp,buffer,bufsize,ks);
+
+ arg->a_desc=VDESC(vop_write);
+ arg->a_uio->uio_rw=UIO_WRITE;
+ arg->a_uio->uio_resid=bufsize;
+ arg->a_uio->uio_offset=f.in_boff;
+ arg->a_uio->uio_iov->iov_base=buffer;
+ arg->a_uio->uio_iov->iov_len=bufsize;
+ terr=tcfs_bypass(arg);
+
+ if (f.tcfs_op_desc==TCFS_WRITE_C5)
+ {
+
+ tcfs_dispose_new_uio(tmp);
+ free(buffer,M_FREE);
+
+ bufsize=f.out_foff-f.out_boff+1;
+ buffer=tcfs_new_uio_obs(old,&tmp,f.out_boff,bufsize);
+ arg->a_uio=tmp;
+ arg->a_desc=VDESC(vop_write);
+ arg->a_uio->uio_rw=UIO_WRITE;
+
+ for(e=0;e<ROFF(&f);e++)
+ *(buffer+e)='\0';
+
+ buffp=buffer+ROFF(&f);
+ chdap=f.req;
+ buffpf=buffp+chdap;
+
+ uiomove(buffp,chdap,old);
+ mkencrypt(mp,buffer,bufsize,ks);
+ terr=tcfs_bypass(arg);
+
+ }
+
+ chwrote=bufsize-tmp->uio_resid;
+ e_chwrote=MIN(f.req,chwrote-ROFF(&f));
+
+ switch(f.tcfs_op_desc)
+ {
+ case TCFS_WRITE_C1:
+ case TCFS_WRITE_C2:
+ break;
+ case TCFS_WRITE_C3:
+ if ((f.in_boff+chwrote)>FI_ENDOF(i)-FI_SPURE(i))
+ {
+
+
+ if(chwrote>f.req){
+ spure=D_SPURE(f.off+f.req);
+ } else
+ {
+ spure=D_SPURE(f.out_boff+chwrote);
+ }
+
+ FI_SET_SP(i,spure);
+ tcfs_set_fileinfo(v,i);
+ }
+ break;
+ case TCFS_WRITE_C4:
+ case TCFS_WRITE_C5:
+ spure=D_SPURE(f.off+f.req);
+ FI_SET_SP(i,spure);
+ tcfs_set_fileinfo(v,i);
+ break;
+
+ }
+
+
+ old->uio_resid=f.req-e_chwrote;
+
+ret:
+ arg->a_uio=old;
+ tcfs_dispose_new_uio(tmp);
+ free(buffer,M_FREE);
+ return terr;
+}
+
+int tcfs_ed(struct vnode *v,struct proc *p,struct ucred *c, tcfs_fileinfo *i)
+{
+ struct vop_read_args ra;
+ struct vop_write_args wa;
+ struct uio *u;
+ struct iovec *n;
+ char *buff;
+ unsigned long csize,resid,w_resid;
+ unsigned long size,w_size;
+ int bufsize,e;
+ int retval,sp;
+ void *ks;
+ int encr=0;
+ struct tcfs_mount *mp;
+
+ mp=MOUNTTOTCFSMOUNT(v->v_mount);
+ encr=FI_CFLAG(i)||FI_GSHAR(i);
+
+
+ if(v->v_type!=VREG)
+ return 0;
+
+ if(FI_GSHAR(i))
+ {
+ ks=tcfs_getgkey(c,p,v);
+ if(!ks)
+ return EACCES;
+ }
+ else
+ {
+
+ ks=tcfs_getpkey(c,p,v);
+ if (!ks)
+ ks=tcfs_getukey(c,p,v);
+ if (!ks)
+ {
+ return EACCES;
+ }
+
+ }
+
+ u=malloc(sizeof(struct uio),M_FREE,M_NOWAIT);
+ n=malloc(sizeof(struct iovec),M_FREE,M_NOWAIT);
+
+
+ size=FI_ENDOF(i);
+
+ if(encr)
+ {
+ w_size=D_PFOFF(size);
+ sp=D_SPURE(size);
+ }
+ else
+ {
+ w_size=size-FI_SPURE(i);
+ sp=-FI_SPURE(i);
+ }
+
+ csize=0;
+ resid=size;
+ w_resid=w_size;
+
+ bufsize=BLOCKSIZE;
+
+ buff=malloc(BLOCKSIZE,M_FREE,M_NOWAIT);
+
+ u->uio_offset=0;
+ u->uio_resid=bufsize;
+ u->uio_iovcnt=1;
+ u->uio_segflg=UIO_SYSSPACE;
+ u->uio_procp=p;
+ u->uio_iov=n;
+
+ wa.a_desc=VDESC(vop_write);
+ ra.a_desc=VDESC(vop_read);
+ wa.a_vp=ra.a_vp=v;
+ wa.a_cred=ra.a_cred=c;
+ wa.a_ioflag=ra.a_ioflag=0;
+ wa.a_uio=ra.a_uio=u;
+
+
+ for(e=0;e<=D_NOBLK(size);e++)
+ {
+
+ int x,y;
+
+ u->uio_offset=csize;
+ u->uio_rw=UIO_READ;
+ n->iov_base=buff;
+ n->iov_len=u->uio_resid=x=MIN(bufsize,resid+1);
+
+ retval=tcfs_bypass((void*)&ra);
+
+
+ u->uio_offset=csize;
+ u->uio_rw=UIO_WRITE;
+ n->iov_base=buff;
+ n->iov_len=u->uio_resid=y=MIN(bufsize,w_resid+1);
+
+ if(!encr)
+ mkdecrypt(mp,buff,x,ks);
+ else
+ mkencrypt(mp,buff,y,ks);
+
+ retval=tcfs_bypass((void*)&wa);
+
+ resid-=x; csize+=x;
+ w_resid-=y;
+
+ /* I should call the scheduler here */
+ }
+
+ tcfs_dispose_new_uio(u);
+ return sp;
+}
+
diff --git a/sys/miscfs/tcfs/tcfs_rw.h b/sys/miscfs/tcfs/tcfs_rw.h
new file mode 100644
index 00000000000..a8e2db60891
--- /dev/null
+++ b/sys/miscfs/tcfs/tcfs_rw.h
@@ -0,0 +1,52 @@
+/* Gestione informazioni sui files cifrati
+*/
+#include <miscfs/tcfs/tcfs_fileinfo.h>
+
+typedef struct {
+ tcfs_fileinfo i;
+ int off;
+ int req;
+ int tcfs_op_desc;
+ int in_boff;
+ int in_foff;
+ int out_boff;
+ int out_foff;
+ } tcfs_opinfo;
+
+
+
+/* tcfs_opinfo x */
+
+#define ROFF(x) ((x)->off%BLOCKSIZE)
+#define LAST(x) ((x)->off+(x)->req-1)
+#define BOFF(x) (((x)->off/BLOCKSIZE)*BLOCKSIZE)
+#define FOFF(x) (LAST((x))+BLOCKSIZE-(LAST((x))%BLOCKSIZE+1))
+#define P_BOFF(x) (((x)->off/SBLOCKSIZE)*SBLOCKSIZE)
+#define P_FOFF(x) (LAST((x))+SBLOCKSIZE-(LAST((x))%SBLOCKSIZE+1))
+#define SPURE(x) ((x)->req%SBLOCKSIZE?(SBLOCKSIZE-(x)->req%SBLOCKSIZE):0)
+
+/* int o */
+#define D_BOFF(o) (((o)/BLOCKSIZE)*BLOCKSIZE)
+#define D_FOFF(o) ((o)+BLOCKSIZE-((o)%BLOCKSIZE+1))
+#define D_PFOFF(o) ((o)+SBLOCKSIZE-((o)%SBLOCKSIZE+1))
+#define D_SPURE(o) ((o)%SBLOCKSIZE?(SBLOCKSIZE-(o)%SBLOCKSIZE):0)
+#define D_NOBLK(o) ((o)/BLOCKSIZE+(o%BLOCKSIZE?1:0))
+
+#define TCFS_NONE 0
+#define TCFS_READ_C1 1
+#define TCFS_READ_C2 2
+#define TCFS_WRITE_C1 3
+#define TCFS_WRITE_C2 4
+#define TCFS_WRITE_C3 5
+#define TCFS_WRITE_C4 6
+#define TCFS_WRITE_C5 7
+
+/* prototyphes */
+
+char *tcfs_new_uio_i(struct uio*,struct uio**,tcfs_opinfo*);
+char *tcfs_new_uio_obs(struct uio*,struct uio**,int off, int ireq);
+void tcfs_dispose_new_uio(struct uio *);
+void dispose_new_uio(struct uio *);
+int tcfs_ed(struct vnode*, struct proc*, struct ucred *, tcfs_fileinfo *);
+tcfs_opinfo tcfs_get_opinfo(void*);
+
diff --git a/sys/miscfs/tcfs/tcfs_subr.c b/sys/miscfs/tcfs/tcfs_subr.c
new file mode 100644
index 00000000000..9d329efee94
--- /dev/null
+++ b/sys/miscfs/tcfs/tcfs_subr.c
@@ -0,0 +1,355 @@
+/* $OpenBSD: tcfs_subr.c,v 1.1 2000/06/17 17:16:07 provos Exp $ */
+/* $NetBSD: tcfs_subr.c,v 1.6 1996/05/10 22:50:52 jtk Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Id: lofs_subr.c,v 1.11 1992/05/30 10:05:43 jsp Exp
+ * @(#)tcfs_subr.c 8.4 (Berkeley) 1/21/94
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/malloc.h>
+#include <miscfs/specfs/specdev.h>
+#include <miscfs/tcfs/tcfs.h>
+
+#define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */
+#define NTCFSNODECACHE 16
+
+/*
+ * Null layer cache:
+ * Each cache entry holds a reference to the lower vnode
+ * along with a pointer to the alias vnode. When an
+ * entry is added the lower vnode is VREF'd. When the
+ * alias is removed the lower vnode is vrele'd.
+ */
+
+#define TCFS_NHASH(vp) \
+ (&tcfs_node_hashtbl[(((u_long)vp)>>LOG2_SIZEVNODE) & tcfs_node_hash])
+LIST_HEAD(tcfs_node_hashhead, tcfs_node) *tcfs_node_hashtbl;
+u_long tcfs_node_hash;
+
+static struct vnode *
+ tcfs_node_find __P((struct mount *, struct vnode *));
+static int
+ tcfs_node_alloc __P((struct mount *, struct vnode *, struct vnode **));
+/*
+ * Initialise cache headers
+ */
+/*ARGSUSED*/
+int
+tcfs_init(vfsp)
+ struct vfsconf *vfsp;
+{
+
+#ifdef TCFS_DIAGNOSTIC
+ printf("tcfs_init\n"); /* printed during system boot */
+#endif
+ tcfs_node_hashtbl = hashinit(NTCFSNODECACHE, M_CACHE, M_WAITOK, &tcfs_node_hash);
+ return (0);
+}
+
+/*
+ * Return a VREF'ed alias for lower vnode if already exists, else 0.
+ */
+static struct vnode *
+tcfs_node_find(mp, lowervp)
+ struct mount *mp;
+ struct vnode *lowervp;
+{
+ struct tcfs_node_hashhead *hd;
+ struct tcfs_node *a;
+ struct vnode *vp;
+ struct proc *p = curproc;
+
+ /*
+ * Find hash base, and then search the (two-way) linked
+ * list looking for a tcfs_node structure which is referencing
+ * the lower vnode. If found, the increment the tcfs_node
+ * reference count (but NOT the lower vnode's VREF counter).
+ */
+ hd = TCFS_NHASH(lowervp);
+loop:
+ for (a = hd->lh_first; a != 0; a = a->tcfs_hash.le_next) {
+ if (a->tcfs_lowervp == lowervp && TCFSTOV(a)->v_mount == mp) {
+ vp = TCFSTOV(a);
+ /*
+ * We need vget for the VXLOCK
+ * stuff, but we don't want to lock
+ * the lower node.
+ */
+ if (vget(vp, 0, p)) {
+ printf ("tcfs_node_find: vget failed.\n");
+ goto loop;
+ };
+ return (vp);
+ }
+ }
+
+ return NULLVP;
+}
+
+
+/*
+ * Make a new tcfs_node node.
+ * Vp is the alias vnode, lowervp is the lower vnode.
+ * Maintain a reference to lowervp.
+ */
+static int
+tcfs_node_alloc(mp, lowervp, vpp)
+ struct mount *mp;
+ struct vnode *lowervp;
+ struct vnode **vpp;
+{
+ struct tcfs_node_hashhead *hd;
+ struct tcfs_node *xp;
+ struct vnode *vp, *nvp;
+ int error;
+ extern int (**dead_vnodeop_p) __P((void *));
+ struct proc *p = curproc;
+
+
+ MALLOC(xp, struct tcfs_node *, sizeof(struct tcfs_node), M_TEMP,
+ M_WAITOK);
+
+ if ((error = getnewvnode(VT_TCFS, mp, tcfs_vnodeop_p, vpp)) != 0) {
+ FREE (xp, M_TEMP);
+ return (error);
+ }
+
+ vp = *vpp;
+ vp->v_type = lowervp->v_type;
+
+ if (vp->v_type == VBLK || vp->v_type == VCHR) {
+ MALLOC(vp->v_specinfo, struct specinfo *,
+ sizeof(struct specinfo), M_VNODE, M_WAITOK);
+ vp->v_rdev = lowervp->v_rdev;
+ }
+
+ vp->v_data = xp;
+ xp->tcfs_vnode = vp;
+ xp->tcfs_lowervp = lowervp;
+ /*
+ * Before we insert our new node onto the hash chains,
+ * check to see if someone else has beaten us to it.
+ * (We could have slept in MALLOC.)
+ */
+ if ((nvp = tcfs_node_find(mp, lowervp)) != NULL) {
+ *vpp = nvp;
+
+ /* free the substructures we've allocated. */
+ FREE(xp, M_TEMP);
+ if (vp->v_type == VBLK || vp->v_type == VCHR)
+ FREE(vp->v_specinfo, M_VNODE);
+
+ vp->v_type = VBAD; /* node is discarded */
+ vp->v_op = dead_vnodeop_p; /* so ops will still work */
+ vrele(vp); /* get rid of it. */
+ return (0);
+ }
+
+ /*
+ * XXX if it's a device node, it needs to be checkalias()ed.
+ * however, for locking reasons, that's just not possible.
+ * so we have to do most of the dirty work inline. Note that
+ * this is a limited case; we know that there's going to be
+ * an alias, and we know that that alias will be a "real"
+ * device node, i.e. not tagged VT_NON.
+ */
+ if (vp->v_type == VBLK || vp->v_type == VCHR) {
+ struct vnode *cvp, **cvpp;
+
+ cvpp = &speclisth[SPECHASH(vp->v_rdev)];
+loop:
+ for (cvp = *cvpp; cvp; cvp = cvp->v_specnext) {
+ if (vp->v_rdev != cvp->v_rdev ||
+ vp->v_type != cvp->v_type)
+ continue;
+
+ /*
+ * Alias, but not in use, so flush it out.
+ */
+ if (cvp->v_usecount == 0) {
+ vgone(cvp);
+ goto loop;
+ }
+ if (vget(cvp, 0, p)) /* can't lock; will die! */
+ goto loop;
+ break;
+ }
+
+ vp->v_hashchain = cvpp;
+ vp->v_specnext = *cvpp;
+ vp->v_specmountpoint = NULL;
+ *cvpp = vp;
+#ifdef DIAGNOSTIC
+ if (cvp == NULLVP)
+ panic("tcfs_node_alloc: no alias for device");
+#endif
+ vp->v_flag |= VALIASED;
+ cvp->v_flag |= VALIASED;
+ vrele(cvp);
+ }
+ /* XXX end of transmogrified checkalias() */
+
+ VREF(lowervp); /* Extra VREF will be vrele'd in tcfs_node_create */
+ hd = TCFS_NHASH(lowervp);
+ LIST_INSERT_HEAD(hd, xp, tcfs_hash);
+ return (0);
+}
+
+
+/*
+ * Try to find an existing tcfs_node vnode refering
+ * to it, otherwise make a new tcfs_node vnode which
+ * contains a reference to the lower vnode.
+ *
+ * >>> we assume that the lower node is already locked upon entry, so we mark
+ * the upper node as locked too (if caller requests it). <<<
+ */
+int
+tcfs_node_create(mp, lowervp, newvpp, takelock)
+ struct mount *mp;
+ struct vnode *lowervp;
+ struct vnode **newvpp;
+ int takelock;
+{
+ struct vnode *aliasvp;
+
+ if ((aliasvp = tcfs_node_find(mp, lowervp)) != NULL) {
+ /*
+ * tcfs_node_find has taken another reference
+ * to the alias vnode.
+ */
+#ifdef TCFS_DIAGNOSTIC
+ vprint("tcfs_node_create: exists", aliasvp);
+#endif
+ /* VREF(aliasvp); --- done in tcfs_node_find */
+ } else {
+ int error;
+
+ /*
+ * Get new vnode.
+ */
+#ifdef TCFS_DIAGNOSTIC
+ printf("tcfs_node_create: create new alias vnode\n");
+#endif
+
+ /*
+ * Make new vnode reference the tcfs_node.
+ */
+ if ((error = tcfs_node_alloc(mp, lowervp, &aliasvp)) != 0)
+ return error;
+
+ /*
+ * aliasvp is already VREF'd by getnewvnode()
+ */
+ }
+
+ vrele(lowervp);
+
+#ifdef DIAGNOSTIC
+ if (lowervp->v_usecount < 1) {
+ /* Should never happen... */
+ vprint("tcfs_node_create: alias", aliasvp);
+ panic("tcfs_node_create: lower has 0 usecount.");
+ };
+#endif
+
+#ifdef TCFS_DIAGNOSTIC
+ vprint("tcfs_node_create: alias", aliasvp);
+#endif
+
+ *newvpp = aliasvp;
+ return (0);
+}
+
+#ifdef TCFS_DIAGNOSTIC
+int tcfs_checkvp_barrier = 1;
+struct vnode *
+tcfs_checkvp(vp, fil, lno)
+ struct vnode *vp;
+ char *fil;
+ int lno;
+{
+ struct tcfs_node *a = VTOTCFS(vp);
+#ifdef notyet
+ /*
+ * Can't do this check because vop_reclaim runs
+ * with a funny vop vector.
+ */
+ if (vp->v_op != tcfs_vnodeop_p) {
+ printf ("tcfs_checkvp: on non-tcfs-node\n");
+ while (tcfs_checkvp_barrier) /*WAIT*/ ;
+ panic("tcfs_checkvp");
+ };
+#endif
+ if (a->tcfs_lowervp == TCFS) {
+ /* Should never happen */
+ int i; u_long *p;
+ printf("vp = %p, ZERO ptr\n", vp);
+ for (p = (u_long *) a, i = 0; i < 8; i++)
+ printf(" %lx", p[i]);
+ printf("\n");
+ /* wait for debugger */
+ while (tcfs_checkvp_barrier) /*WAIT*/ ;
+ panic("tcfs_checkvp");
+ }
+ if (a->tcfs_lowervp->v_usecount < 1) {
+ int i; u_long *p;
+ printf("vp = %p, unref'ed lowervp\n", vp);
+ for (p = (u_long *) a, i = 0; i < 8; i++)
+ printf(" %lx", p[i]);
+ printf("\n");
+ /* wait for debugger */
+ while (tcfs_checkvp_barrier) /*WAIT*/ ;
+ panic ("tcfs with unref'ed lowervp");
+ };
+#ifdef notyet
+ printf("tcfs %p/%d -> %p/%d [%s, %d]\n",
+ TCFSTOV(a), TCFSTOV(a)->v_usecount,
+ a->tcfs_lowervp, a->tcfs_lowervp->v_usecount,
+ fil, lno);
+#endif
+ return a->tcfs_lowervp;
+}
+#endif
diff --git a/sys/miscfs/tcfs/tcfs_version.h b/sys/miscfs/tcfs/tcfs_version.h
new file mode 100644
index 00000000000..fb88b344dcd
--- /dev/null
+++ b/sys/miscfs/tcfs/tcfs_version.h
@@ -0,0 +1,3 @@
+#define _TCFS_VERSION_H_
+#define TCFS_VERSION_NUM 0
+
diff --git a/sys/miscfs/tcfs/tcfs_vfsops.c b/sys/miscfs/tcfs/tcfs_vfsops.c
new file mode 100644
index 00000000000..df84c99db55
--- /dev/null
+++ b/sys/miscfs/tcfs/tcfs_vfsops.c
@@ -0,0 +1,329 @@
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/malloc.h>
+#include <miscfs/tcfs/tcfs.h>
+
+int tcfs_mount __P((struct mount *, const char *, caddr_t,
+ struct nameidata *, struct proc *));
+int tcfs_start __P((struct mount *, int, struct proc *));
+int tcfs_unmount __P((struct mount *, int, struct proc *));
+int tcfs_root __P((struct mount *, struct vnode **));
+int tcfs_quotactl __P((struct mount *, int, uid_t, caddr_t,
+ struct proc *));
+int tcfs_statfs __P((struct mount *, struct statfs *, struct proc *));
+int tcfs_sync __P((struct mount *, int, struct ucred *, struct proc *));
+int tcfs_vget __P((struct mount *, ino_t, struct vnode **));
+
+/*
+ * Mount tcfs layer
+ */
+int
+tcfs_mount(mp, path, data, ndp, p)
+ struct mount *mp;
+ const char *path;
+ caddr_t data;
+ struct nameidata *ndp;
+ struct proc *p;
+{
+ int error = 0;
+ struct tcfs_args args;
+ struct vnode *lowerrootvp, *vp;
+ struct vnode *tcfsm_rootvp;
+ struct tcfs_mount *xmp;
+ size_t size;
+ int tcfs_error=0;
+
+#ifdef TCFS_DIAGNOSTIC
+ printf("tcfs_mount(mp = %p)\n", mp);
+#endif
+
+ /*
+ * Get argument
+ */
+ error = copyin(data, (caddr_t)&args, sizeof(struct tcfs_args));
+ if (error)
+ return (error);
+
+ /* receiving user directives */
+ if (mp->mnt_flag & MNT_UPDATE) {
+ int i;
+ i=tcfs_exec_cmd(MOUNTTOTCFSMOUNT(mp),&args);
+ copyout((caddr_t)&args,data,sizeof(struct tcfs_args));
+ return i;
+ }
+
+ /*
+ * Find lower node
+ */
+ NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF,
+ UIO_USERSPACE, args.target, p);
+ if ((error = namei(ndp)) != 0)
+ return (error);
+
+ /*
+ * Sanity check on lower vnode
+ */
+ lowerrootvp = ndp->ni_vp;
+
+ vrele(ndp->ni_dvp);
+ ndp->ni_dvp = NULL;
+
+ if (lowerrootvp->v_type != VDIR) {
+ vput(lowerrootvp);
+ return (EINVAL);
+ }
+
+ xmp = (struct tcfs_mount *) malloc(sizeof(struct tcfs_mount),
+ M_UFSMNT, M_WAITOK); /* XXX */
+
+ /*
+ * Save reference to underlying FS
+ */
+ xmp->tcfsm_vfs = lowerrootvp->v_mount;
+
+ /*
+ * Save reference. Each mount also holds
+ * a reference on the root vnode.
+ */
+ error = tcfs_node_create(mp, lowerrootvp, &vp, 1);
+ /*
+ * Unlock the node (either the lower or the alias)
+ */
+ VOP_UNLOCK(vp, 0, p);
+ /*
+ * Make sure the node alias worked
+ */
+ if (error) {
+ vrele(lowerrootvp);
+ free(xmp, M_UFSMNT); /* XXX */
+ return (error);
+ }
+
+ /*
+ * Keep a held reference to the root vnode.
+ * It is vrele'd in tcfs_unmount.
+ */
+ tcfsm_rootvp = vp;
+ tcfsm_rootvp->v_flag |= VROOT;
+ xmp->tcfsm_rootvp = tcfsm_rootvp;
+ if (TCFSVPTOLOWERVP(tcfsm_rootvp)->v_mount->mnt_flag & MNT_LOCAL)
+ mp->mnt_flag |= MNT_LOCAL;
+ mp->mnt_data = (qaddr_t) xmp;
+ vfs_getnewfsid(mp);
+
+ (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
+ bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
+ (void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
+ &size);
+ bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
+#ifdef TCFS_DIAGNOSTIC
+ printf("tcfs_mount: lower %s, alias at %s\n",
+ mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
+#endif
+
+ tcfs_error=tcfs_init_mp(xmp,&args);
+ copyout((caddr_t)&args,data,sizeof(struct tcfs_args));
+ return (tcfs_error);
+
+}
+
+/*
+ * VFS start. Nothing needed here - the start routine
+ * on the underlying filesystem will have been called
+ * when that filesystem was mounted.
+ */
+int
+tcfs_start(mp, flags, p)
+ struct mount *mp;
+ int flags;
+ struct proc *p;
+{
+
+ return (0);
+ /* return VFS_START(MOUNTTOTCFSMOUNT(mp)->tcfsm_vfs, flags, p); */
+}
+
+/*
+ * Free reference to tcfs layer
+ */
+int
+tcfs_unmount(mp, mntflags, p)
+ struct mount *mp;
+ int mntflags;
+ struct proc *p;
+{
+ struct vnode *tcfsm_rootvp = MOUNTTOTCFSMOUNT(mp)->tcfsm_rootvp;
+ int error;
+ int flags = 0;
+
+#ifdef TCFS_DIAGNOSTIC
+ printf("tcfs_unmount(mp = %p)\n", mp);
+#endif
+
+ if (mntflags & MNT_FORCE) {
+ flags |= FORCECLOSE;
+ }
+
+ /*
+ * Clear out buffer cache. I don't think we
+ * ever get anything cached at this level at the
+ * moment, but who knows...
+ */
+#if 0
+ mntflushbuf(mp, 0);
+ if (mntinvalbuf(mp, 1))
+ return (EBUSY);
+#endif
+ if (tcfsm_rootvp->v_usecount > 1)
+ return (EBUSY);
+ if ((error = vflush(mp, tcfsm_rootvp, flags)) != 0)
+ return (error);
+
+#ifdef TCFS_DIAGNOSTIC
+ vprint("alias root of lower", tcfsm_rootvp);
+#endif
+ /*
+ * Release reference on underlying root vnode
+ */
+ vrele(tcfsm_rootvp);
+ /*
+ * And blow it away for future re-use
+ */
+ vgone(tcfsm_rootvp);
+ /*
+ * Finally, throw away the tcfs_mount structure
+ */
+
+ tcfs_keytab_dispose(MOUNTTOTCFSMOUNT(mp)->tcfs_uid_kt);
+ tcfs_keytab_dispose(MOUNTTOTCFSMOUNT(mp)->tcfs_gid_kt);
+
+
+ free(mp->mnt_data, M_UFSMNT); /* XXX */
+ mp->mnt_data = 0;
+ return 0;
+}
+
+int
+tcfs_root(mp, vpp)
+ struct mount *mp;
+ struct vnode **vpp;
+{
+ struct vnode *vp;
+ struct proc *p = curproc;
+
+#ifdef TCFS_DIAGNOSTIC
+ printf("tcfs_root(mp = %p, vp = %p->%p)\n", mp,
+ MOUNTTOTCFSMOUNT(mp)->tcfsm_rootvp,
+ TCFSVPTOLOWERVP(MOUNTTOTCFSMOUNT(mp)->tcfsm_rootvp)
+ );
+#endif
+
+ /*
+ * Return locked reference to root.
+ */
+ vp = MOUNTTOTCFSMOUNT(mp)->tcfsm_rootvp;
+ VREF(vp);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+ *vpp = vp;
+ return 0;
+}
+
+int
+tcfs_quotactl(mp, cmd, uid, arg, p)
+ struct mount *mp;
+ int cmd;
+ uid_t uid;
+ caddr_t arg;
+ struct proc *p;
+{
+
+ return VFS_QUOTACTL(MOUNTTOTCFSMOUNT(mp)->tcfsm_vfs, cmd, uid, arg, p);
+}
+
+int
+tcfs_statfs(mp, sbp, p)
+ struct mount *mp;
+ struct statfs *sbp;
+ struct proc *p;
+{
+ int error;
+ struct statfs mstat;
+
+#ifdef TCFS_DIAGNOSTIC
+ printf("tcfs_statfs(mp = %p, vp = %p->%p)\n", mp,
+ MOUNTTOTCFSMOUNT(mp)->tcfsm_rootvp,
+ TCFSVPTOLOWERVP(MOUNTTOTCFSMOUNT(mp)->tcfsm_rootvp)
+ );
+#endif
+
+ bzero(&mstat, sizeof(mstat));
+
+ error = VFS_STATFS(MOUNTTOTCFSMOUNT(mp)->tcfsm_vfs, &mstat, p);
+ if (error)
+ return (error);
+
+ /* now copy across the "interesting" information and fake the rest */
+ sbp->f_flags = mstat.f_flags;
+ sbp->f_bsize = mstat.f_bsize;
+ sbp->f_iosize = mstat.f_iosize;
+ sbp->f_blocks = mstat.f_blocks;
+ sbp->f_bfree = mstat.f_bfree;
+ sbp->f_bavail = mstat.f_bavail;
+ sbp->f_files = mstat.f_files;
+ sbp->f_ffree = mstat.f_ffree;
+ if (sbp != &mp->mnt_stat) {
+ bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
+ bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
+ bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
+ }
+ strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN);
+ return (0);
+}
+
+int
+tcfs_sync(mp, waitfor, cred, p)
+ struct mount *mp;
+ int waitfor;
+ struct ucred *cred;
+ struct proc *p;
+{
+
+ /*
+ * XXX - Assumes no data cached at tcfs layer.
+ */
+ return (0);
+}
+
+int
+tcfs_vget(mp, ino, vpp)
+ struct mount *mp;
+ ino_t ino;
+ struct vnode **vpp;
+{
+
+ return VFS_VGET(MOUNTTOTCFSMOUNT(mp)->tcfsm_vfs, ino, vpp);
+}
+
+#define tcfs_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \
+ size_t, struct proc *)))eopnotsupp)
+
+struct vfsops tcfs_vfsops = {
+ tcfs_mount,
+ tcfs_start,
+ tcfs_unmount,
+ tcfs_root,
+ tcfs_quotactl,
+ tcfs_statfs,
+ tcfs_sync,
+ tcfs_vget,
+ tcfs_fhtovp,
+ tcfs_vptofh,
+ tcfs_init,
+ tcfs_sysctl
+};
diff --git a/sys/miscfs/tcfs/tcfs_vnops.c b/sys/miscfs/tcfs/tcfs_vnops.c
new file mode 100644
index 00000000000..eb824b34ee5
--- /dev/null
+++ b/sys/miscfs/tcfs/tcfs_vnops.c
@@ -0,0 +1,435 @@
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#include <miscfs/tcfs/tcfs.h>
+
+
+int tcfs_bug_bypass = 0; /* for debugging: enables bypass printf'ing */
+
+int tcfs_bypass __P((void *));
+int tcfs_getattr __P((void *));
+int tcfs_setattr __P((void *));
+int tcfs_inactive __P((void *));
+int tcfs_reclaim __P((void *));
+int tcfs_print __P((void *));
+int tcfs_strategy __P((void *));
+int tcfs_bwrite __P((void *));
+int tcfs_lock __P((void *));
+int tcfs_unlock __P((void *));
+int tcfs_islocked __P((void *));
+int tcfs_read __P((void *));
+int tcfs_readdir __P((void *));
+int tcfs_write __P((void *));
+int tcfs_create __P((void *));
+int tcfs_mknod __P((void *));
+int tcfs_mkdir __P((void *));
+int tcfs_link __P((void *));
+int tcfs_symlink __P((void *));
+int tcfs_rename __P((void *));
+int tcfs_lookup __P((void *));
+
+int
+tcfs_bypass(v)
+ void *v;
+{
+ struct vop_generic_args /* {
+ struct vnodeop_desc *a_desc;
+ <other random data follows, presumably>
+ } */ *ap = v;
+ register struct vnode **this_vp_p;
+ int error;
+ struct vnode *old_vps[VDESC_MAX_VPS];
+ struct vnode **vps_p[VDESC_MAX_VPS];
+ struct vnode ***vppp;
+ struct vnodeop_desc *descp = ap->a_desc;
+ int reles, i;
+
+ if (tcfs_bug_bypass)
+ printf ("tcfs_bypass: %s\n", descp->vdesc_name);
+
+#ifdef SAFETY
+ /*
+ * We require at least one vp.
+ */
+ if (descp->vdesc_vp_offsets == TCFS ||
+ descp->vdesc_vp_offsets[0] == VDESC_NO_OFFSET)
+ panic ("tcfs_bypass: no vp's in map.");
+#endif
+
+ /*
+ * Map the vnodes going in.
+ * Later, we'll invoke the operation based on
+ * the first mapped vnode's operation vector.
+ */
+ reles = descp->vdesc_flags;
+ for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) {
+ if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET)
+ break; /* bail out at end of list */
+ vps_p[i] = this_vp_p =
+ VOPARG_OFFSETTO(struct vnode**,descp->vdesc_vp_offsets[i],ap);
+ /*
+ * We're not guaranteed that any but the first vnode
+ * are of our type. Check for and don't map any
+ * that aren't. (We must always map first vp or vclean fails.)
+ */
+ if (i && (*this_vp_p == NULLVP ||
+ (*this_vp_p)->v_op != tcfs_vnodeop_p)) {
+ old_vps[i] = NULLVP;
+ } else {
+ old_vps[i] = *this_vp_p;
+ *(vps_p[i]) = TCFSVPTOLOWERVP(*this_vp_p);
+ /*
+ * XXX - Several operations have the side effect
+ * of vrele'ing their vp's. We must account for
+ * that. (This should go away in the future.)
+ */
+ if (reles & 1)
+ VREF(*this_vp_p);
+ }
+
+ }
+
+ /*
+ * Call the operation on the lower layer
+ * with the modified argument structure.
+ */
+ error = VCALL(*(vps_p[0]), descp->vdesc_offset, ap);
+
+ /*
+ * Maintain the illusion of call-by-value
+ * by restoring vnodes in the argument structure
+ * to their original value.
+ */
+ reles = descp->vdesc_flags;
+ for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) {
+ if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET)
+ break; /* bail out at end of list */
+ if (old_vps[i] != NULLVP) {
+ *(vps_p[i]) = old_vps[i];
+ if (reles & 1) {
+ vrele(*(vps_p[i]));
+ }
+ }
+
+ /*
+ * Map the possible out-going vpp
+ * (Assumes that the lower layer always returns
+ * a VREF'ed vpp unless it gets an error.)
+ */
+ if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET &&
+ !(descp->vdesc_flags & VDESC_NOMAP_VPP) &&
+ !error) {
+ /*
+ * XXX - even though some ops have vpp returned vp's,
+ * several ops actually vrele this before returning.
+ * We must avoid these ops.
+ * (This should go away when these ops are regularized.)
+ */
+ if (descp->vdesc_flags & VDESC_VPP_WILLRELE)
+ goto out;
+ vppp = VOPARG_OFFSETTO(struct vnode***,
+ descp->vdesc_vpp_offset,ap);
+ /*
+ * This assumes that **vppp is a locked vnode (it is always
+ * so as of this writing, NetBSD-current 1995/02/16)
+ *
+ * (don't want to lock it if being called on behalf
+ * of lookup--it plays weird locking games depending
+ * on whether or not it's looking up ".", "..", etc.
+ */
+ error = tcfs_node_create(old_vps[0]->v_mount, **vppp, *vppp,
+ descp == &vop_lookup_desc ? 0 : 1);
+ }
+ }
+
+ out:
+ return (error);
+
+}
+
+
+/*
+ * We must handle open to be able to catch MNT_NODEV and friends.
+ */
+int
+tcfs_open(v)
+ void *v;
+{
+ struct vop_open_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+ enum vtype lower_type = VTOTCFS(vp)->tcfs_lowervp->v_type;
+
+
+ if (((lower_type == VBLK) || (lower_type == VCHR)) &&
+ (vp->v_mount->mnt_flag & MNT_NODEV))
+ return ENXIO;
+
+ return tcfs_bypass(ap);
+}
+
+int
+tcfs_inactive(v)
+ void *v;
+{
+ struct vop_inactive_args *ap = v;
+
+ /*
+ * Do nothing (and _don't_ bypass).
+ * Wait to vrele lowervp until reclaim,
+ * so that until then our tcfs_node is in the
+ * cache and reusable.
+ *
+ * NEEDSWORK: Someday, consider inactive'ing
+ * the lowervp and then trying to reactivate it
+ * with capabilities (v_id)
+ * like they do in the name lookup cache code.
+ * That's too much work for now.
+ */
+ VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
+
+ return (0);
+}
+
+int
+tcfs_reclaim(v)
+ void *v;
+{
+ struct vop_reclaim_args /* {
+ struct vnode *a_vp;
+ } */ *ap = v;
+ struct vnode *vp = ap->a_vp;
+ struct tcfs_node *xp = VTOTCFS(vp);
+ struct vnode *lowervp = xp->tcfs_lowervp;
+
+ /*
+ * Note: in vop_reclaim, vp->v_op == dead_vnodeop_p,
+ * so we can't call VOPs on ourself.
+ */
+ /* After this assignment, this node will not be re-used. */
+ xp->tcfs_lowervp = NULL;
+ LIST_REMOVE(xp, tcfs_hash);
+ FREE(vp->v_data, M_TEMP);
+ vp->v_data = NULL;
+ vrele (lowervp);
+ return (0);
+}
+
+
+int
+tcfs_print(v)
+ void *v;
+{
+ struct vop_print_args /* {
+ struct vnode *a_vp;
+ } */ *ap = v;
+ register struct vnode *vp = ap->a_vp;
+
+ printf ("\ttag VT_TCFS, vp=%p, lowervp=%p\n", vp, TCFSVPTOLOWERVP(vp));
+ vprint("tcfs lowervp", TCFSVPTOLOWERVP(vp));
+ return (0);
+}
+
+
+/*
+ * XXX - vop_strategy must be hand coded because it has no
+ * vnode in its arguments.
+ * This goes away with a merged VM/buffer cache.
+ */
+int
+tcfs_strategy(v)
+ void *v;
+{
+ struct vop_strategy_args /* {
+ struct buf *a_bp;
+ } */ *ap = v;
+ struct buf *bp = ap->a_bp;
+ int error;
+ struct vnode *savedvp;
+
+ savedvp = bp->b_vp;
+ bp->b_vp = TCFSVPTOLOWERVP(bp->b_vp);
+
+ error = VOP_STRATEGY(bp);
+
+ bp->b_vp = savedvp;
+
+ return (error);
+}
+
+
+/*
+ * XXX - like vop_strategy, vop_bwrite must be hand coded because it has no
+ * vnode in its arguments.
+ * This goes away with a merged VM/buffer cache.
+ */
+int
+tcfs_bwrite(v)
+ void *v;
+{
+ struct vop_bwrite_args /* {
+ struct buf *a_bp;
+ } */ *ap = v;
+ struct buf *bp = ap->a_bp;
+ int error;
+ struct vnode *savedvp;
+
+ savedvp = bp->b_vp;
+ bp->b_vp = TCFSVPTOLOWERVP(bp->b_vp);
+
+ error = VOP_BWRITE(bp);
+
+ bp->b_vp = savedvp;
+
+ return (error);
+}
+
+/*
+ * We need a separate tcfs lock routine, to avoid deadlocks at reclaim time.
+ * If a process holds the lower-vnode locked when it tries to reclaim
+ * the tcfs upper-vnode, _and_ tcfs_bypass is used as the locking operation,
+ * then a process can end up locking against itself.
+ * This has been observed when a tcfs mount is set up to "tunnel" beneath a
+ * union mount (that setup is useful if you still wish to be able to access
+ * the non-union version of either the above or below union layer)
+ */
+int
+tcfs_lock(v)
+ void *v;
+{
+ struct vop_lock_args *ap = v;
+
+#if 0
+ vop_generic_lock(ap);
+#endif
+ if ((ap->a_flags & LK_TYPE_MASK) == LK_DRAIN)
+ return (0);
+ ap->a_flags &= ~LK_INTERLOCK;
+
+ return (tcfs_bypass((struct vop_generic_args *)ap));
+}
+
+int
+tcfs_unlock(v)
+ void *v;
+{
+ struct vop_unlock_args *ap = v;
+#if 0
+ vop_generic_unlock(ap);
+#endif
+ ap->a_flags &= ~LK_INTERLOCK;
+
+ return (tcfs_bypass((struct vop_generic_args *)ap));
+}
+
+int
+tcfs_islocked(v)
+ void *v;
+{
+ /* XXX */
+ return (0);
+}
+
+int
+tcfs_lookup(v)
+ void *v;
+{
+ register struct vop_lookup_args /* {
+ struct vnodeop_desc *a_desc;
+ struct vnode *a_dvp;
+ struct vnode **a_vpp;
+ struct componentname *a_cnp;
+ } */ *ap = v;
+ register int error;
+ int flags = ap->a_cnp->cn_flags;
+ struct componentname *cnp = ap->a_cnp;
+#if 0
+ register struct vnode *dvp, *vp;
+ struct proc *p = cnp->cn_proc;
+ struct vop_unlock_args unlockargs;
+ struct vop_lock_args lockargs;
+#endif
+
+#ifdef TCFS_DIAGNOSTIC
+ printf("tcfs_lookup: dvp=%lx, name='%s'\n",
+ ap->a_dvp, cnp->cn_nameptr);
+#endif
+
+ if ((flags & ISLASTCN) && (ap->a_dvp->v_mount->mnt_flag & MNT_RDONLY) &&
+ (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
+ return (EROFS);
+ error = tcfs_bypass((struct vop_generic_args *)ap);
+ if (error == EJUSTRETURN && (flags & ISLASTCN) &&
+ (ap->a_dvp->v_mount->mnt_flag & MNT_RDONLY) &&
+ (cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME))
+ error = EROFS;
+
+#if 0
+ /*
+ * We must do the same locking and unlocking at this layer as
+ * is done in the layers below us. We could figure this out
+ * based on the error return and the LASTCN, LOCKPARENT, and
+ * LOCKLEAF flags. However, it is more expidient to just find
+ * out the state of the lower level vnodes and set ours to the
+ * same state.
+ */
+ dvp = ap->a_dvp;
+ vp = *ap->a_vpp;
+ if (dvp == vp)
+ return (error);
+ if (!VOP_ISLOCKED(dvp)) {
+ unlockargs.a_vp = dvp;
+ unlockargs.a_flags = 0;
+ unlockargs.a_p = p;
+ vop_generic_unlock(&unlockargs);
+ }
+ if (vp != TCFSVP && VOP_ISLOCKED(vp)) {
+ lockargs.a_vp = vp;
+ lockargs.a_flags = LK_SHARED;
+ lockargs.a_p = p;
+ vop_generic_lock(&lockargs);
+ }
+#endif
+ return (error);
+}
+
+/*
+ * Global vfs data structures
+ */
+int (**tcfs_vnodeop_p) __P((void *));
+struct vnodeopv_entry_desc tcfs_vnodeop_entries[] = {
+ { &vop_default_desc, tcfs_bypass },
+
+ { &vop_getattr_desc, tcfs_getattr },
+ { &vop_setattr_desc, tcfs_setattr },
+ { &vop_inactive_desc, tcfs_inactive },
+ { &vop_reclaim_desc, tcfs_reclaim },
+ { &vop_print_desc, tcfs_print },
+
+ { &vop_lock_desc, tcfs_lock },
+ { &vop_unlock_desc, tcfs_unlock },
+ { &vop_islocked_desc, tcfs_islocked },
+ { &vop_lookup_desc, tcfs_lookup }, /* special locking frob */
+
+ { &vop_strategy_desc, tcfs_strategy },
+ { &vop_bwrite_desc, tcfs_bwrite },
+ { &vop_read_desc, tcfs_read },
+ { &vop_readdir_desc, tcfs_readdir },
+ { &vop_write_desc, tcfs_write },
+ { &vop_create_desc, tcfs_create },
+ { &vop_mknod_desc, tcfs_mknod },
+ { &vop_mkdir_desc, tcfs_mkdir },
+ { &vop_link_desc, tcfs_link },
+ { &vop_rename_desc, tcfs_rename },
+ { &vop_symlink_desc, tcfs_symlink },
+ { (struct vnodeop_desc*)NULL, (int(*) __P((void *)))NULL }
+};
+struct vnodeopv_desc tcfs_vnodeop_opv_desc =
+ { &tcfs_vnodeop_p, tcfs_vnodeop_entries };
+
diff --git a/sys/sys/mount.h b/sys/sys/mount.h
index 261dea541d0..451817c8483 100644
--- a/sys/sys/mount.h
+++ b/sys/sys/mount.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: mount.h,v 1.36 2000/05/22 17:29:06 mickey Exp $ */
+/* $OpenBSD: mount.h,v 1.37 2000/06/17 17:16:04 provos Exp $ */
/* $NetBSD: mount.h,v 1.48 1996/02/18 11:55:47 fvdl Exp $ */
/*
@@ -317,6 +317,7 @@ struct ostatfs {
#define MOUNT_EXT2FS "ext2fs" /* Second Extended Filesystem */
#define MOUNT_NCPFS "ncpfs" /* NetWare Network File System */
#define MOUNT_XFS "xfs" /* xfs */
+#define MOUNT_TCFS "tcfs" /* tcfs */
/*
* Structure per mounted file system. Each mounted file system has an
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
index b5c2175d2fd..47ffb2e8af3 100644
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: vnode.h,v 1.24 2000/05/22 13:48:40 provos Exp $ */
+/* $OpenBSD: vnode.h,v 1.25 2000/06/17 17:16:05 provos Exp $ */
/* $NetBSD: vnode.h,v 1.38 1996/02/29 20:59:05 cgd Exp $ */
/*
@@ -68,7 +68,7 @@ enum vtype { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO, VBAD };
enum vtagtype {
VT_NON, VT_UFS, VT_NFS, VT_MFS, VT_MSDOSFS, VT_LFS, VT_LOFS, VT_FDESC,
VT_PORTAL, VT_NULL, VT_UMAP, VT_KERNFS, VT_PROCFS, VT_AFS, VT_ISOFS,
- VT_UNION, VT_ADOSFS, VT_EXT2FS, VT_NCPFS, VT_VFS, VT_XFS
+ VT_UNION, VT_ADOSFS, VT_EXT2FS, VT_NCPFS, VT_VFS, VT_XFS, VT_TCFS
};
/*