summaryrefslogtreecommitdiff
path: root/debian
diff options
context:
space:
mode:
authorJustus Winter <4winter@informatik.uni-hamburg.de>2016-02-13 15:13:22 +0100
committerJustus Winter <4winter@informatik.uni-hamburg.de>2016-02-13 15:13:22 +0100
commit3d96bd27970069a214e41b923ca2c1ce53648f4d (patch)
treeee3758d0f2a017b4a695b365419ccaa6cc917a95 /debian
parent88b13ab082c5a587efea28450bc0d1770822e2ee (diff)
drop old patch series
Diffstat (limited to 'debian')
-rw-r--r--debian/patches/gpg0001-trans-add-transparent-GnuPG-translator.patch2005
-rw-r--r--debian/patches/series1
2 files changed, 0 insertions, 2006 deletions
diff --git a/debian/patches/gpg0001-trans-add-transparent-GnuPG-translator.patch b/debian/patches/gpg0001-trans-add-transparent-GnuPG-translator.patch
deleted file mode 100644
index 4bb2d08a..00000000
--- a/debian/patches/gpg0001-trans-add-transparent-GnuPG-translator.patch
+++ /dev/null
@@ -1,2005 +0,0 @@
-From b6fb09056bb3fe2557c185a56755c1a83e3e1960 Mon Sep 17 00:00:00 2001
-From: Justus Winter <4winter@informatik.uni-hamburg.de>
-Date: Sat, 23 Jan 2016 00:14:56 +0100
-Subject: [PATCH hurd] trans: add transparent GnuPG translator
-
-* trans/Makefile: Add new files.
-* trans/chroot.c: New file.
-* trans/chroot.h: Likewise.
-* trans/gpg.c: Likewise.
-* utils/gpg-env.sh: Likewise.
----
- trans/Makefile | 8 +-
- trans/chroot.c | 876 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
- trans/chroot.h | 37 +++
- trans/gpg.c | 734 ++++++++++++++++++++++++++++++++++++++++++++++
- trans/identity.c | 127 ++++++++
- utils/Makefile | 6 +-
- utils/gpg-env.sh | 121 ++++++++
- 7 files changed, 1903 insertions(+), 6 deletions(-)
- create mode 100644 trans/chroot.c
- create mode 100644 trans/chroot.h
- create mode 100644 trans/gpg.c
- create mode 100644 trans/identity.c
- create mode 100755 utils/gpg-env.sh
-
-diff --git a/trans/Makefile b/trans/Makefile
-index 65b51d1..e3d89c2 100644
---- a/trans/Makefile
-+++ b/trans/Makefile
-@@ -21,10 +21,11 @@ makemode := servers
-
- targets = symlink firmlink ifsock magic null fifo new-fifo fwd crash \
- password hello hello-mt streamio fakeroot proxy-defpager remap \
-- mtab
-+ mtab gpg identity
- SRCS = ifsock.c symlink.c magic.c null.c fifo.c new-fifo.c fwd.c \
- crash.c firmlink.c password.c hello.c hello-mt.c streamio.c \
-- fakeroot.c proxy-defpager.c remap.c mtab.c
-+ fakeroot.c proxy-defpager.c remap.c mtab.c gpg.c chroot.c \
-+ identity.c
- OBJS = $(SRCS:.c=.o) fsysServer.o ifsockServer.o passwordServer.o \
- crashServer.o crash_replyUser.o msgServer.o \
- default_pagerServer.o default_pagerUser.o \
-@@ -65,7 +66,8 @@ proxy-defpager: default_pagerServer.o default_pagerUser.o
- streamio: device_replyServer.o
- symlink: fsysServer.o
-
--fakeroot: ../libnetfs/libnetfs.a
-+gpg identity: chroot.o
-+fakeroot gpg identity: ../libnetfs/libnetfs.a
- fifo new-fifo: ../libpipe/libpipe.a
- crash fifo firmlink hello hello-mt ifsock magic mtab new-fifo null password proxy-defpager remap streamio: ../libtrivfs/libtrivfs.a
- $(targets): ../libfshelp/libfshelp.a \
-diff --git a/trans/chroot.c b/trans/chroot.c
-new file mode 100644
-index 0000000..fc509b8
---- /dev/null
-+++ b/trans/chroot.c
-@@ -0,0 +1,876 @@
-+/* chroot.c -- support for writing chrooting translators
-+ Copyright (C) 2002, 2003, 2008, 2013, 2016 Free Software Foundation, Inc.
-+
-+ 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, or (at
-+ your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful, but
-+ WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-+
-+#include <argz.h>
-+#include <argp.h>
-+#include <dirent.h>
-+#include <error.h>
-+#include <hurd/netfs.h>
-+#include <stddef.h>
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <string.h>
-+#include <fcntl.h>
-+#include <sys/mman.h>
-+#include <sys/stat.h>
-+#include <pthread.h>
-+#include <hurd/ihash.h>
-+#include <hurd/paths.h>
-+#include <sys/types.h>
-+#include <sys/wait.h>
-+#include <unistd.h>
-+
-+#include <version.h>
-+
-+#include "chroot.h"
-+
-+#include "libnetfs/fs_S.h"
-+#include "libnetfs/io_S.h"
-+#include "libnetfs/fsys_S.h"
-+#include "libports/notify_S.h"
-+#include "libports/interrupt_S.h"
-+
-+pthread_mutex_t idport_ihash_lock = PTHREAD_MUTEX_INITIALIZER;
-+struct hurd_ihash idport_ihash
-+= HURD_IHASH_INITIALIZER (sizeof (struct node)
-+ + offsetof (struct netnode, idport_locp));
-+
-+/* Make a new virtual node. Always consumes the ports. If
-+ successful, NP will be locked. */
-+error_t
-+chroot_new_node (file_t file, mach_port_t idport, int locked,
-+ size_t size, struct node **np)
-+{
-+ error_t err;
-+ struct netnode *nn;
-+
-+ *np = netfs_make_node_alloc (sizeof *nn + size);
-+ if (*np == 0)
-+ {
-+ mach_port_deallocate (mach_task_self (), file);
-+ if (MACH_PORT_VALID (idport))
-+ mach_port_deallocate (mach_task_self (), idport);
-+ if (locked)
-+ pthread_mutex_unlock (&idport_ihash_lock);
-+ return ENOMEM;
-+ }
-+ nn = netfs_node_netnode (*np);
-+ nn->file = file;
-+ if (MACH_PORT_VALID (idport))
-+ nn->idport = idport;
-+ else
-+ {
-+ ino_t fileno;
-+ mach_port_t fsidport;
-+ assert (!locked);
-+ err = io_identity (file, &nn->idport, &fsidport, &fileno);
-+ if (err)
-+ {
-+ mach_port_deallocate (mach_task_self (), file);
-+ free (*np);
-+ return err;
-+ }
-+ }
-+
-+ if (!locked)
-+ pthread_mutex_lock (&idport_ihash_lock);
-+ err = hurd_ihash_add (&idport_ihash, nn->idport, *np);
-+ if (err)
-+ goto lose;
-+
-+ pthread_mutex_lock (&(*np)->lock);
-+ pthread_mutex_unlock (&idport_ihash_lock);
-+ return 0;
-+
-+ lose:
-+ pthread_mutex_unlock (&idport_ihash_lock);
-+ mach_port_deallocate (mach_task_self (), nn->idport);
-+ mach_port_deallocate (mach_task_self (), file);
-+ free (*np);
-+ *np = NULL;
-+ return err;
-+}
-+
-+/* Node NP has no more references; free all its associated storage. */
-+void
-+netfs_node_norefs (struct node *np)
-+{
-+ pthread_mutex_unlock (&np->lock);
-+ pthread_spin_unlock (&netfs_node_refcnt_lock);
-+
-+ pthread_mutex_lock (&idport_ihash_lock);
-+ hurd_ihash_locp_remove (&idport_ihash, netfs_node_netnode (np)->idport_locp);
-+ pthread_mutex_unlock (&idport_ihash_lock);
-+
-+ chroot_node_norefs (np);
-+ mach_port_deallocate (mach_task_self (), netfs_node_netnode (np)->file);
-+ mach_port_deallocate (mach_task_self (), netfs_node_netnode (np)->idport);
-+ free (np);
-+
-+ pthread_spin_lock (&netfs_node_refcnt_lock);
-+}
-+
-+/* This is the cleanup function we install in netfs_protid_class. If
-+ the associated nodes reference count would also drop to zero, and
-+ the node has no faked attributes, we destroy it as well. */
-+static void
-+chroot_netfs_release_protid (void *cookie)
-+{
-+ netfs_release_protid (cookie);
-+
-+ int cports = ports_count_class (netfs_control_class);
-+ int nports = ports_count_class (netfs_protid_class);
-+ ports_enable_class (netfs_control_class);
-+ ports_enable_class (netfs_protid_class);
-+ if (cports == 0 && nports == 0)
-+ {
-+ /* The last client is gone. Our job is done. */
-+ error_t err = netfs_shutdown (0);
-+ if (! err)
-+ exit (EXIT_SUCCESS);
-+
-+ /* If netfs_shutdown returns EBUSY, we lost a race against
-+ fsys_goaway. Hence we ignore this error. */
-+ if (err != EBUSY)
-+ error (1, err, "netfs_shutdown");
-+ }
-+}
-+
-+error_t
-+chroot_init (void)
-+{
-+ /* Install our own clean routine. */
-+ netfs_protid_class->clean_routine = chroot_netfs_release_protid;
-+ return 0;
-+}
-+
-+/* This is called by netfs_S_fsys_getroot. */
-+error_t
-+netfs_check_open_permissions (struct iouser *user, struct node *np,
-+ int flags, int newnode)
-+{
-+ return 0; /* XXX */
-+}
-+
-+/* The user may define this function. Attempt to set the passive
-+ translator record for FILE to ARGZ (of length ARGZLEN) for user
-+ CRED. */
-+error_t
-+netfs_set_translator (struct iouser *cred, struct node *np,
-+ char *argz, size_t argzlen)
-+{
-+ return file_set_translator (netfs_node_netnode (np)->file,
-+ FS_TRANS_EXCL|FS_TRANS_SET,
-+ FS_TRANS_EXCL|FS_TRANS_SET, 0,
-+ argz, argzlen,
-+ MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND);
-+}
-+
-+/* These callbacks are used only by the standard netfs_S_dir_lookup,
-+ which we do not use. But the shared library requires us to define them. */
-+error_t
-+netfs_attempt_lookup (struct iouser *user, struct node *dir,
-+ char *name, struct node **np)
-+{
-+ assert (! "should not be here");
-+ return EIEIO;
-+}
-+
-+error_t
-+netfs_attempt_create_file (struct iouser *user, struct node *dir,
-+ char *name, mode_t mode, struct node **np)
-+{
-+ assert (! "should not be here");
-+ return EIEIO;
-+}
-+
-+/* Make sure that NP->nn_stat is filled with the most current information.
-+ CRED identifies the user responsible for the operation. NP is locked. */
-+error_t
-+netfs_validate_stat (struct node *np, struct iouser *cred)
-+{
-+ struct stat st;
-+ error_t err = io_stat (netfs_node_netnode (np)->file, &st);
-+ if (err)
-+ return err;
-+
-+ np->nn_stat = st;
-+ np->nn_translated = S_ISLNK (st.st_mode) ? S_IFLNK : 0;
-+
-+ return 0;
-+}
-+
-+#if 0
-+/* Various netfs functions will call fshelp_isowner to check whether
-+ USER is allowed to do some operation. As gpg is not running
-+ within the fakeauth'ed environment, USER contains the real
-+ user. Hence, we override this check. */
-+error_t
-+fshelp_isowner (struct stat *st, struct iouser *user)
-+{
-+ return 0;
-+}
-+#endif
-+
-+error_t
-+netfs_attempt_chown (struct iouser *cred, struct node *np,
-+ uid_t uid, uid_t gid)
-+{
-+ if (! cred)
-+ return EOPNOTSUPP;
-+ return file_chown (netfs_node_netnode (np)->file, uid, gid);
-+}
-+
-+error_t
-+netfs_attempt_chauthor (struct iouser *cred, struct node *np, uid_t author)
-+{
-+ if (! cred)
-+ return EOPNOTSUPP;
-+ return file_chauthor (netfs_node_netnode (np)->file, author);
-+}
-+
-+/* This should attempt a chmod call for the user specified by CRED on
-+ locked node NODE, to change the mode to MODE. Unlike the normal Unix
-+ and Hurd meaning of chmod, this function is also used to attempt to
-+ change files into other types. If such a transition is attempted which
-+ is impossible, then return EOPNOTSUPP. */
-+error_t
-+netfs_attempt_chmod (struct iouser *cred, struct node *np, mode_t mode)
-+{
-+ if (! cred)
-+ return EOPNOTSUPP;
-+ return file_chmod (netfs_node_netnode (np)->file, mode);
-+}
-+
-+/* The user must define this function. Attempt to turn locked node NP
-+ (user CRED) into a symlink with target NAME. */
-+error_t
-+netfs_attempt_mksymlink (struct iouser *cred, struct node *np, char *name)
-+{
-+ int namelen = strlen (name) + 1;
-+ char trans[sizeof _HURD_SYMLINK + namelen];
-+ memcpy (trans, _HURD_SYMLINK, sizeof _HURD_SYMLINK);
-+ memcpy (&trans[sizeof _HURD_SYMLINK], name, namelen);
-+ return file_set_translator (netfs_node_netnode (np)->file,
-+ FS_TRANS_EXCL|FS_TRANS_SET,
-+ FS_TRANS_EXCL|FS_TRANS_SET, 0,
-+ trans, sizeof trans,
-+ MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND);
-+}
-+
-+error_t
-+netfs_attempt_mkdev (struct iouser *cred, struct node *np,
-+ mode_t type, dev_t indexes)
-+{
-+ char *trans = 0;
-+ int translen = asprintf (&trans, "%s%c%d%c%d",
-+ S_ISCHR (type) ? _HURD_CHRDEV : _HURD_BLKDEV,
-+ '\0', major (indexes), '\0', minor (indexes));
-+ if (trans == 0)
-+ return ENOMEM;
-+ else
-+ {
-+ error_t err = file_set_translator (netfs_node_netnode (np)->file,
-+ FS_TRANS_EXCL|FS_TRANS_SET,
-+ FS_TRANS_EXCL|FS_TRANS_SET, 0,
-+ trans, translen + 1,
-+ MACH_PORT_NULL,
-+ MACH_MSG_TYPE_COPY_SEND);
-+ free (trans);
-+ return err;
-+ }
-+}
-+
-+error_t
-+netfs_attempt_chflags (struct iouser *cred, struct node *np, int flags)
-+{
-+ return file_chflags (netfs_node_netnode (np)->file, flags);
-+}
-+
-+error_t
-+netfs_attempt_utimes (struct iouser *cred, struct node *np,
-+ struct timespec *atime, struct timespec *mtime)
-+{
-+ union tv
-+ {
-+ struct timeval tv;
-+ time_value_t tvt;
-+ };
-+ union tv a, m;
-+ if (atime)
-+ {
-+ TIMESPEC_TO_TIMEVAL (&a.tv, atime);
-+ }
-+ else
-+ a.tv.tv_sec = a.tv.tv_usec = -1;
-+ if (mtime)
-+ {
-+ TIMESPEC_TO_TIMEVAL (&m.tv, mtime);
-+ }
-+ else
-+ m.tv.tv_sec = m.tv.tv_usec = -1;
-+
-+ return file_utimes (netfs_node_netnode (np)->file, a.tvt, m.tvt);
-+}
-+
-+error_t
-+netfs_attempt_set_size (struct iouser *cred, struct node *np, off_t size)
-+{
-+ return file_set_size (netfs_node_netnode (np)->file, size);
-+}
-+
-+error_t
-+netfs_attempt_statfs (struct iouser *cred, struct node *np, struct statfs *st)
-+{
-+ return file_statfs (netfs_node_netnode (np)->file, st);
-+}
-+
-+error_t __attribute__ ((weak))
-+netfs_attempt_sync (struct iouser *cred, struct node *np, int wait)
-+{
-+ return file_sync (netfs_node_netnode (np)->file, wait, 0);
-+}
-+
-+error_t
-+netfs_attempt_syncfs (struct iouser *cred, int wait)
-+{
-+ return 0;
-+}
-+
-+error_t
-+netfs_attempt_mkdir (struct iouser *user, struct node *dir,
-+ char *name, mode_t mode)
-+{
-+ return dir_mkdir (netfs_node_netnode (dir)->file, name, mode | S_IRWXU);
-+}
-+
-+
-+/* XXX
-+ Removing a node should mark the netnode so that it is GC'd when
-+ it has no hard refs.
-+ */
-+
-+error_t
-+netfs_attempt_unlink (struct iouser *user, struct node *dir, char *name)
-+{
-+ return dir_unlink (netfs_node_netnode (dir)->file, name);
-+}
-+
-+error_t
-+netfs_attempt_rename (struct iouser *user, struct node *fromdir,
-+ char *fromname, struct node *todir,
-+ char *toname, int excl)
-+{
-+ return dir_rename (netfs_node_netnode (fromdir)->file, fromname,
-+ netfs_node_netnode (todir)->file, toname, excl);
-+}
-+
-+error_t
-+netfs_attempt_rmdir (struct iouser *user,
-+ struct node *dir, char *name)
-+{
-+ return dir_rmdir (netfs_node_netnode (dir)->file, name);
-+}
-+
-+error_t __attribute__ ((weak))
-+netfs_attempt_link (struct iouser *user, struct node *dir,
-+ struct node *file, char *name, int excl)
-+{
-+ return dir_link (netfs_node_netnode (dir)->file,
-+ netfs_node_netnode (file)->file, name, excl);
-+}
-+
-+error_t __attribute__ ((weak))
-+netfs_S_dir_lookup (struct protid *diruser,
-+ char *filename,
-+ int flags,
-+ mode_t mode,
-+ retry_type *do_retry,
-+ char *retry_name,
-+ mach_port_t *retry_port,
-+ mach_msg_type_name_t *retry_port_type)
-+{
-+ struct node *dnp, *np;
-+ error_t err;
-+ struct protid *newpi;
-+ struct iouser *user;
-+ mach_port_t file;
-+ mach_port_t idport, fsidport;
-+ ino_t fileno;
-+
-+ if (!diruser)
-+ return EOPNOTSUPP;
-+
-+ //error (0, 0, "netfs_S_dir_lookup (%p, %s, 0x%x, ...", diruser, filename, flags);
-+ dnp = diruser->po->np;
-+
-+ mach_port_t dir = netfs_node_netnode (dnp)->file;
-+ err = dir_lookup (dir, filename,
-+ flags & (O_NOLINK|O_RDWR|O_EXEC|O_CREAT|O_EXCL|O_NONBLOCK),
-+ mode, do_retry, retry_name, &file);
-+ if (err)
-+ {
-+ /* xxx deref stuff */
-+ return err;
-+ }
-+
-+ switch (*do_retry)
-+ {
-+ case FS_RETRY_NORMAL:
-+ break;
-+
-+ case FS_RETRY_REAUTH:
-+ error (0, 0, "FS_RETRY_REAUTH");
-+ /* Fallthrough. */
-+
-+ case FS_RETRY_MAGICAL:
-+ *retry_port = file;
-+ *retry_port_type = MACH_MSG_TYPE_MOVE_SEND;
-+ return 0;
-+
-+ default:
-+ /* Invalid response to our dir_lookup request. */
-+ if (MACH_PORT_VALID (file))
-+ mach_port_deallocate (mach_task_self (), file);
-+ *retry_port = MACH_PORT_NULL;
-+ *retry_port_type = MACH_MSG_TYPE_COPY_SEND;
-+ return EOPNOTSUPP;
-+ }
-+
-+ /* We have a new port to an underlying node.
-+ Find or make our corresponding virtual node. */
-+
-+ np = 0;
-+ err = io_identity (file, &idport, &fsidport, &fileno);
-+ if (err)
-+ {
-+ mach_port_deallocate (mach_task_self (), file);
-+ return err;
-+ }
-+
-+ mach_port_deallocate (mach_task_self (), fsidport);
-+
-+ redo_hash_lookup:
-+ pthread_mutex_lock (&idport_ihash_lock);
-+ pthread_mutex_lock (&dnp->lock);
-+ /* The hashtable may not hold a true reference on the node. Acquire the
-+ refcount lock so that, if a node is found, its reference counter cannot
-+ drop to 0 before we get our own reference. */
-+ pthread_spin_lock (&netfs_node_refcnt_lock);
-+ np = hurd_ihash_find (&idport_ihash, idport);
-+ if (np != NULL)
-+ {
-+ /* We already know about this node. */
-+
-+ if (np->references == 0)
-+ {
-+ /* But it might be in the process of being released. If so,
-+ unlock the hash table to give the node a chance to actually
-+ be removed and retry. */
-+ pthread_spin_unlock (&netfs_node_refcnt_lock);
-+ pthread_mutex_unlock (&dnp->lock);
-+ pthread_mutex_unlock (&idport_ihash_lock);
-+ goto redo_hash_lookup;
-+ }
-+
-+ /* Otherwise, reference it right away. */
-+ np->references++;
-+ pthread_spin_unlock (&netfs_node_refcnt_lock);
-+
-+ mach_port_deallocate (mach_task_self (), idport);
-+
-+ if (np == dnp)
-+ {
-+ /* dnp is already locked. */
-+ }
-+ else
-+ {
-+ pthread_mutex_lock (&np->lock);
-+ pthread_mutex_unlock (&dnp->lock);
-+ }
-+
-+ pthread_mutex_unlock (&idport_ihash_lock);
-+ }
-+ else
-+ {
-+ pthread_spin_unlock (&netfs_node_refcnt_lock);
-+ err = chroot_new_node (file, idport, 1, 0, &np);
-+ pthread_mutex_unlock (&dnp->lock);
-+ if (!err)
-+ err = netfs_validate_stat (np, diruser->user);
-+ }
-+ if (err)
-+ goto lose;
-+
-+ assert (*do_retry == FS_RETRY_NORMAL);
-+ flags &= ~(O_CREAT|O_EXCL|O_NOLINK|O_NOTRANS|O_NONBLOCK);
-+
-+ err = iohelp_dup_iouser (&user, diruser->user);
-+ if (!err)
-+ {
-+ newpi = netfs_make_protid (netfs_make_peropen (np, flags, diruser->po),
-+ user);
-+ if (! newpi)
-+ {
-+ iohelp_free_iouser (user);
-+ err = errno;
-+ }
-+ else
-+ {
-+ *retry_port = ports_get_right (newpi);
-+ *retry_port_type = MACH_MSG_TYPE_MAKE_SEND;
-+ ports_port_deref (newpi);
-+ }
-+ }
-+
-+ lose:
-+ if (dir != netfs_node_netnode (dnp)->file)
-+ mach_port_deallocate (mach_task_self (), dir);
-+ if (np != NULL)
-+ netfs_nput (np);
-+ return err;
-+}
-+
-+error_t __attribute__ ((weak))
-+netfs_attempt_mkfile (struct iouser *user, struct node *dir,
-+ mode_t mode, struct node **np)
-+{
-+ file_t newfile;
-+ error_t err = dir_mkfile (netfs_node_netnode (dir)->file, O_RDWR|O_EXEC,
-+ mode, &newfile);
-+ pthread_mutex_unlock (&dir->lock);
-+ if (err)
-+ return err;
-+
-+ err = chroot_new_node (newfile, MACH_PORT_NULL, 0, 0, np);
-+ if (err)
-+ return err;
-+
-+ pthread_mutex_unlock (&(*np)->lock);
-+ return err;
-+}
-+
-+error_t
-+netfs_attempt_readlink (struct iouser *user, struct node *np, char *buf)
-+{
-+ char transbuf[sizeof _HURD_SYMLINK + np->nn_stat.st_size + 1];
-+ char *trans = transbuf;
-+ size_t translen = sizeof transbuf;
-+ error_t err = file_get_translator (netfs_node_netnode (np)->file,
-+ &trans, &translen);
-+ if (err == 0)
-+ {
-+ if (translen < sizeof _HURD_SYMLINK
-+ || memcmp (trans, _HURD_SYMLINK, sizeof _HURD_SYMLINK) != 0)
-+ err = EINVAL;
-+ else
-+ {
-+ assert (translen <= sizeof _HURD_SYMLINK + np->nn_stat.st_size + 1);
-+ memcpy (buf, &trans[sizeof _HURD_SYMLINK],
-+ translen - sizeof _HURD_SYMLINK);
-+ }
-+ if (trans != transbuf)
-+ munmap (trans, translen);
-+ }
-+ return err;
-+}
-+
-+error_t __attribute__ ((weak))
-+netfs_get_dirents (struct iouser *cred, struct node *dir,
-+ int entry, int nentries, char **data,
-+ mach_msg_type_number_t *datacnt,
-+ vm_size_t bufsize, int *amt)
-+{
-+ error_t err;
-+ err = dir_readdir (netfs_node_netnode (dir)->file, data, datacnt,
-+ entry, nentries, bufsize, amt);
-+ error (0, err, "%s: dir is %d", __FUNCTION__, netfs_node_netnode (dir)->file);
-+ return err;
-+}
-+
-+error_t __attribute__ ((weak))
-+netfs_attempt_read (struct iouser *cred, struct node *np,
-+ off_t offset, size_t *len, void *data)
-+{
-+ char *buf = data;
-+ error_t err = io_read (netfs_node_netnode (np)->file,
-+ &buf, len, offset, *len);
-+ if (err == 0 && buf != data)
-+ {
-+ memcpy (data, buf, *len);
-+ munmap (buf, *len);
-+ }
-+ return err;
-+}
-+
-+error_t __attribute__ ((weak))
-+netfs_attempt_write (struct iouser *cred, struct node *np,
-+ off_t offset, size_t *len, void *data)
-+{
-+ return io_write (netfs_node_netnode (np)->file, data, *len, offset, len);
-+}
-+
-+error_t
-+netfs_report_access (struct iouser *cred, struct node *np, int *types)
-+{
-+ return file_check_access (netfs_node_netnode (np)->file, types);
-+}
-+
-+error_t
-+netfs_file_get_storage_info (struct iouser *cred,
-+ struct node *np,
-+ mach_port_t **ports,
-+ mach_msg_type_name_t *ports_type,
-+ mach_msg_type_number_t *num_ports,
-+ int **ints,
-+ mach_msg_type_number_t *num_ints,
-+ off_t **offsets,
-+ mach_msg_type_number_t *num_offsets,
-+ char **data,
-+ mach_msg_type_number_t *data_len)
-+{
-+ *ports_type = MACH_MSG_TYPE_MOVE_SEND;
-+ return file_get_storage_info (netfs_node_netnode (np)->file,
-+ ports, num_ports,
-+ ints, num_ints,
-+ offsets, num_offsets,
-+ data, data_len);
-+}
-+
-+kern_return_t
-+netfs_S_file_exec (struct protid *user,
-+ task_t task,
-+ int flags,
-+ char *argv,
-+ size_t argvlen,
-+ char *envp,
-+ size_t envplen,
-+ mach_port_t *fds,
-+ size_t fdslen,
-+ mach_port_t *portarray,
-+ size_t portarraylen,
-+ int *intarray,
-+ size_t intarraylen,
-+ mach_port_t *deallocnames,
-+ size_t deallocnameslen,
-+ mach_port_t *destroynames,
-+ size_t destroynameslen)
-+{
-+ error_t err;
-+ file_t file;
-+
-+ if (!user)
-+ return EOPNOTSUPP;
-+
-+ pthread_mutex_lock (&user->po->np->lock);
-+ file = netfs_node_netnode (user->po->np)->file;
-+ err = mach_port_mod_refs (mach_task_self (),
-+ file, MACH_PORT_RIGHT_SEND, 1);
-+ pthread_mutex_unlock (&user->po->np->lock);
-+
-+ if (!err)
-+ {
-+ /* We cannot use MACH_MSG_TYPE_MOVE_SEND because we might need to
-+ retry an interrupted call that would have consumed the rights. */
-+ err = file_exec (netfs_node_netnode (user->po->np)->file,
-+ task, flags, argv, argvlen,
-+ envp, envplen, fds, MACH_MSG_TYPE_COPY_SEND, fdslen,
-+ portarray, MACH_MSG_TYPE_COPY_SEND, portarraylen,
-+ intarray, intarraylen, deallocnames, deallocnameslen,
-+ destroynames, destroynameslen);
-+ mach_port_deallocate (mach_task_self (), file);
-+ }
-+
-+ if (err == 0)
-+ {
-+ size_t i;
-+ mach_port_deallocate (mach_task_self (), task);
-+ for (i = 0; i < fdslen; ++i)
-+ mach_port_deallocate (mach_task_self (), fds[i]);
-+ for (i = 0; i < portarraylen; ++i)
-+ mach_port_deallocate (mach_task_self (), portarray[i]);
-+ }
-+ return err;
-+}
-+
-+error_t
-+netfs_S_io_map (struct protid *user,
-+ mach_port_t *rdobj, mach_msg_type_name_t *rdobjtype,
-+ mach_port_t *wrobj, mach_msg_type_name_t *wrobjtype)
-+{
-+ error_t err;
-+
-+ if (!user)
-+ return EOPNOTSUPP;
-+ *rdobjtype = *wrobjtype = MACH_MSG_TYPE_MOVE_SEND;
-+
-+ pthread_mutex_lock (&user->po->np->lock);
-+ err = io_map (netfs_node_netnode (user->po->np)->file, rdobj, wrobj);
-+ pthread_mutex_unlock (&user->po->np->lock);
-+ return err;
-+}
-+
-+error_t
-+netfs_S_io_map_cntl (struct protid *user,
-+ mach_port_t *obj,
-+ mach_msg_type_name_t *objtype)
-+{
-+ error_t err;
-+
-+ if (!user)
-+ return EOPNOTSUPP;
-+ *objtype = MACH_MSG_TYPE_MOVE_SEND;
-+
-+ pthread_mutex_lock (&user->po->np->lock);
-+ err = io_map_cntl (netfs_node_netnode (user->po->np)->file, obj);
-+ pthread_mutex_unlock (&user->po->np->lock);
-+ return err;
-+}
-+
-+error_t
-+netfs_S_io_identity (struct protid *user,
-+ mach_port_t *id,
-+ mach_msg_type_name_t *idtype,
-+ mach_port_t *fsys,
-+ mach_msg_type_name_t *fsystype,
-+ ino_t *fileno)
-+{
-+ error_t err;
-+
-+ if (!user)
-+ return EOPNOTSUPP;
-+
-+ *idtype = *fsystype = MACH_MSG_TYPE_MOVE_SEND;
-+
-+ pthread_mutex_lock (&user->po->np->lock);
-+ err = io_identity (netfs_node_netnode (user->po->np)->file,
-+ id, fsys, fileno);
-+ pthread_mutex_unlock (&user->po->np->lock);
-+ return err;
-+}
-+
-+#define NETFS_S_SIMPLE(name) \
-+error_t \
-+netfs_S_##name (struct protid *user) \
-+{ \
-+ error_t err; \
-+ \
-+ if (!user) \
-+ return EOPNOTSUPP; \
-+ \
-+ pthread_mutex_lock (&user->po->np->lock); \
-+ err = name (netfs_node_netnode (user->po->np)->file); \
-+ pthread_mutex_unlock (&user->po->np->lock); \
-+ return err; \
-+}
-+
-+NETFS_S_SIMPLE (io_get_conch)
-+NETFS_S_SIMPLE (io_release_conch)
-+NETFS_S_SIMPLE (io_eofnotify)
-+NETFS_S_SIMPLE (io_readnotify)
-+NETFS_S_SIMPLE (io_readsleep)
-+NETFS_S_SIMPLE (io_sigio)
-+
-+error_t
-+netfs_S_io_prenotify (struct protid *user,
-+ vm_offset_t start, vm_offset_t stop)
-+{
-+ error_t err;
-+
-+ if (!user)
-+ return EOPNOTSUPP;
-+
-+ pthread_mutex_lock (&user->po->np->lock);
-+ err = io_prenotify (netfs_node_netnode (user->po->np)->file, start, stop);
-+ pthread_mutex_unlock (&user->po->np->lock);
-+ return err;
-+}
-+
-+error_t
-+netfs_S_io_postnotify (struct protid *user,
-+ vm_offset_t start, vm_offset_t stop)
-+{
-+ error_t err;
-+
-+ if (!user)
-+ return EOPNOTSUPP;
-+
-+ pthread_mutex_lock (&user->po->np->lock);
-+ err = io_postnotify (netfs_node_netnode (user->po->np)->file, start, stop);
-+ pthread_mutex_unlock (&user->po->np->lock);
-+ return err;
-+}
-+
-+/* This overrides the library's definition. */
-+int
-+netfs_demuxer (mach_msg_header_t *inp,
-+ mach_msg_header_t *outp)
-+{
-+ mig_routine_t routine;
-+ if ((routine = netfs_io_server_routine (inp)) ||
-+ (routine = netfs_fs_server_routine (inp)) ||
-+ (routine = ports_notify_server_routine (inp)) ||
-+ (routine = netfs_fsys_server_routine (inp)) ||
-+ /* XXX we should intercept interrupt_operation and do
-+ the ports_S_interrupt_operation work as well as
-+ sending an interrupt_operation to the underlying file.
-+ */
-+ (routine = ports_interrupt_server_routine (inp)))
-+ {
-+ (*routine) (inp, outp);
-+ return TRUE;
-+ }
-+ else
-+ {
-+ /* We didn't recognize the message ID, so pass the message through
-+ unchanged to the underlying file. */
-+ struct protid *cred;
-+ if (MACH_MSGH_BITS_LOCAL (inp->msgh_bits) ==
-+ MACH_MSG_TYPE_PROTECTED_PAYLOAD)
-+ cred = ports_lookup_payload (netfs_port_bucket,
-+ inp->msgh_protected_payload,
-+ netfs_protid_class);
-+ else
-+ cred = ports_lookup_port (netfs_port_bucket,
-+ inp->msgh_local_port,
-+ netfs_protid_class);
-+ if (cred == 0)
-+ /* This must be an unknown message on our fsys control port. */
-+ return 0;
-+ else
-+ {
-+ error_t err;
-+ assert (MACH_MSGH_BITS_LOCAL (inp->msgh_bits)
-+ == MACH_MSG_TYPE_MOVE_SEND
-+ || MACH_MSGH_BITS_LOCAL (inp->msgh_bits)
-+ == MACH_MSG_TYPE_PROTECTED_PAYLOAD);
-+ inp->msgh_bits = (inp->msgh_bits & MACH_MSGH_BITS_COMPLEX)
-+ | MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND,
-+ MACH_MSGH_BITS_REMOTE (inp->msgh_bits));
-+ inp->msgh_local_port = inp->msgh_remote_port; /* reply port */
-+ inp->msgh_remote_port = netfs_node_netnode (cred->po->np)->file;
-+ err = mach_msg (inp, MACH_SEND_MSG, inp->msgh_size, 0,
-+ MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
-+ MACH_PORT_NULL);
-+ assert_perror (err); /* XXX should synthesize reply */
-+ ports_port_deref (cred);
-+ /* We already sent the message, so the server loop shouldn't do it again. */
-+ ((mig_reply_header_t *) outp)->RetCode = MIG_NO_REPLY;
-+ return 1;
-+ }
-+ }
-+}
-diff --git a/trans/chroot.h b/trans/chroot.h
-new file mode 100644
-index 0000000..adabad0
---- /dev/null
-+++ b/trans/chroot.h
-@@ -0,0 +1,37 @@
-+#ifndef __HURD_CHROOT_H__
-+#define __HURD_CHROOT_H__
-+
-+struct netnode
-+{
-+ hurd_ihash_locp_t idport_locp;/* easy removal pointer in idport ihash */
-+ mach_port_t idport; /* port from io_identity */
-+ file_t file; /* port on real file */
-+};
-+
-+struct chroot_node;
-+
-+error_t chroot_init (void);
-+
-+/* Make a new virtual node. Always consumes the ports. If
-+ successful, NP will be locked. */
-+error_t chroot_new_node (file_t file, mach_port_t idport, int locked,
-+ size_t size, struct node **np);
-+
-+/* Users must implement this. */
-+void chroot_node_norefs (struct node *np);
-+
-+/* Return the address of the chroot_node for NODE. NODE must have been
-+ allocated using chroot_new_node. */
-+static inline struct chroot_node *
-+chroot_node (struct node *node)
-+{
-+ return (struct chroot_node *) ((char *) netfs_node_netnode (node)
-+ + sizeof (struct netnode));
-+}
-+
-+// XXX
-+pthread_mutex_t idport_ihash_lock;
-+struct hurd_ihash idport_ihash;
-+
-+
-+#endif /* __HURD_CHROOT_H__ */
-diff --git a/trans/gpg.c b/trans/gpg.c
-new file mode 100644
-index 0000000..7eb9424
---- /dev/null
-+++ b/trans/gpg.c
-@@ -0,0 +1,734 @@
-+/* gpg -- a translator for encrypting, decrypting, and verifying files
-+ Copyright (C) 2016 Free Software Foundation, Inc.
-+
-+ 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, or (at
-+ your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful, but
-+ WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-+
-+#include <argz.h>
-+#include <argp.h>
-+#include <dirent.h>
-+#include <error.h>
-+#include <hurd/netfs.h>
-+#include <stddef.h>
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <string.h>
-+#include <fcntl.h>
-+#include <sys/mman.h>
-+#include <sys/stat.h>
-+#include <pthread.h>
-+#include <hurd/ihash.h>
-+#include <hurd/paths.h>
-+#include <sys/types.h>
-+#include <sys/wait.h>
-+#include <unistd.h>
-+
-+#include <version.h>
-+
-+#include "chroot.h"
-+
-+#include "libnetfs/fs_S.h"
-+#include "libnetfs/io_S.h"
-+#include "libnetfs/fsys_S.h"
-+#include "libports/notify_S.h"
-+#include "libports/interrupt_S.h"
-+
-+const char *argp_program_version = STANDARD_HURD_VERSION (gpg);
-+
-+char *netfs_server_name = "gpg";
-+char *netfs_server_version = HURD_VERSION;
-+int netfs_maxsymlinks = 16; /* arbitrary */
-+
-+struct chroot_node
-+{
-+ unsigned int encrypt:1;
-+ file_t shadow_file;
-+};
-+
-+#define GPG_DEFAULT_FILENAME "/usr/bin/gpg2"
-+static char* gpg_filename = GPG_DEFAULT_FILENAME;
-+static file_t gpg_file;
-+
-+int symmetric;
-+char *recipients;
-+size_t recipients_len;
-+
-+static error_t
-+execute_gpg (mach_port_t in, mach_port_t out, mach_port_t extra,
-+ char *argz, size_t argz_len, pid_t *pid)
-+{
-+ error_t err;
-+ task_t task;
-+ process_t proc;
-+ mach_port_t ports[INIT_PORT_MAX];
-+ mach_port_t fds[STDERR_FILENO + 2];
-+ int ints[INIT_INT_MAX];
-+ int i;
-+
-+ for (i = 0; i < INIT_PORT_MAX; i++)
-+ ports[i] = MACH_PORT_NULL;
-+ for (i = 0; i < STDERR_FILENO + 2; i++)
-+ fds[i] = MACH_PORT_NULL;
-+ memset (ints, 0, INIT_INT_MAX * sizeof(int));
-+
-+ ports[INIT_PORT_CWDIR] = getcwdir ();
-+ ports[INIT_PORT_CRDIR] = getcrdir ();
-+ ports[INIT_PORT_AUTH] = getauth ();
-+ fds[STDIN_FILENO] = in;
-+ fds[STDOUT_FILENO] = out;
-+ fds[STDERR_FILENO] = getdport (STDERR_FILENO);
-+ fds[STDERR_FILENO+1] = extra;
-+
-+ err = task_create (mach_task_self (), 0, &task);
-+ if (err)
-+ goto lose;
-+
-+ proc = getproc ();
-+ proc_child (proc, task);
-+
-+ /* Try and exec GnuPG in TASK... */
-+ err = file_exec (gpg_file, task, EXEC_DEFAULTS,
-+ argz, argz_len, 0, 0,
-+ fds, MACH_MSG_TYPE_COPY_SEND, STDERR_FILENO + 2,
-+ ports, MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX,
-+ ints, INIT_INT_MAX, 0, 0, 0, 0);
-+ if (err)
-+ goto lose;
-+
-+ err = proc_task2pid (proc, task, pid);
-+
-+ lose:
-+ for (i = 0; i < INIT_PORT_MAX; i++)
-+ mach_port_deallocate (mach_task_self (), ports[i]);
-+ mach_port_deallocate (mach_task_self (), fds[STDERR_FILENO]);
-+ return err;
-+}
-+
-+error_t
-+clone_file (file_t file, file_t *new_file)
-+{
-+ error_t err;
-+ off_t newp;
-+ retry_type do_retry;
-+ string_t retry_name;
-+ err = dir_lookup (file, "", O_RDONLY, 0, &do_retry, retry_name, new_file);
-+ if (err)
-+ return err;
-+ return io_seek (*new_file, 0, SEEK_SET, &newp);
-+}
-+
-+static int
-+gpg_verify (file_t sigfile, file_t orig_file)
-+{
-+ error_t err;
-+ file_t file;
-+ pid_t pid;
-+ char *argz = NULL;
-+ size_t argz_len = 0;
-+ err = clone_file (orig_file, &file);
-+ if (err)
-+ return 0;
-+
-+ argz_add (&argz, &argz_len, "gpg2");
-+ argz_add (&argz, &argz_len, "--verify");
-+ argz_add (&argz, &argz_len, "/dev/fd/3");
-+ argz_add (&argz, &argz_len, "-");
-+ err = execute_gpg (file, getdport (STDERR_FILENO), sigfile, argz, argz_len, &pid);
-+ mach_port_deallocate (mach_task_self (), file);
-+ if (err)
-+ {
-+ error (0, err, "execute_gpg");
-+ return 0;
-+ }
-+
-+ int status;
-+ while (waitpid (pid, &status, 0) == (pid_t)-1 && errno == EINTR)
-+ { }
-+
-+ return WIFEXITED (status) && WEXITSTATUS (status) == 0;
-+}
-+
-+static int
-+gpg_decrypt (file_t cipherfile, file_t plainfile)
-+{
-+ error_t err;
-+ pid_t pid;
-+ char *argz = NULL;
-+ size_t argz_len = 0;
-+
-+ argz_add (&argz, &argz_len, "gpg2");
-+ argz_add (&argz, &argz_len, "--output");
-+ argz_add (&argz, &argz_len, "-");
-+ err = execute_gpg (cipherfile, plainfile, MACH_PORT_NULL,
-+ argz, argz_len, &pid);
-+ if (err)
-+ {
-+ error (0, err, "execute_gpg");
-+ return 0;
-+ }
-+
-+ int status;
-+ while (waitpid (pid, &status, 0) == (pid_t)-1 && errno == EINTR)
-+ { }
-+
-+ return WIFEXITED (status) && WEXITSTATUS (status) == 0;
-+}
-+
-+static int
-+gpg_encrypt (file_t plainfile, file_t cipherfile)
-+{
-+ error_t err;
-+ pid_t pid;
-+ char *argz = NULL;
-+ size_t argz_len = 0;
-+
-+ argz_add (&argz, &argz_len, "gpg2");
-+ argz_add (&argz, &argz_len, "--always-trust"); // XXX
-+ argz_add (&argz, &argz_len, "--output");
-+ argz_add (&argz, &argz_len, "-");
-+ if (recipients)
-+ {
-+ char *recipient;
-+ argz_add (&argz, &argz_len, "--encrypt");
-+ for (recipient = recipients;
-+ recipient;
-+ recipient = argz_next (recipients, recipients_len, recipient))
-+ {
-+ argz_add (&argz, &argz_len, "--recipient");
-+ argz_add (&argz, &argz_len, recipient);
-+ }
-+ }
-+ if (symmetric)
-+ argz_add (&argz, &argz_len, "--symmetric");
-+
-+ err = execute_gpg (plainfile, cipherfile, MACH_PORT_NULL,
-+ argz, argz_len, &pid);
-+ if (err)
-+ {
-+ error (0, err, "execute_gpg");
-+ return 0;
-+ }
-+
-+ int status;
-+ while (waitpid (pid, &status, 0) == (pid_t)-1 && errno == EINTR)
-+ { }
-+
-+ return WIFEXITED (status) && WEXITSTATUS (status) == 0;
-+}
-+
-+static error_t
-+make_tmp_file (file_t *file)
-+{
-+ char name[] = "/tmp/gpgtmp-XXXXXX";
-+ int fd;
-+
-+ fd = mkstemp (name);
-+ if (fd == -1)
-+ return errno;
-+ if (unlink (name) == -1)
-+ return errno;
-+ *file = getdport (fd);
-+ close (fd);
-+ return 0;
-+}
-+
-+error_t
-+netfs_S_dir_lookup (struct protid *diruser,
-+ char *filename,
-+ int flags,
-+ mode_t mode,
-+ retry_type *do_retry,
-+ char *retry_name,
-+ mach_port_t *retry_port,
-+ mach_msg_type_name_t *retry_port_type)
-+{
-+ struct node *dnp, *np;
-+ error_t err;
-+ struct protid *newpi;
-+ struct iouser *user;
-+ mach_port_t file;
-+ mach_port_t idport, fsidport;
-+ ino_t fileno;
-+
-+ if (!diruser)
-+ return EOPNOTSUPP;
-+
-+ error (0, 0, "netfs_S_dir_lookup (%p, %s, 0x%x, ...", diruser, filename, flags);
-+ dnp = diruser->po->np;
-+
-+ mach_port_t dir = netfs_node_netnode (dnp)->file;
-+ err = dir_lookup (dir, filename,
-+ flags & (O_NOLINK|O_RDWR|O_EXEC|O_CREAT|O_EXCL|O_NONBLOCK),
-+ mode, do_retry, retry_name, &file);
-+ if (err == ENOENT)
-+ {
-+ file_t gpgfile;
-+ char *gpgname;
-+ asprintf (&gpgname, "%s.gpg", filename);
-+ gpgfile = file_name_lookup_under (dir, gpgname, O_RDONLY, 0);
-+ if (MACH_PORT_VALID (gpgfile))
-+ {
-+ file_t tmpfile;
-+ int ok;
-+ off_t newp;
-+
-+ err = make_tmp_file (&tmpfile);
-+ if (err)
-+ return err;
-+ ok = gpg_decrypt (gpgfile, tmpfile);
-+ mach_port_deallocate (mach_task_self (), gpgfile);
-+ if (! ok)
-+ {
-+ mach_port_deallocate (mach_task_self (), tmpfile);
-+ return EIO;
-+ }
-+
-+ err = io_seek (tmpfile, 0, SEEK_SET, &newp);
-+ if (err)
-+ {
-+ mach_port_deallocate (mach_task_self (), tmpfile);
-+ return err;
-+ }
-+
-+ *do_retry = FS_RETRY_NORMAL;
-+ retry_name[0] = 0;
-+ *retry_port = tmpfile;
-+ *retry_port_type = MACH_MSG_TYPE_MOVE_SEND;
-+ return 0;
-+ }
-+ free (gpgname);
-+ }
-+
-+ if (err)
-+ {
-+ /* xxx deref stuff */
-+ return err;
-+ }
-+
-+ switch (*do_retry)
-+ {
-+ case FS_RETRY_NORMAL:
-+ break;
-+
-+ case FS_RETRY_REAUTH:
-+ error (0, 0, "FS_RETRY_REAUTH");
-+ /* Fallthrough. */
-+
-+ case FS_RETRY_MAGICAL:
-+ *retry_port = file;
-+ *retry_port_type = MACH_MSG_TYPE_MOVE_SEND;
-+ return 0;
-+
-+ default:
-+ /* Invalid response to our dir_lookup request. */
-+ if (MACH_PORT_VALID (file))
-+ mach_port_deallocate (mach_task_self (), file);
-+ *retry_port = MACH_PORT_NULL;
-+ *retry_port_type = MACH_MSG_TYPE_COPY_SEND;
-+ return EOPNOTSUPP;
-+ }
-+
-+ /* We have a new port to an underlying node.
-+ Find or make our corresponding virtual node. */
-+
-+ np = 0;
-+ err = io_identity (file, &idport, &fsidport, &fileno);
-+ if (err)
-+ {
-+ mach_port_deallocate (mach_task_self (), file);
-+ return err;
-+ }
-+
-+ mach_port_deallocate (mach_task_self (), fsidport);
-+
-+ redo_hash_lookup:
-+ pthread_mutex_lock (&idport_ihash_lock);
-+ pthread_mutex_lock (&dnp->lock);
-+ /* The hashtable may not hold a true reference on the node. Acquire the
-+ refcount lock so that, if a node is found, its reference counter cannot
-+ drop to 0 before we get our own reference. */
-+ pthread_spin_lock (&netfs_node_refcnt_lock);
-+ np = hurd_ihash_find (&idport_ihash, idport);
-+ if (np != NULL)
-+ {
-+ /* We already know about this node. */
-+
-+ if (np->references == 0)
-+ {
-+ /* But it might be in the process of being released. If so,
-+ unlock the hash table to give the node a chance to actually
-+ be removed and retry. */
-+ pthread_spin_unlock (&netfs_node_refcnt_lock);
-+ pthread_mutex_unlock (&dnp->lock);
-+ pthread_mutex_unlock (&idport_ihash_lock);
-+ goto redo_hash_lookup;
-+ }
-+
-+ /* Otherwise, reference it right away. */
-+ np->references++;
-+ pthread_spin_unlock (&netfs_node_refcnt_lock);
-+
-+ mach_port_deallocate (mach_task_self (), idport);
-+
-+ if (np == dnp)
-+ {
-+ /* dnp is already locked. */
-+ }
-+ else
-+ {
-+ pthread_mutex_lock (&np->lock);
-+ pthread_mutex_unlock (&dnp->lock);
-+ }
-+
-+ pthread_mutex_unlock (&idport_ihash_lock);
-+ }
-+ else
-+ {
-+ pthread_spin_unlock (&netfs_node_refcnt_lock);
-+ err = chroot_new_node (file, idport, 1, sizeof (struct chroot_node), &np);
-+ pthread_mutex_unlock (&dnp->lock);
-+ if (!err)
-+ {
-+ chroot_node (np)->encrypt = chroot_node (dnp)->encrypt;
-+ chroot_node (np)->shadow_file = MACH_PORT_NULL;
-+ err = netfs_validate_stat (np, diruser->user);
-+ }
-+ }
-+ if (err)
-+ goto lose;
-+
-+ {
-+ if (chroot_node (np)->encrypt && flags & O_WRITE
-+ && strncmp (filename, "dev/", 4) != 0)
-+ {
-+ char *ciphname;
-+ asprintf (&ciphname, "%s.gpg", filename);
-+ if (ciphname == NULL)
-+ {
-+ err = errno;
-+ goto lose;
-+ }
-+
-+ /* Fixup name. */
-+ err = dir_link (dir, file, ciphname, 0);
-+ free (ciphname);
-+ if (err)
-+ return err;
-+
-+ err = dir_unlink (dir, filename);
-+ if (err)
-+ return err;
-+
-+ err = make_tmp_file (&chroot_node (np)->shadow_file);
-+ //err = dir_mkfile (dir, flags, mode, &chroot_node (np)->shadow_file);
-+ if (err)
-+ return err;
-+ }
-+
-+ if (retry_name[0] == 0)
-+ {
-+ file_t sig;
-+ char *signame;
-+ asprintf (&signame, "%s.sig", filename);
-+ sig = file_name_lookup_under (dir, signame, O_RDONLY, 0);
-+ if (MACH_PORT_VALID (sig))
-+ {
-+ if (! gpg_verify (sig, file))
-+ err = EIO;
-+ free (signame);
-+ signame = NULL;
-+ mach_port_deallocate (mach_task_self (), sig);
-+ if (err)
-+ goto lose;
-+ }
-+ free (signame);
-+ }
-+ }
-+
-+ assert (*do_retry == FS_RETRY_NORMAL);
-+ flags &= ~(O_CREAT|O_EXCL|O_NOLINK|O_NOTRANS|O_NONBLOCK);
-+
-+ err = iohelp_dup_iouser (&user, diruser->user);
-+ if (!err)
-+ {
-+ newpi = netfs_make_protid (netfs_make_peropen (np, flags, diruser->po),
-+ user);
-+ if (! newpi)
-+ {
-+ iohelp_free_iouser (user);
-+ err = errno;
-+ }
-+ else
-+ {
-+ *retry_port = ports_get_right (newpi);
-+ *retry_port_type = MACH_MSG_TYPE_MAKE_SEND;
-+ ports_port_deref (newpi);
-+ }
-+ }
-+
-+ lose:
-+ if (dir != netfs_node_netnode (dnp)->file)
-+ mach_port_deallocate (mach_task_self (), dir);
-+ if (np != NULL)
-+ netfs_nput (np);
-+ return err;
-+}
-+
-+error_t
-+netfs_attempt_mkfile (struct iouser *user, struct node *dir,
-+ mode_t mode, struct node **np)
-+{
-+ file_t newfile;
-+ error_t err = dir_mkfile (netfs_node_netnode (dir)->file, O_RDWR|O_EXEC,
-+ mode, &newfile);
-+ pthread_mutex_unlock (&dir->lock);
-+ if (err)
-+ return err;
-+
-+ err = chroot_new_node (newfile, MACH_PORT_NULL,
-+ 0, sizeof (struct chroot_node), np);
-+ if (err)
-+ return err;
-+
-+ if (chroot_node (dir)->encrypt)
-+ {
-+ err = make_tmp_file (&chroot_node (*np)->shadow_file);
-+ if (err)
-+ return err;
-+ }
-+ else
-+ chroot_node (*np)->shadow_file = MACH_PORT_NULL;
-+
-+ pthread_mutex_unlock (&(*np)->lock);
-+ return err;
-+}
-+
-+error_t
-+netfs_attempt_read (struct iouser *cred, struct node *np,
-+ off_t offset, size_t *len, void *data)
-+{
-+ struct chroot_node *n = chroot_node (np);
-+ char *buf = data;
-+ error_t err = io_read (n->shadow_file ?: netfs_node_netnode (np)->file,
-+ &buf, len, offset, *len);
-+ if (err == 0 && buf != data)
-+ {
-+ memcpy (data, buf, *len);
-+ munmap (buf, *len);
-+ }
-+ return err;
-+}
-+
-+error_t
-+netfs_attempt_write (struct iouser *cred, struct node *np,
-+ off_t offset, size_t *len, void *data)
-+{
-+ struct chroot_node *n = chroot_node (np);
-+ return io_write (n->shadow_file ?: netfs_node_netnode (np)->file,
-+ data, *len, offset, len);
-+}
-+
-+error_t
-+netfs_attempt_sync (struct iouser *cred, struct node *np, int wait)
-+{
-+ error_t err;
-+ file_t gpg_file = netfs_node_netnode (np)->file;
-+ struct chroot_node *n = chroot_node (np);
-+
-+ err = file_sync (n->shadow_file ?: gpg_file, wait, 0);
-+ if (err)
-+ return err;
-+
-+ if (wait && MACH_PORT_VALID (n->shadow_file))
-+ {
-+ file_t shadow_file;
-+ off_t newp;
-+
-+ err = clone_file (n->shadow_file, &shadow_file);
-+ if (err)
-+ return err;
-+
-+ err = io_seek (gpg_file, 0, SEEK_SET, &newp);
-+ if (err)
-+ return err;
-+
-+ err = gpg_encrypt (shadow_file, gpg_file);
-+ if (err)
-+ return err;
-+
-+ mach_port_deallocate (mach_task_self (), shadow_file);
-+ err = file_sync (gpg_file, wait, 0);
-+ }
-+
-+ return err;
-+}
-+
-+
-+error_t
-+netfs_attempt_link (struct iouser *user, struct node *dir,
-+ struct node *file, char *name, int excl)
-+{
-+ /* XXX translate name if file is encrypted. */
-+ return dir_link (netfs_node_netnode (dir)->file,
-+ netfs_node_netnode (file)->file, name, excl);
-+}
-+
-+void
-+chroot_node_norefs (struct node *np)
-+{
-+ error_t err;
-+ file_t gpg_file = netfs_node_netnode (np)->file;
-+ struct chroot_node *n = chroot_node (np);
-+ if (n->encrypt)
-+ {
-+ off_t newp;
-+
-+ err = io_seek (n->shadow_file, 0, SEEK_SET, &newp);
-+ if (err)
-+ return;
-+
-+ err = io_seek (gpg_file, 0, SEEK_SET, &newp);
-+ if (err)
-+ return;
-+ error (0, 0, "%s: encrypting %d", __FUNCTION__, n->shadow_file);
-+ err = gpg_encrypt (n->shadow_file, gpg_file);
-+ if (err)
-+ return;
-+
-+ mach_port_deallocate (mach_task_self (), n->shadow_file);
-+ }
-+}
-+
-+
-+error_t
-+netfs_get_dirents (struct iouser *cred, struct node *dir,
-+ int entry, int nentries, char **data,
-+ mach_msg_type_number_t *datacnt,
-+ vm_size_t bufsize, int *amt)
-+{
-+ error_t err;
-+ char *ptr;
-+ struct dirent *dent;
-+ err = dir_readdir (netfs_node_netnode (dir)->file, data, datacnt,
-+ entry, nentries, bufsize, amt);
-+ if (err)
-+ return err;
-+
-+ for (ptr = *data, dent = (struct dirent *) ptr;
-+ ptr - *data < *datacnt;
-+ ptr += dent->d_reclen, dent = (struct dirent *) ptr)
-+ {
-+ size_t len = strlen (dent->d_name);
-+ if (len > 4 && strcmp (&dent->d_name[len - 4], ".gpg") == 0)
-+ memset (&dent->d_name[len - 4], 0, 4);
-+ }
-+
-+ return 0;
-+}
-+
-+#define OPT_GPG_PROGRAM -1
-+
-+static struct argp_option options[] =
-+{
-+ {NULL, 0, NULL, 0, "How to encrypt:", 1},
-+ {"recipient", 'r', "NAME", 0, "Encrypt for user NAME. "
-+ "Can be given multiple times.", 1},
-+ {"symmetric", 'c', NULL, 0, "Encrypt with a password.", 1},
-+ {NULL, 0, NULL, 0, "Advanced options:", 2},
-+ {"gpg-program", OPT_GPG_PROGRAM, "FILENAME", 0,
-+ "Path to the GNU Privacy Guard executable ["GPG_DEFAULT_FILENAME"].", 2},
-+ {0}
-+};
-+
-+static char *args_doc = "";
-+static char *doc = "XXX."
-+"\vXXX.";
-+
-+static error_t
-+parse_opt (int key, char *arg, struct argp_state *state)
-+{
-+ error_t err;
-+ switch (key)
-+ {
-+ case 'r':
-+ err = argz_add (&recipients, &recipients_len, arg);
-+ if (err)
-+ error (1, err, "argz_add");
-+ break;
-+
-+ case 'c':
-+ symmetric = 1;
-+ break;
-+
-+ case OPT_GPG_PROGRAM:
-+ gpg_filename = arg;
-+ break;
-+
-+ default:
-+ return ARGP_ERR_UNKNOWN;
-+ }
-+ return 0;
-+}
-+
-+int
-+main (int argc, char **argv)
-+{
-+ error_t err;
-+ mach_port_t bootstrap;
-+
-+ struct argp argp =
-+ {
-+ .options = options,
-+ .parser = parse_opt,
-+ .args_doc = args_doc,
-+ .doc = doc,
-+ };
-+
-+ /* Parse our command line arguments (all none of them). */
-+ argp_parse (&argp, argc, argv, 0, 0, 0);
-+
-+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
-+ if (! MACH_PORT_VALID (bootstrap))
-+ error (1, 0, "Must be started as a translator");
-+
-+ gpg_file = file_name_lookup (gpg_filename, O_EXEC, 0);
-+ if (! MACH_PORT_VALID (gpg_file))
-+ error (1, errno, "%s", gpg_filename);
-+
-+ netfs_init ();
-+ chroot_init ();
-+
-+ /* Get our underlying node (we presume it's a directory) and use
-+ that to make the root node of the filesystem. */
-+ err = chroot_new_node (netfs_startup (bootstrap, O_READ), MACH_PORT_NULL,
-+ 0, sizeof (struct chroot_node), &netfs_root_node);
-+ if (err)
-+ error (5, err, "Cannot create root node");
-+
-+ err = netfs_validate_stat (netfs_root_node, 0);
-+ if (err)
-+ error (6, err, "Cannot stat underlying node");
-+
-+ netfs_root_node->nn_stat.st_mode &= ~(S_IPTRANS | S_IATRANS);
-+ netfs_root_node->nn_stat.st_mode |= S_IROOT;
-+ pthread_mutex_unlock (&netfs_root_node->lock);
-+
-+ chroot_node (netfs_root_node)->encrypt = 1; // XXX
-+ chroot_node (netfs_root_node)->shadow_file = MACH_PORT_NULL;
-+
-+ netfs_server_loop (); /* Never returns. */
-+
-+ /*NOTREACHED*/
-+ return 0;
-+}
-diff --git a/trans/identity.c b/trans/identity.c
-new file mode 100644
-index 0000000..2606c3e
---- /dev/null
-+++ b/trans/identity.c
-@@ -0,0 +1,127 @@
-+/* identity -- an translator interposing file RPCs.
-+ Copyright (C) 2016 Free Software Foundation, Inc.
-+
-+ 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, or (at
-+ your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful, but
-+ WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-+
-+#include <argz.h>
-+#include <argp.h>
-+#include <dirent.h>
-+#include <error.h>
-+#include <hurd/netfs.h>
-+#include <stddef.h>
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <string.h>
-+#include <fcntl.h>
-+#include <sys/mman.h>
-+#include <sys/stat.h>
-+#include <pthread.h>
-+#include <hurd/ihash.h>
-+#include <hurd/paths.h>
-+#include <sys/types.h>
-+#include <sys/wait.h>
-+#include <unistd.h>
-+
-+#include <version.h>
-+
-+#include "chroot.h"
-+
-+#include "libnetfs/fs_S.h"
-+#include "libnetfs/io_S.h"
-+#include "libnetfs/fsys_S.h"
-+#include "libports/notify_S.h"
-+#include "libports/interrupt_S.h"
-+
-+const char *argp_program_version = STANDARD_HURD_VERSION (identity);
-+
-+char *netfs_server_name = "identity";
-+char *netfs_server_version = HURD_VERSION;
-+int netfs_maxsymlinks = 16; /* arbitrary */
-+
-+struct chroot_node
-+{
-+};
-+
-+void
-+chroot_node_norefs (struct node *np)
-+{
-+}
-+
-+
-+static struct argp_option options[] =
-+{
-+ {0}
-+};
-+
-+static char *args_doc = "";
-+static char *doc = "XXX."
-+"\vXXX.";
-+
-+static error_t
-+parse_opt (int key, char *arg, struct argp_state *state)
-+{
-+ error_t err;
-+ switch (key)
-+ {
-+ default:
-+ return ARGP_ERR_UNKNOWN;
-+ }
-+ return 0;
-+}
-+
-+int
-+main (int argc, char **argv)
-+{
-+ error_t err;
-+ mach_port_t bootstrap;
-+
-+ struct argp argp =
-+ {
-+ .options = options,
-+ .parser = parse_opt,
-+ .args_doc = args_doc,
-+ .doc = doc,
-+ };
-+
-+ /* Parse our command line arguments (all none of them). */
-+ argp_parse (&argp, argc, argv, 0, 0, 0);
-+
-+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
-+ if (! MACH_PORT_VALID (bootstrap))
-+ error (1, 0, "Must be started as a translator");
-+
-+ netfs_init ();
-+ chroot_init ();
-+
-+ /* Get our underlying node (we presume it's a directory) and use
-+ that to make the root node of the filesystem. */
-+ err = chroot_new_node (netfs_startup (bootstrap, O_READ), MACH_PORT_NULL,
-+ 0, sizeof (struct chroot_node), &netfs_root_node);
-+ if (err)
-+ error (5, err, "Cannot create root node");
-+
-+ err = netfs_validate_stat (netfs_root_node, 0);
-+ if (err)
-+ error (6, err, "Cannot stat underlying node");
-+
-+ netfs_root_node->nn_stat.st_mode &= ~(S_IPTRANS | S_IATRANS);
-+ netfs_root_node->nn_stat.st_mode |= S_IROOT;
-+ pthread_mutex_unlock (&netfs_root_node->lock);
-+
-+ netfs_server_loop (); /* Never returns. */
-+
-+ /*NOTREACHED*/
-+ return 0;
-+}
-diff --git a/utils/Makefile b/utils/Makefile
-index 603b722..8685093 100644
---- a/utils/Makefile
-+++ b/utils/Makefile
-@@ -22,16 +22,16 @@ targets = shd ps settrans showtrans syncfs fsysopts \
- storeinfo login w uptime ids loginpr sush vmstat portinfo \
- devprobe vminfo addauth rmauth unsu setauth ftpcp ftpdir storecat \
- storeread msgport rpctrace mount gcore fakeauth fakeroot remap \
-- umount nullauth rpcscan
-+ umount nullauth rpcscan gpg-env
-
--special-targets = loginpr sush uptime fakeroot remap
-+special-targets = loginpr sush uptime fakeroot remap gpg-env
- SRCS = shd.c ps.c settrans.c syncfs.c showtrans.c addauth.c rmauth.c \
- fsysopts.c storeinfo.c login.c loginpr.sh sush.sh w.c \
- uptime.sh psout.c ids.c vmstat.c portinfo.c devprobe.c vminfo.c \
- parse.c frobauth.c frobauth-mod.c setauth.c pids.c nonsugid.c \
- unsu.c ftpcp.c ftpdir.c storeread.c storecat.c msgport.c \
- rpctrace.c mount.c gcore.c fakeauth.c fakeroot.sh remap.sh \
-- nullauth.c match-options.c msgids.c rpcscan.c
-+ nullauth.c match-options.c msgids.c rpcscan.c gpg-env.sh
-
- OBJS = $(filter-out %.sh,$(SRCS:.c=.o))
- HURDLIBS = ps ihash store fshelp ports ftpconn shouldbeinlibc
-diff --git a/utils/gpg-env.sh b/utils/gpg-env.sh
-new file mode 100755
-index 0000000..4e4128b
---- /dev/null
-+++ b/utils/gpg-env.sh
-@@ -0,0 +1,121 @@
-+#!/bin/sh
-+# Execute a command in an environment which encrypts, decrypts, and
-+# verifies files on demand.
-+#
-+# Copyright (C) 2002, 2013, 2016 Free Software Foundation, Inc.
-+#
-+# This file is part of the GNU Hurd.
-+#
-+# The GNU Hurd 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, or (at
-+# your option) any later version.
-+#
-+# The GNU Hurd 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.
-+#
-+
-+USAGE="Usage:
-+ [$0] encrypt for RECIPIENT [RECIPIENT...] -- [OPTION...] [COMMAND...]
-+ [$0] encrypt with password [OPTION...] [COMMAND...]
-+ [$0] decrypt [OPTION...] [COMMAND...]
-+ [$0] decrypt with password [OPTION...] [COMMAND...]
-+ [$0] verify [OPTION...] [COMMAND...]"
-+DOC="Execute COMMAND in an environment where files are automatically
-+encrypted, decrypted and verified."
-+
-+help()
-+{
-+ [ "$1" ] && echo "$1
-+"
-+ echo "$USAGE"
-+ echo "$DOC"
-+ echo ""
-+ echo " -?, --help Give this help list"
-+ echo " --usage Give a short usage message"
-+ echo " -V, --version Print program version"
-+ [ "$1" ] && exit 1 || exit 0
-+}
-+
-+if [ "$(basename $0)" = "gpg-env.sh" ] \
-+ || [ "$(basename $0)" = "gpg-env" ]; then
-+ ACTION="$1"
-+ if [ ! "$ACTION" ]; then
-+ help "No action given."
-+ fi
-+ shift
-+else
-+ ACTION="$(basename $0)"
-+fi
-+
-+case "$ACTION" in
-+ "encrypt") ;;
-+ "decrypt") ;;
-+ "verify") ;;
-+ *)
-+ help "Invalid action '$ACTION'."
-+esac
-+
-+ENCRYPT=""
-+if [ "$ACTION" = "encrypt" ]; then
-+ if [ "$1" = "with" ] && [ "$2" = "password" ]; then
-+ ENCRYPT="--symmetric"
-+ shift 2
-+ elif [ "$1" = "for" ]; then
-+ shift
-+ while [ "$#" -gt 0 ] && [ "x$1" != "x--" ]; do
-+ ENCRYPT="$ENCRYPT --recipient $1"
-+ shift
-+ done
-+ if [ "$ENCRYPT" = "" ]; then
-+ echo "No recipients given."
-+ exit 1
-+ fi
-+ if [ "x$1" = "x--" ]; then
-+ shift
-+ elif [ "$#" -eq 0 ]; then
-+ # it's ok if there are no more arguments
-+ :
-+ else
-+ echo "Recipient list must be terminated using '--'."
-+ exit 1
-+ fi
-+ fi
-+fi
-+
-+while [ "$#" -gt 0 ]; do
-+ case "$1" in
-+ --help|"-?")
-+ help
-+ ;;
-+ --usage)
-+ echo "$USAGE"
-+ echo "Options: [-V?] [--help] [--usage] [--version]"
-+ exit 0;;
-+ --version|-V)
-+ echo "STANDARD_HURD_VERSION_gpg-env_"; exit 0;;
-+ --)
-+ shift
-+ break
-+ ;;
-+ *)
-+ break
-+ esac
-+done
-+
-+if [ $# -eq 0 ]; then
-+ set -- ${SHELL:-/bin/sh}
-+fi
-+
-+# We exec settrans, which execs the target command in the chroot
-+# context provided by /hurd/gpg.
-+exec /bin/settrans \
-+ --chroot-chdir "$PWD" \
-+ --chroot "$@" -- \
-+ / /hurd/gpg $ENCRYPT
---
-2.1.4
-
diff --git a/debian/patches/series b/debian/patches/series
index 5caa5598..993b4fb4 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -36,4 +36,3 @@ exec_filename0002-Add-a-file_exec_file_name-RPC.patch
exec_filename0003-Use-the-new-_hurd_exec_file_name-function.patch
exec_filename0004-This-patch-is-an-amendment-of-exec_filename_exec.pat.patch
flavio0001-Use-libihash-to-store-directory-entries-in-ftpfs.patch
-gpg0001-trans-add-transparent-GnuPG-translator.patch