[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[hurd] 01/07: New upstream snapshot
From: |
Samuel Thibault |
Subject: |
[hurd] 01/07: New upstream snapshot |
Date: |
Mon, 16 Sep 2013 07:41:30 +0000 |
This is an automated email from the git hooks/post-receive script.
sthibault pushed a commit to branch master
in repository hurd.
commit ae796083c6e7862929375c773080f8103905fe82
Author: Samuel Thibault <address@hidden>
Date: Mon Sep 16 00:17:32 2013 +0000
New upstream snapshot
---
TODO | 4 -
config.make.in | 13 +
configure.ac | 15 +-
console-client/Makefile | 4 +-
console-client/console.c | 115 ++-
console/pager.c | 10 +-
daemons/console-run.c | 5 +-
devnode/devnode.c | 10 +
exec/Makefile | 12 +-
exec/exec.c | 933 ++-----------------
exec/main.c | 3 +-
exec/priv.h | 43 +-
ext2fs/balloc.c | 31 +-
ext2fs/ext2fs.c | 6 +-
ext2fs/ext2fs.h | 145 ++-
ext2fs/getblk.c | 21 +-
ext2fs/hyper.c | 35 +-
ext2fs/ialloc.c | 37 +-
ext2fs/inode.c | 40 +-
ext2fs/pager.c | 467 +++++++++-
ext2fs/pokel.c | 39 +-
ext2fs/truncate.c | 9 +-
fatfs/pager.c | 11 +-
hurd/fsys.defs | 22 +-
hurd/fsys_reply.defs | 12 +-
hurd/process.defs | 32 +-
hurd/process_reply.defs | 134 ++-
hurd/process_request.defs | 33 +-
include/pids.h | 29 +
init/init.c | 24 +-
isofs/pager.c | 12 +-
libdiskfs/Makefile | 5 +-
libdiskfs/boot-start.c | 3 +-
libdiskfs/dead-name.c | 4 +-
libdiskfs/dir-lookup.c | 26 +-
libdiskfs/disk-pager.c | 6 +-
libdiskfs/diskfs-pager.h | 3 +-
libdiskfs/diskfs.h | 11 +-
libdiskfs/file-set-trans.c | 19 +-
libdiskfs/fsys-get-children.c | 99 ++
libdiskfs/fsys-get-source.c | 34 +
libdiskfs/fsys-getroot.c | 3 +-
libdiskfs/get-source.c | 28 +
libdiskfs/init-startup.c | 10 +-
libdiskfs/peropen-make.c | 8 +
libdiskfs/peropen-rele.c | 1 +
libfshelp/Makefile | 3 +-
libfshelp/fshelp.h | 33 +-
libfshelp/translator-list.c | 169 ++++
libihash/ihash.h | 17 +
libnetfs/Makefile | 7 +-
{libdiskfs => libnetfs}/dead-name.c | 12 +-
libnetfs/dir-lookup.c | 26 +-
libnetfs/file-get-transcntl.c | 52 ++
libnetfs/file-get-translator.c | 14 +
libnetfs/file-set-translator.c | 17 +-
libnetfs/fsstubs.c | 8 -
libnetfs/fsys-get-children.c | 112 +++
libnetfs/fsys-get-source.c | 34 +
libnetfs/fsys-getroot.c | 6 +-
libnetfs/get-source.c | 28 +
libnetfs/init-startup.c | 14 +
libnetfs/make-peropen.c | 8 +
libnetfs/netfs.h | 10 +-
libnetfs/release-peropen.c | 1 +
libpager/data-request.c | 3 +-
libpager/data-return.c | 79 +-
libpager/pager-create.c | 4 +-
libpager/pager.h | 23 +-
libpager/priv.h | 1 +
libshouldbeinlibc/Makefile | 4 +-
libshouldbeinlibc/nullauth.c | 47 +
libshouldbeinlibc/nullauth.h | 31 +
libstore/Makefile | 4 -
libstore/crypt.h | 12 +
libstore/do-bunzip2.c | 1745 +++++++++++++++++++++++++++++++++++
libstore/gzip.h | 315 +++++++
libstore/inflate.c | 954 +++++++++++++++++++
libstore/tailor.h | 14 +
libstore/unzip.c | 199 ++++
libstore/util.c | 272 ++++++
libtrivfs/Makefile | 5 +-
libtrivfs/fsys-get-children.c | 35 +
libtrivfs/fsys-get-source.c | 33 +
libtrivfs/get-source.c | 28 +
libtrivfs/startup.c | 19 +
libtrivfs/trivfs.h | 8 +-
mach-defpager/main.c | 13 +
pfinet/main.c | 3 +-
pfinet/tunnel.c | 13 +-
proc/info.c | 2 +-
proc/main.c | 3 +-
proc/mgt.c | 77 +-
proc/pgrp.c | 7 +-
proc/proc.h | 6 +-
procfs/ChangeLog | 6 +
procfs/main.c | 165 +++-
procfs/process.c | 24 +-
procfs/rootdir.c | 49 +-
storeio/pager.c | 9 +-
sutils/fstab.c | 115 +--
tmpfs/pager-stubs.c | 8 +
tmpfs/tmpfs.c | 6 +
trans/Makefile | 8 +-
trans/mtab.c | 800 ++++++++++++++++
trans/null.c | 5 +
trans/symlink.c | 28 +
ufs/pager.c | 11 +-
utils/Makefile | 13 +-
utils/fakeroot.sh | 10 +-
utils/match-options.c | 68 ++
utils/match-options.h | 33 +
utils/mount.c | 122 ++-
utils/nullauth.c | 90 ++
utils/remap.sh | 8 +-
utils/umount.c | 357 +++++++
116 files changed, 7785 insertions(+), 1246 deletions(-)
diff --git a/TODO b/TODO
index b541f38..bf37fb2 100644
--- a/TODO
+++ b/TODO
@@ -173,10 +173,6 @@ See `tasks', the exported task list.
3: when a session leader exits, the association has to be torn
down; bsd does SIGHUP + drain + revoke.)
-** exec:
-*** either resurrect or excise BFD exec server
- (needs stdio magic converted to use libio when libc converts)
-
** proc:
*** Add a version of proc_wait usable by non-parent processes, and use it in
gdb; maybe just a flag WNOREAP to proc_wait that doesn't reap and allows
diff --git a/config.make.in b/config.make.in
index b8002a1..4d2abcc 100644
--- a/config.make.in
+++ b/config.make.in
@@ -30,6 +30,7 @@ sysconfdir = @sysconfdir@
localstatedir = @localstatedir@
sharedstatedir = @sharedstatedir@
datadir = @datadir@
+datarootdir = @datarootdir@
# All of those directories together:
installationdirlist = $(hurddir) $(libdir) $(bindir) $(sbindir) \
@@ -48,6 +49,8 @@ MIG = @MIG@
MIGCOM = $(MIG) -cc cat - /dev/null
AWK = @AWK@
SED = @SED@
+LEX = @LEX@
+YACC = @YACC@
# Compilation flags. Append these to the definitions already made by
# the specific Makefile.
@@ -77,6 +80,16 @@ X11_LIBS = @X11_LIBS@
XKB_BASE = @XKB_BASE@
X11_KEYSYMDEF_H = @X11_KEYSYMDEF_H@
+# How to compile and link against libdaemon.
+HAVE_DAEMON = @HAVE_DAEMON@
+libdaemon_CFLAGS = @libdaemon_CFLAGS@
+libdaemon_LIBS = @libdaemon_LIBS@
+
+# How to compile and link against libblkid.
+HAVE_BLKID = @HAVE_BLKID@
+libblkid_CFLAGS = @libblkid_CFLAGS@
+libblkid_LIBS = @libblkid_LIBS@
+
# Whether Sun RPC support is available.
HAVE_SUN_RPC = @HAVE_SUN_RPC@
diff --git a/configure.ac b/configure.ac
index 31e48ef..5340b50 100644
--- a/configure.ac
+++ b/configure.ac
@@ -246,8 +246,9 @@ PKG_CHECK_MODULES([X11], [x11 xproto],
AS_IF([test $pkg_failed = no],
[XKB_BASE="$pkg_cv_XKB_BASE"
AC_MSG_RESULT([$XKB_BASE])],
- [XKB_BASE="$datadir/share/X11/xkb"
+ [XKB_BASE="$datadir/X11/xkb"
AC_MSG_RESULT([(default) $XKB_BASE])])
+ pkg_failed=no
AC_MSG_CHECKING([for X11 prefix])
_PKG_CONFIG([X11_PREFIX], [variable=prefix], [x11])
AS_IF([test $pkg_failed = no],
@@ -296,6 +297,18 @@ else
echo ${file}:build.mk.in; done`"
fi
+PKG_CHECK_MODULES([libdaemon], [libdaemon],
+ [AC_DEFINE([HAVE_DAEMON], [1], [Use libdaemon])],
+ [true])
+AC_SUBST([libdaemon_LIBS])
+AC_SUBST([libdaemon_CFLAGS])
+
+PKG_CHECK_MODULES([libblkid], [blkid],
+ [AC_DEFINE([HAVE_BLKID], [1], [Use libblkid])],
+ [true])
+AC_SUBST([libblkid_LIBS])
+AC_SUBST([libblkid_CFLAGS])
+
AC_CONFIG_FILES([config.make ${makefiles}])
AC_OUTPUT
diff --git a/console-client/Makefile b/console-client/Makefile
index 69a7e37..65a04e0 100644
--- a/console-client/Makefile
+++ b/console-client/Makefile
@@ -37,11 +37,11 @@ SRCS = $(CONSOLE_SRCS) \
VPATH += $(srcdir)/xkb
OBJS = $(addsuffix .o,$(basename $(notdir $(SRCS)))) kdioctlServer.o
HURDLIBS = cons ports netfs fshelp iohelp ihash shouldbeinlibc
-LDLIBS = -ldl -lpthread
+LDLIBS = -ldl -lpthread $(libdaemon_LIBS)
module-dir = $(libdir)/hurd/console
console-LDFLAGS = -Wl,-E
-CPPFLAGS += -I$(CURDIR)/xkb -I$(srcdir)/xkb
+CPPFLAGS += -I$(CURDIR)/xkb -I$(srcdir)/xkb $(libdaemon_CFLAGS)
LFLAGS = -i
YFLAGS = -by
XKB_DATA_FILES = keymap/hurd types/hurd symbols/hurd
diff --git a/console-client/console.c b/console-client/console.c
index 7c9a880..f995ca2 100644
--- a/console-client/console.c
+++ b/console-client/console.c
@@ -26,6 +26,9 @@
#include <assert.h>
#include <pthread.h>
+#if HAVE_DAEMON
+#include <libdaemon/daemon.h>
+#endif
#include <hurd/console.h>
#include <hurd/cons.h>
@@ -61,6 +64,8 @@ static cons_t saved_cons;
set. */
static char *console_node;
+/* If set, the client will daemonize. */
+static int daemonize;
/* Callbacks for input source drivers. */
@@ -516,6 +521,8 @@ cons_vcons_set_mousecursor_status (vcons_t vcons, int
status)
}
+#define DAEMONIZE_KEY 0x80 /* !isascii (DAEMONIZE_KEY), so no short option. */
+
/* Console-specific options. */
static const struct argp_option
options[] =
@@ -524,6 +531,9 @@ options[] =
{"driver", 'd', "NAME", 0, "Add driver NAME to the console" },
{"console-node", 'c', "FILE", OPTION_ARG_OPTIONAL,
"Set a translator on the node FILE (default: " DEFAULT_CONSOLE_NODE ")" },
+#if HAVE_DAEMON
+ {"daemonize", DAEMONIZE_KEY, NULL, 0, "daemonize the console client"},
+#endif
{0}
};
@@ -577,7 +587,11 @@ parse_opt (int key, char *arg, struct argp_state *state)
if (!console_node)
return ENOMEM;
break;
-
+
+ case DAEMONIZE_KEY:
+ daemonize = 1;
+ break;
+
case ARGP_KEY_SUCCESS:
if (!devcount)
{
@@ -597,6 +611,31 @@ static const struct argp_child startup_children[] =
{ { &cons_startup_argp }, { 0 } };
static struct argp startup_argp = {options, parse_opt, 0,
0, startup_children};
+#if HAVE_DAEMON
+#define daemon_error(status, errnum, format, args...) \
+ do \
+ { \
+ if (daemonize) \
+ { \
+ if (errnum) \
+ daemon_log (LOG_ERR, format ": %s", ##args, \
+ strerror(errnum)); \
+ else \
+ daemon_log (LOG_ERR, format, ##args); \
+ if (status) \
+ { \
+ /* Signal parent. */ \
+ daemon_retval_send (status); \
+ return 0; \
+ } \
+ } \
+ else \
+ error (status, errnum, format, ##args); \
+ } \
+ while (0);
+#else
+#define daemon_error error
+#endif
int
main (int argc, char *argv[])
@@ -609,9 +648,69 @@ main (int argc, char *argv[])
/* Parse our command line. This shouldn't ever return an error. */
argp_parse (&startup_argp, argc, argv, ARGP_IN_ORDER, 0, 0);
+#if HAVE_DAEMON
+ if (daemonize)
+ {
+ /* Reset signal handlers. */
+ if (daemon_reset_sigs (-1) < 0)
+ error (1, errno, "Failed to reset all signal handlers");
+
+ /* Unblock signals. */
+ if (daemon_unblock_sigs (-1) < 0)
+ error (1, errno, "Failed to unblock all signals");
+
+ /* Set indetification string for the daemon for both syslog and
+ PID file. */
+ daemon_pid_file_ident = daemon_log_ident = \
+ daemon_ident_from_argv0 (argv[0]);
+
+ /* Check that the daemon is not run twice at the same time. */
+ pid_t pid;
+ if ((pid = daemon_pid_file_is_running ()) >= 0)
+ error (1, errno, "Daemon already running on PID file %u", pid);
+
+ /* Prepare for return value passing from the initialization
+ procedure of the daemon process. */
+ if (daemon_retval_init () < 0)
+ error (1, errno, "Failed to create pipe.");
+
+ /* Do the fork. */
+ if ((pid = daemon_fork ()) < 0)
+ {
+ /* Exit on error. */
+ daemon_retval_done ();
+ error (1, errno, "Failed to fork");
+ }
+ else if (pid)
+ {
+ /* The parent. */
+ int ret;
+
+ /* Wait for 20 seconds for the return value passed from the
+ daemon process. . */
+ if ((ret = daemon_retval_wait (20)) < 0)
+ error (1, errno,
+ "Could not receive return value from daemon process");
+
+ return ret;
+ }
+ else
+ {
+ /* The daemon. */
+ /* Close FDs. */
+ if (daemon_close_all (-1) < 0)
+ daemon_error (1, errno, "Failed to close all file descriptors");
+
+ /* Create the PID file. */
+ if (daemon_pid_file_create () < 0)
+ daemon_error (2, errno, "Could not create PID file");
+ }
+ }
+#endif /* HAVE_DAEMON */
+
err = driver_start (&errname);
if (err)
- error (1, err, "Starting driver %s failed", errname);
+ daemon_error (1, err, "Starting driver %s failed", errname);
pthread_mutex_init (&global_lock, NULL);
@@ -619,19 +718,25 @@ main (int argc, char *argv[])
if (err)
{
driver_fini ();
- error (1, err, "Console library initialization failed");
+ daemon_error (1, err, "Console library initialization failed");
}
err = timer_init ();
if (err)
{
driver_fini ();
- error (1, err, "Timer thread initialization failed");
+ daemon_error (1, err, "Timer thread initialization failed");
}
if (console_node)
console_setup_node (console_node);
-
+
+#if HAVE_DAEMON
+ if (daemonize)
+ /* Signal parent that all went well. */
+ daemon_retval_send(0);
+#endif
+
cons_server_loop ();
/* Never reached. */
diff --git a/console/pager.c b/console/pager.c
index 781ba35..4d0c5cd 100644
--- a/console/pager.c
+++ b/console/pager.c
@@ -95,6 +95,14 @@ pager_unlock_page (struct user_pager_info *pager,
}
+void
+pager_notify_evict (struct user_pager_info *pager,
+ vm_offset_t page)
+{
+ assert (!"unrequested notification on eviction");
+}
+
+
/* Tell how big the file is. */
error_t
pager_report_extent (struct user_pager_info *upi,
@@ -170,7 +178,7 @@ user_pager_create (struct user_pager *user_pager, unsigned
int npages,
/* XXX Are the values 1 and MEMORY_OBJECT_COPY_DELAY correct? */
user_pager->pager = pager_create (upi, pager_bucket,
- 1, MEMORY_OBJECT_COPY_DELAY);
+ 1, MEMORY_OBJECT_COPY_DELAY, 0);
if (!user_pager->pager)
{
free (upi);
diff --git a/daemons/console-run.c b/daemons/console-run.c
index fb879e5..e1bfe64 100644
--- a/daemons/console-run.c
+++ b/daemons/console-run.c
@@ -217,8 +217,9 @@ open_console (char **namep)
dup2 (0, 1);
dup2 (0, 2);
- if (setsid () == -1)
- error (0, errno, "setsid");
+ if (getsid (0) != getpid ())
+ if (setsid () == -1)
+ error (0, errno, "setsid");
/* Set the console to our pgrp. */
tcsetpgrp (0, getpid ());
diff --git a/devnode/devnode.c b/devnode/devnode.c
index 50011aa..218b308 100644
--- a/devnode/devnode.c
+++ b/devnode/devnode.c
@@ -164,6 +164,16 @@ ds_device_open (mach_port_t master_port, mach_port_t
reply_port,
|| device_name == NULL)
return D_NO_SUCH_DEVICE;
+ if (master_file != NULL)
+ {
+ if (master_device != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), master_device);
+
+ master_device = file_name_lookup (master_file, 0, 0);
+ if (master_device == MACH_PORT_NULL)
+ error (1, errno, "file_name_lookup");
+ }
+
err = device_open (master_device, mode, device_name, device);
*devicetype = MACH_MSG_TYPE_MOVE_SEND;
return err;
diff --git a/exec/Makefile b/exec/Makefile
index 3fc8273..890ee4b 100644
--- a/exec/Makefile
+++ b/exec/Makefile
@@ -20,15 +20,9 @@
dir := exec
makemode := server
-SRCS = exec.c main.c hashexec.c hostarch.c \
- $(gzip-sources) $(bzip2-sources)
+SRCS = exec.c main.c hashexec.c hostarch.c
OBJS = main.o hostarch.o exec.o hashexec.o \
- execServer.o exec_startupServer.o \
- $(gzip-objects) $(bzip2-objects)
-gzip-sources = unzip.c util.c inflate.c
-gzip-objects = $(gzip-sources:%.c=%.o)
-bzip2-sources = do-bunzip2.c
-bzip2-objects = $(bzip2-sources:%.c=%.o)
+ execServer.o exec_startupServer.o
target = exec
#targets = exec exec.static
@@ -40,6 +34,6 @@ exec-MIGSFLAGS = -imacros $(srcdir)/execmutations.h
include ../Makeconf
-CPPFLAGS += -DGZIP -DBZIP2 # -DBFD
+CPPFLAGS += # -DBFD
exec.static exec: $(OBJS) $(library_deps)
diff --git a/exec/exec.c b/exec/exec.c
index 30a5e00..fad9492 100644
--- a/exec/exec.c
+++ b/exec/exec.c
@@ -4,16 +4,6 @@
Written by Roland McGrath.
Can exec ELF format directly.
- #ifdef GZIP
- Can gunzip executables into core on the fly.
- #endif
- #ifdef BFD
- Can exec any executable format the BFD library understands
- to be for this flavor of machine.
- #endif
- #ifdef BZIP2
- Can bunzip2 executables into core on the fly.
- #endif
This file is part of the GNU Hurd.
@@ -50,70 +40,8 @@ size_t std_nports, std_nints;
pthread_rwlock_t std_lock = PTHREAD_RWLOCK_INITIALIZER;
-#ifdef BFD
-/* Return a Hurd error code corresponding to the most recent BFD error. */
-static error_t
-b2he (error_t deflt)
-{
- switch (bfd_get_error ())
- {
- case bfd_error_system_call:
- return errno;
-
- case bfd_error_no_memory:
- return ENOMEM;
-
- default:
- return deflt;
- }
-}
-#else
#define b2he() a2he (errno)
-#endif
-#ifdef GZIP
-static void check_gzip (struct execdata *);
-#endif
-
-#ifdef BZIP2
-static void check_bzip2 (struct execdata *);
-#endif
-
-#ifdef BFD
-
-/* Check a section, updating the `locations' vector [BFD]. */
-static void
-check_section (bfd *bfd, asection *sec, void *userdata)
-{
- struct execdata *u = userdata;
- static const union
- {
- char string[8];
- unsigned int quadword __attribute__ ((mode (DI)));
- } interp = { string: ".interp" };
-
- if (u->error)
- return;
-
- /* Fast strcmp for this 8-byte constant string. */
- if (*(const __typeof (interp.quadword) *) sec->name == interp.quadword)
- u->interp.section = sec;
-
- if (!(sec->flags & (SEC_ALLOC|SEC_LOAD)) ||
- (sec->flags & SEC_NEVER_LOAD))
- /* Nothing to do for this section. */
- return;
-
- if (sec->flags & SEC_LOAD)
- {
- u->info.bfd_locations[sec->index] = sec->filepos;
- if ((off_t) sec->filepos < 0 || (off_t) sec->filepos > u->file_size)
- u->error = ENOEXEC;
- }
-}
-#endif
-
-
/* Zero the specified region but don't crash the server if it faults. */
#include <hurd/sigpreempt.h>
@@ -135,69 +63,45 @@ load_section (void *section, struct execdata *u)
vm_prot_t vm_prot;
int anywhere;
vm_address_t mask = 0;
-#ifdef BFD
- asection *const sec = section;
-#endif
const ElfW(Phdr) *const ph = section;
if (u->error)
return;
-#ifdef BFD
- if (u->bfd && sec->flags & SEC_NEVER_LOAD)
- /* Nothing to do for this section. */
- return;
-#endif
-
vm_prot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
-#ifdef BFD
- if (u->bfd)
- {
- addr = (vm_address_t) sec->vma;
- filepos = u->info.bfd_locations[sec->index];
- memsz = sec->_raw_size;
- filesz = (sec->flags & SEC_LOAD) ? memsz : 0;
- if (sec->flags & (SEC_READONLY|SEC_ROM))
- vm_prot &= ~VM_PROT_WRITE;
- anywhere = 0;
- }
+ addr = ph->p_vaddr & ~(ph->p_align - 1);
+ memsz = ph->p_vaddr + ph->p_memsz - addr;
+ filepos = ph->p_offset & ~(ph->p_align - 1);
+ filesz = ph->p_offset + ph->p_filesz - filepos;
+ if ((ph->p_flags & PF_R) == 0)
+ vm_prot &= ~VM_PROT_READ;
+ if ((ph->p_flags & PF_W) == 0)
+ vm_prot &= ~VM_PROT_WRITE;
+ if ((ph->p_flags & PF_X) == 0)
+ vm_prot &= ~VM_PROT_EXECUTE;
+ anywhere = u->info.elf.anywhere;
+ if (! anywhere)
+ addr += u->info.elf.loadbase;
else
-#endif
- {
- addr = ph->p_vaddr & ~(ph->p_align - 1);
- memsz = ph->p_vaddr + ph->p_memsz - addr;
- filepos = ph->p_offset & ~(ph->p_align - 1);
- filesz = ph->p_offset + ph->p_filesz - filepos;
- if ((ph->p_flags & PF_R) == 0)
- vm_prot &= ~VM_PROT_READ;
- if ((ph->p_flags & PF_W) == 0)
- vm_prot &= ~VM_PROT_WRITE;
- if ((ph->p_flags & PF_X) == 0)
- vm_prot &= ~VM_PROT_EXECUTE;
- anywhere = u->info.elf.anywhere;
- if (! anywhere)
- addr += u->info.elf.loadbase;
- else
#if 0
- switch (elf_machine)
- {
- case EM_386:
- case EM_486:
- /* On the i386, programs normally load at 0x08000000, and
- expect their data segment to be able to grow dynamically
- upward from its start near that address. We need to make
- sure that the dynamic linker is not mapped in a conflicting
- address. */
- /* mask = 0xf8000000UL; */ /* XXX */
- break;
- default:
- break;
- }
+ switch (elf_machine)
+ {
+ case EM_386:
+ case EM_486:
+ /* On the i386, programs normally load at 0x08000000, and
+ expect their data segment to be able to grow dynamically
+ upward from its start near that address. We need to make
+ sure that the dynamic linker is not mapped in a conflicting
+ address. */
+ /* mask = 0xf8000000UL; */ /* XXX */
+ break;
+ default:
+ break;
+ }
#endif
- if (anywhere && addr < vm_page_size)
- addr = vm_page_size;
- }
+ if (anywhere && addr < vm_page_size)
+ addr = vm_page_size;
if (memsz == 0)
/* This section is empty; ignore it. */
@@ -289,6 +193,17 @@ load_section (void *section, struct execdata *u)
}
}
+ /* If this segment is executable, adjust start_code and end_code
+ so that this mapping is within that range. */
+ if (vm_prot & VM_PROT_EXECUTE)
+ {
+ if (u->start_code == 0 || u->start_code > addr)
+ u->start_code = addr;
+
+ if (u->end_code < addr + memsz)
+ u->end_code = addr + memsz;
+ }
+
if (mapstart > addr)
{
/* We must read and copy in the space in the section before the
@@ -502,16 +417,6 @@ map (struct execdata *e, off_t posn, size_t len)
return map_buffer (e) + offset;
}
-
-/* Initialize E's stdio stream. */
-static void prepare_stream (struct execdata *e);
-
-/* Point the stream at the buffer of file data in E->file_data. */
-static void prepare_in_memory (struct execdata *e);
-
-
-#ifndef EXECDATA_STREAM
-
/* We don't have a stdio stream, but we have a mapping window
we need to initialize. */
static void
@@ -521,199 +426,7 @@ prepare_stream (struct execdata *e)
e->map_vsize = e->map_fsize = 0;
e->map_filepos = 0;
}
-
-static void prepare_in_memory (struct execdata *e)
-{
- prepare_stream(e);
-}
-
-#else
-
-#ifdef _STDIO_USES_IOSTREAM
-
-# error implement me for libio!
-
-#else /* old GNU stdio */
-
-#if 0
-void *
-map (struct execdata *e, off_t posn, size_t len)
-{
- FILE *f = &e->stream;
- const size_t size = e->file_size;
- size_t offset;
-
- if ((f->__offset & ~(f->__bufsize - 1)) == (posn & ~(f->__bufsize - 1)) &&
- f->__buffer + (posn + len - f->__offset) < f->__get_limit)
- /* The current mapping window covers it. */
- offset = posn & (f->__bufsize - 1);
- else if (e->file_data != NULL)
- {
- /* The current "mapping window" is in fact the whole file contents.
- So if it's not in there, it's not in there. */
- f->__eof = 1;
- return NULL;
- }
- else if (e->filemap == MACH_PORT_NULL)
- {
- /* No mapping for the file. Read the data by RPC. */
- char *buffer = f->__buffer;
- mach_msg_type_number_t nread = f->__bufsize;
- /* Read as much as we can get into the buffer right now. */
- e->error = io_read (e->file, &buffer, &nread, posn, round_page (len));
- if (e->error)
- {
- errno = e->error;
- f->__error = 1;
- return NULL;
- }
- if (buffer != f->__buffer)
- {
- /* The data was returned out of line. Discard the old buffer. */
- if (f->__bufsize != 0)
- munmap (f->__buffer, f->__bufsize);
- f->__buffer = buffer;
- f->__bufsize = round_page (nread);
- }
-
- f->__offset = posn;
- f->__get_limit = f->__buffer + nread;
- offset = 0;
- }
- else
- {
- /* Deallocate the old mapping area. */
- if (f->__buffer != NULL)
- munmap (f->__buffer, f->__bufsize);
- f->__buffer = NULL;
-
- /* Make sure our mapping is page-aligned in the file. */
- offset = posn & (vm_page_size - 1);
- f->__offset = trunc_page (posn);
- f->__bufsize = round_page (posn + len) - f->__offset;
-
- /* Map the data from the file. */
- if (vm_map (mach_task_self (),
- (vm_address_t *) &f->__buffer, f->__bufsize, 0, 1,
- e->filemap, f->__offset, 1, VM_PROT_READ, VM_PROT_READ,
- VM_INHERIT_NONE))
- {
- errno = e->error = EIO;
- f->__error = 1;
- return NULL;
- }
-
- if (e->cntl)
- e->cntl->accessed = 1;
-
- if (f->__offset + f->__bufsize > size)
- f->__get_limit = f->__buffer + (size - f->__offset);
- else
- f->__get_limit = f->__buffer + f->__bufsize;
- }
-
- f->__target = f->__offset;
- f->__bufp = f->__buffer + offset;
-
- if (f->__bufp + len > f->__get_limit)
- {
- f->__eof = 1;
- return NULL;
- }
-
- return f->__bufp;
-}
-#endif
-
-/* stdio input-room function.
- XXX/fault in the stdio case (or libio replacement), i.e. for bfd
- (if ever revived), need to check all the mapping fault issues */
-static int
-input_room (FILE *f)
-{
- struct execdata *e = f->__cookie;
- char *p = map (e, f->__target, 1);
- if (p == NULL)
- {
- (e->error ? f->__error : f->__eof) = 1;
- return EOF;
- }
-
- f->__target = f->__offset;
- f->__bufp = p;
-
- return (unsigned char) *f->__bufp++;
-}
-
-static int
-close_exec_stream (void *cookie)
-{
- struct execdata *e = cookie;
-
- if (e->stream.__buffer != NULL)
- munmap (e->stream.__buffer, e->stream.__bufsize);
-
- return 0;
-}
-
-/* stdio seek function. */
-static int
-fake_seek (void *cookie, fpos_t *pos, int whence)
-{
- struct execdata *e = cookie;
-
- /* Set __target to match the specifed seek location */
- switch (whence)
- {
- case SEEK_END:
- e->stream.__target = e->file_size + *pos;
- break;
-
- case SEEK_CUR:
- e->stream.__target += *pos;
- break;
-
- case SEEK_SET:
- e->stream.__target = *pos;
- break;
- }
- *pos = e->stream.__target;
- return 0;
-}
-
-/* Initialize E's stdio stream. */
-static void
-prepare_stream (struct execdata *e)
-{
- memset (&e->stream, 0, sizeof (e->stream));
- e->stream.__magic = _IOMAGIC;
- e->stream.__mode.__read = 1;
- e->stream.__userbuf = 1;
- e->stream.__room_funcs.__input = input_room;
- e->stream.__io_funcs.seek = fake_seek;
- e->stream.__io_funcs.close = close_exec_stream;
- e->stream.__cookie = e;
- e->stream.__seen = 1;
-}
-
-/* Point the stream at the buffer of file data. */
-static void
-prepare_in_memory (struct execdata *e)
-{
- memset (&e->stream, 0, sizeof (e->stream));
- e->stream.__magic = _IOMAGIC;
- e->stream.__mode.__read = 1;
- e->stream.__buffer = e->file_data;
- e->stream.__bufsize = e->file_size;
- e->stream.__get_limit = e->stream.__buffer + e->stream.__bufsize;
- e->stream.__bufp = e->stream.__buffer;
- e->stream.__seen = 1;
-}
-#endif
-
-#endif
-
/* Prepare to check and load FILE. */
static void
prepare (file_t file, struct execdata *e)
@@ -722,9 +435,6 @@ prepare (file_t file, struct execdata *e)
e->file = file;
-#ifdef BFD
- e->bfd = NULL;
-#endif
e->file_data = NULL;
e->cntl = NULL;
e->filemap = MACH_PORT_NULL;
@@ -732,6 +442,9 @@ prepare (file_t file, struct execdata *e)
e->interp.section = NULL;
+ e->start_code = 0;
+ e->end_code = 0;
+
/* Initialize E's stdio stream. */
prepare_stream (e);
@@ -801,42 +514,6 @@ prepare (file_t file, struct execdata *e)
}
}
-/* Check the magic number, etc. of the file.
- On successful return, the caller must allocate the
- E->locations vector, and map check_section over the BFD. */
-
-#ifdef BFD
-static void
-check_bfd (struct execdata *e)
-{
- bfd_set_error (bfd_error_no_error);
-
- e->bfd = bfd_openstreamr (NULL, NULL, &e->stream);
- if (e->bfd == NULL)
- {
- e->error = b2he (ENOEXEC);
- return;
- }
-
- if (!bfd_check_format (e->bfd, bfd_object))
- {
- e->error = b2he (ENOEXEC);
- return;
- }
- else if (/* !(e->bfd->flags & EXEC_P) || XXX */
- (host_bfd.arch_info->compatible = e->bfd->arch_info->compatible,
- bfd_arch_get_compatible (&host_bfd, e->bfd)) != host_bfd.arch_info)
- {
- /* This file is of a recognized binary file format, but it is not
- executable on this machine. */
- e->error = b2he (ENOEXEC);
- return;
- }
-
- e->entry = e->bfd->start_address;
-}
-#endif
-
#include <endian.h>
#if BYTE_ORDER == BIG_ENDIAN
#define host_ELFDATA ELFDATA2MSB
@@ -955,13 +632,6 @@ static void
check (struct execdata *e)
{
check_elf (e); /* XXX/fault */
-#ifdef BFD
- if (e->error == ENOEXEC)
- {
- e->error = 0;
- check_bfd (e);
- }
-#endif
}
@@ -1004,18 +674,7 @@ void
finish (struct execdata *e, int dealloc_file)
{
finish_mapping (e);
-#ifdef BFD
- if (e->bfd != NULL)
{
- bfd_close (e->bfd);
- e->bfd = NULL;
- }
- else
-#endif
- {
-#ifdef EXECDATA_STREAM
- fclose (&e->stream);
-#else
if (e->file_data != NULL) {
free (e->file_data);
e->file_data = NULL;
@@ -1023,7 +682,6 @@ finish (struct execdata *e, int dealloc_file)
munmap (map_buffer (e), map_vsize (e));
map_buffer (e) = NULL;
}
-#endif
}
if (dealloc_file && e->file != MACH_PORT_NULL)
{
@@ -1041,293 +699,19 @@ load (task_t usertask, struct execdata *e)
if (! e->error)
{
-#ifdef BFD
- if (e->bfd)
- {
- void load_bfd_section (bfd *bfd, asection *sec, void *userdata)
- {
- load_section (sec, userdata);
- }
- bfd_map_over_sections (e->bfd, &load_bfd_section, e);
- }
- else
-#endif
- {
- ElfW(Word) i;
- for (i = 0; i < e->info.elf.phnum; ++i)
- if (e->info.elf.phdr[i].p_type == PT_LOAD)
- load_section (&e->info.elf.phdr[i], e);
-
- /* The entry point address is relative to wherever we loaded the
- program text. */
- e->entry += e->info.elf.loadbase;
- }
+ ElfW(Word) i;
+ for (i = 0; i < e->info.elf.phnum; ++i)
+ if (e->info.elf.phdr[i].p_type == PT_LOAD)
+ load_section (&e->info.elf.phdr[i], e);
+
+ /* The entry point address is relative to wherever we loaded the
+ program text. */
+ e->entry += e->info.elf.loadbase;
}
/* Release the conch for the file. */
finish_mapping (e);
-
- if (! e->error)
- {
- /* Do post-loading processing on the task. */
-
-#ifdef BFD
- if (e->bfd)
- {
- /* Do post-loading processing for a section. This consists of
- peeking the pages of non-demand-paged executables. */
-
- void postload_section (bfd *bfd, asection *sec, void *userdata)
- {
- struct execdata *u = userdata;
- vm_address_t addr = 0;
- vm_size_t secsize = 0;
-
- addr = (vm_address_t) sec->vma;
- secsize = sec->_raw_size;
-
- if ((sec->flags & SEC_LOAD) && !(bfd->flags & D_PAGED))
- {
- /* Pre-load the section by peeking every mapped page. */
- vm_address_t myaddr, a;
- vm_size_t mysize;
- myaddr = 0;
-
- /* We have already mapped the file into the task in
- load_section. Now read from the task's memory into our
- own address space so we can peek each page and cause it to
- be paged in. */
- u->error = vm_read (u->task, trunc_page (addr),
- round_page (secsize), &myaddr, &mysize);
- if (u->error)
- return;
-
- /* Peek at the first word of each page. */
- for (a = ((myaddr + mysize) & ~(vm_page_size - 1));
- a >= myaddr; a -= vm_page_size)
- /* Force it to be paged in. */
- (void) *(volatile int *) a;
-
- munmap ((caddr_t) myaddr, mysize);
- }
- }
-
- bfd_map_over_sections (e->bfd, postload_section, e);
- }
-#endif
- }
-}
-
-#ifdef GZIP
-/* Check the file for being a gzip'd image. Return with ENOEXEC means not
- a valid gzip file; return with another error means lossage in decoding;
- return with zero means the file was uncompressed into memory which E now
- points to, and `check' can be run again. */
-
-static void
-check_gzip (struct execdata *earg)
-{
- struct execdata *e = earg;
- /* Entry points to unzip engine. */
- int get_method (int);
- void unzip (int, int);
- extern long int bytes_out;
- /* Callbacks from unzip for I/O and error interface. */
- extern int (*unzip_read) (char *buf, size_t maxread);
- extern void (*unzip_write) (const char *buf, size_t nwrite);
- extern void (*unzip_read_error) (void);
- extern void (*unzip_error) (const char *msg);
-
- char *zipdata = NULL;
- size_t zipdatasz = 0;
- FILE *zipout = NULL;
- jmp_buf ziperr;
- off_t zipread_pos = 0;
- int zipread (char *buf, size_t maxread)
- {
- char *contents = map (e, zipread_pos, 1);
- size_t n;
- if (contents == NULL)
- {
- errno = e->error;
- return -1;
- }
- n = MIN (maxread, map_buffer (e) + map_fsize (e) - contents);
- errno = hurd_safe_copyin (buf, contents, n); /* XXX/fault */
- if (errno)
- longjmp (ziperr, 2);
-
- zipread_pos += n;
- return n;
- }
- void zipwrite (const char *buf, size_t nwrite)
- {
- if (fwrite (buf, nwrite, 1, zipout) != 1)
- longjmp (ziperr, 1);
- }
- void ziprderr (void)
- {
- errno = ENOEXEC;
- longjmp (ziperr, 2);
- }
- void ziperror (const char *msg)
- {
- errno = ENOEXEC;
- longjmp (ziperr, 2);
- }
-
- unzip_read = zipread;
- unzip_write = zipwrite;
- unzip_read_error = ziprderr;
- unzip_error = ziperror;
-
- if (setjmp (ziperr))
- {
- /* Error in unzipping jumped out. */
- if (zipout)
- {
- fclose (zipout);
- free (zipdata);
- }
- e->error = errno;
- return;
- }
-
- if (get_method (0) != 0)
- {
- /* Not a happy gzip file. */
- e->error = ENOEXEC;
- return;
- }
-
- /* Matched gzip magic number. Ready to unzip.
- Set up the output stream and let 'er rip. */
-
- zipout = open_memstream (&zipdata, &zipdatasz);
- if (! zipout)
- {
- e->error = errno;
- return;
- }
-
- /* Call the gunzip engine. */
- bytes_out = 0;
- unzip (17, 23); /* Arguments ignored. */
-
- /* The output is complete. Clean up the stream and store its resultant
- buffer and size in the execdata as the file contents. */
- fclose (zipout);
-
- /* Clean up the old exec file stream's state.
- Now that we have the contents all in memory (in E->file_data),
- nothing will in fact ever try to use E->stream again. */
- finish (e, 0);
-
- /* Prepare the stream state to use the file contents already in memory. */
- e->file_data = zipdata;
- e->file_size = zipdatasz;
- prepare_in_memory (e);
-}
-#endif
-
-#ifdef BZIP2
-/* Check the file for being a bzip2'd image. Return with ENOEXEC means not
- a valid bzip2 file; return with another error means lossage in decoding;
- return with zero means the file was uncompressed into memory which E now
- points to, and `check' can be run again. */
-
-static void
-check_bzip2 (struct execdata *earg)
-{
- struct execdata *e = earg;
- /* Entry points to bunzip2 engine. */
- void do_bunzip2 (void);
- /* Callbacks from unzip for I/O and error interface. */
- extern int (*unzip_read) (char *buf, size_t maxread);
- extern void (*unzip_write) (const char *buf, size_t nwrite);
- extern void (*unzip_read_error) (void);
- extern void (*unzip_error) (const char *msg);
-
- char *zipdata = NULL;
- size_t zipdatasz = 0;
- FILE *zipout = NULL;
- jmp_buf ziperr;
- off_t zipread_pos = 0;
- int zipread (char *buf, size_t maxread)
- {
- char *contents = map (e, zipread_pos, 1);
- size_t n;
- if (contents == NULL)
- {
- errno = e->error;
- return -1;
- }
- n = MIN (maxread, map_buffer (e) + map_fsize (e) - contents);
- errno = hurd_safe_copyin (buf, contents, n); /* XXX/fault */
- if (errno)
- longjmp (ziperr, 2);
-
- zipread_pos += n;
- return n;
- }
- void zipwrite (const char *buf, size_t nwrite)
- {
- if (fwrite (buf, nwrite, 1, zipout) != 1)
- longjmp (ziperr, 1);
- }
- void ziprderr (void)
- {
- errno = ENOEXEC;
- longjmp (ziperr, 2);
- }
- void ziperror (const char *msg)
- {
- errno = ENOEXEC;
- longjmp (ziperr, 2);
- }
-
- unzip_read = zipread;
- unzip_write = zipwrite;
- unzip_read_error = ziprderr;
- unzip_error = ziperror;
-
- if (setjmp (ziperr))
- {
- /* Error in unzipping jumped out. */
- if (zipout)
- {
- fclose (zipout);
- free (zipdata);
- }
- e->error = errno;
- return;
- }
-
- zipout = open_memstream (&zipdata, &zipdatasz);
- if (! zipout)
- {
- e->error = errno;
- return;
- }
-
- /* Call the bunzip2 engine. */
- do_bunzip2 ();
-
- /* The output is complete. Clean up the stream and store its resultant
- buffer and size in the execdata as the file contents. */
- fclose (zipout);
-
- /* Clean up the old exec file stream's state.
- Now that we have the contents all in memory (in E->file_data),
- nothing will in fact ever try to use E->stream again. */
- finish (e, 0);
-
- /* Prepare the stream state to use the file contents already in memory. */
- e->file_data = zipdata;
- e->file_size = zipdatasz;
- prepare_in_memory (e);
}
-#endif
static inline void *
@@ -1386,43 +770,6 @@ do_exec (file_t file,
/* Check the file for validity first. */
check (e);
-
-#ifdef GZIP
- if (e->error == ENOEXEC)
- {
- /* See if it is a compressed image. */
- static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
- /* The gzip code is really cheesy, not even close to thread-safe.
- So we serialize all uses of it. */
- pthread_mutex_lock (&lock);
- e->error = 0;
- check_gzip (e);
- pthread_mutex_unlock (&lock);
- if (e->error == 0)
- /* The file was uncompressed into memory, and now E describes the
- uncompressed image rather than the actual file. Check it again
- for a valid magic number. */
- check (e);
- }
-#endif
-#ifdef BZIP2
- if (e->error == ENOEXEC)
- {
- /* See if it is a compressed image. */
- static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
- /* The bzip2 code is really cheesy, not even close to thread-safe.
- So we serialize all uses of it. */
- pthread_mutex_lock (&lock);
- e->error = 0;
- check_bzip2 (e);
- pthread_mutex_unlock (&lock);
- if (e->error == 0)
- /* The file was uncompressed into memory, and now E describes the
- uncompressed image rather than the actual file. Check it again
- for a valid magic number. */
- check (e);
- }
-#endif
}
@@ -1466,20 +813,9 @@ do_exec (file_t file,
/* The file is not a valid executable. */
goto out;
-#ifdef BFD
- if (e.bfd)
- {
- e.info.bfd_locations = alloca (e.bfd->section_count *
- sizeof (vm_offset_t));
- bfd_map_over_sections (e.bfd, check_section, &e);
- }
- else
-#endif
- {
- const ElfW(Phdr) *phdr = e.info.elf.phdr;
- e.info.elf.phdr = alloca (e.info.elf.phnum * sizeof (ElfW(Phdr)));
- check_elf_phdr (&e, phdr);
- }
+ const ElfW(Phdr) *phdr = e.info.elf.phdr;
+ e.info.elf.phdr = alloca (e.info.elf.phnum * sizeof (ElfW(Phdr)));
+ check_elf_phdr (&e, phdr);
if (oldtask == MACH_PORT_NULL)
flags |= EXEC_NEWTASK;
@@ -1685,33 +1021,11 @@ do_exec (file_t file,
along with this executable. Find the name of the file and open
it. */
-#ifdef BFD
- char namebuf[e.bfd ? e.interp.section->_raw_size : 0];
-#endif
- char *name;
-
-#ifdef BFD
- if (e.bfd)
- {
- if (! bfd_get_section_contents (e.bfd, e.interp.section,
- namebuf, 0,
- e.interp.section->_raw_size))
- {
- e.error = b2he (errno);
- name = NULL;
- }
- else
- name = namebuf;
- }
- else
-#endif
- {
- name = map (&e, (e.interp.phdr->p_offset
- & ~(e.interp.phdr->p_align - 1)),
- e.interp.phdr->p_filesz);
- if (! name && ! e.error)
- e.error = ENOEXEC;
- }
+ char *name = map (&e, (e.interp.phdr->p_offset
+ & ~(e.interp.phdr->p_align - 1)),
+ e.interp.phdr->p_filesz);
+ if (! name && ! e.error)
+ e.error = ENOEXEC;
if (! name)
e.interp.section = NULL;
@@ -1749,21 +1063,10 @@ do_exec (file_t file,
prepare_and_check (interp.file, &interp);
if (! interp.error)
{
-#ifdef BFD
- if (interp.bfd)
- {
- interp.info.bfd_locations = alloca (interp.bfd->section_count *
- sizeof (vm_offset_t));
- bfd_map_over_sections (interp.bfd, check_section, &e);
- }
- else
-#endif
- {
- const ElfW(Phdr) *phdr = interp.info.elf.phdr;
- interp.info.elf.phdr = alloca (interp.info.elf.phnum *
- sizeof (ElfW(Phdr)));
- check_elf_phdr (&interp, phdr);
- }
+ const ElfW(Phdr) *phdr = interp.info.elf.phdr;
+ interp.info.elf.phdr = alloca (interp.info.elf.phnum *
+ sizeof (ElfW(Phdr)));
+ check_elf_phdr (&interp, phdr);
}
e.error = interp.error;
}
@@ -1842,15 +1145,21 @@ do_exec (file_t file,
the image so that a load-anywhere image gets the adjusted addresses. */
if (e.info.elf.phdr_addr != 0)
{
-#ifdef BFD
- if (!e.bfd)
-#endif
- e.info.elf.phdr_addr += e.info.elf.loadbase;
+ e.info.elf.phdr_addr += e.info.elf.loadbase;
boot->phdr_addr = e.info.elf.phdr_addr;
boot->phdr_size = e.info.elf.phnum * sizeof (ElfW(Phdr));
}
boot->user_entry = e.entry; /* already adjusted in `load' */
+ /* Set the start_code and end_code values for this process.
+ /hurd/exec is used to start /hurd/proc, so at this point there is
+ no proc server, so we need to be careful here. */
+ if (boot->portarray[INIT_PORT_PROC] != MACH_PORT_NULL)
+ e.error = proc_set_code (boot->portarray[INIT_PORT_PROC],
+ e.start_code, e.end_code);
+ if (e.error)
+ goto out;
+
/* Create the initial thread. */
e.error = thread_create (newtask, &thread);
if (e.error)
@@ -1864,17 +1173,12 @@ do_exec (file_t file,
&boot->stack_base, &boot->stack_size);
if (e.error)
goto out;
-#ifdef BFD
- if (!e.bfd)
-#endif
- {
- /* It would probably be better to change mach_setup_thread so
- it does a vm_map with the right permissions to start with. */
- if (!e.info.elf.execstack)
- e.error = vm_protect (newtask, boot->stack_base, boot->stack_size,
- 0, VM_PROT_READ | VM_PROT_WRITE);
- }
+ /* It would probably be better to change mach_setup_thread so
+ it does a vm_map with the right permissions to start with. */
+ if (!e.info.elf.execstack)
+ e.error = vm_protect (newtask, boot->stack_base, boot->stack_size,
+ 0, VM_PROT_READ | VM_PROT_WRITE);
if (oldtask != newtask && oldtask != MACH_PORT_NULL)
{
@@ -2071,87 +1375,6 @@ S_exec_exec (struct trivfs_protid *protid,
if (! protid)
return EOPNOTSUPP;
-#if 0
- if (!(flags & EXEC_SECURE))
- {
- char *list = envz_get (envp, envplen, "EXECSERVERS");
-
- if (list)
- {
- int tried = 0;
- list = strdupa (list);
- while ((p = strsep (&list, ":")))
- {
- /* Open the named file using the appropriate directory ports for
- the user. */
- error_t user_port (int which, error_t (*operate) (mach_port_t))
- {
- return (*operate) (nports > which
- ? portarray[which] : MACH_PORT_NULL);
- }
- file_t user_fd (int fd)
- {
- if (fd < 0 || fd >= dtablesize ||
- dtable[fd] == MACH_PORT_NULL)
- {
- errno = EBADF;
- return MACH_PORT_NULL;
- }
- return dtable[fd];
- }
- file_t server;
- if (!hurd_file_name_lookup (user_port, user_fd, 0, p, 0,0,
&server))
- {
- error_t err;
- struct trivfs_protid *protid
- = ports_lookup_port (port_bucket, server,
- trivfs_protid_portclasses[0]);
- if (protid)
- {
- err = do_exec (file, oldtask, 0,
- argv, argvlen, argv_copy,
- envp, envplen, envp_copy,
- dtable, dtablesize, dtable_copy,
- portarray, nports, portarray_copy,
- intarray, nints, intarray_copy,
- deallocnames, ndeallocnames,
- destroynames, ndestroynames);
- ports_port_deref (protid);
- }
- else
- {
- int n;
- err = exec_exec (server,
- file, MACH_MSG_TYPE_COPY_SEND,
- oldtask, 0,
- argv, argvlen,
- envp, envplen,
- dtable, MACH_MSG_TYPE_COPY_SEND,
- dtablesize,
- portarray, MACH_MSG_TYPE_COPY_SEND,
- nports,
- intarray, nints,
- deallocnames, ndeallocnames,
- destroynames, ndestroynames);
- mach_port_deallocate (mach_task_self (), file);
- for (n = 0; n < dtablesize; n++)
- mach_port_deallocate (mach_task_self (), dtable[n]);
- for (n = 0; n < nports; n++)
- mach_port_deallocate (mach_task_self (), portarray[n]);
- }
- mach_port_deallocate (mach_task_self (), server);
- if (err != ENOEXEC)
- return err;
- tried = 1;
- }
- }
- if (tried)
- /* At least one exec server got a crack at it and gave up. */
- return ENOEXEC;
- }
- }
-#endif
-
/* There were no user-specified exec servers,
or none of them could be found. */
diff --git a/exec/main.c b/exec/main.c
index efad85a..d5d6882 100644
--- a/exec/main.c
+++ b/exec/main.c
@@ -25,6 +25,7 @@
#include <hurd/startup.h>
#include <argp.h>
#include <version.h>
+#include <pids.h>
const char *argp_program_version = STANDARD_HURD_VERSION (exec);
@@ -246,7 +247,7 @@ S_exec_init (struct trivfs_protid *protid,
proc_register_version (procserver, host_priv, "exec", "", HURD_VERSION);
- err = proc_getmsgport (procserver, 1, &startup);
+ err = proc_getmsgport (procserver, HURD_PID_STARTUP, &startup);
assert_perror (err);
mach_port_deallocate (mach_task_self (), procserver);
diff --git a/exec/priv.h b/exec/priv.h
index dbecb7a..85e03ae 100644
--- a/exec/priv.h
+++ b/exec/priv.h
@@ -28,10 +28,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA
02139, USA. */
#include <hurd/lookup.h>
#include <pthread.h>
-#ifdef BFD
-#include <bfd.h>
-#endif
-
#include <elf.h>
#include <link.h> /* This gives us the ElfW macro. */
#include <fcntl.h>
@@ -41,12 +37,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA
02139, USA. */
#ifndef exec_priv_h
#define exec_priv_h
-#ifdef BFD
-/* A BFD whose architecture and machine type are those of the host system. */
-extern bfd_arch_info_type host_bfd_arch_info;
-extern bfd host_bfd;
-#endif
-
/* Information kept around to be given to a new task
in response to a message on the task's bootstrap port. */
struct bootinfo
@@ -70,12 +60,7 @@ struct port_class *execboot_portclass;
extern mach_port_t procserver; /* Our proc port. */
-#ifdef BFD
-#define EXECDATA_STREAM /* BFD uses stdio to access the
executable. */
-#else
typedef void asection;
-#endif
-
/* Data shared between check, check_section,
load, load_section, and finish. */
@@ -88,7 +73,9 @@ struct execdata
vm_address_t entry;
file_t file;
-#ifndef EXECDATA_STREAM
+ /* Set by load_section. */
+ vm_address_t start_code;
+ vm_address_t end_code;
/* Note that if `file_data' (below) is set, then these just point
into that and should not be deallocated (file_data is malloc'd). */
@@ -102,26 +89,6 @@ struct execdata
#define map_filepos(e) ((e)->map_filepos)
#define map_set_fsize(e, fsize) ((e)->map_fsize = (fsize))
-#else
-
-#ifdef _STDIO_USES_IOSTREAM
-# error implement me for libio!
-#else
- FILE stream;
-#define map_buffer(e) ((e)->stream.__buffer)
-#define map_fsize(e) ((e)->stream.__get_limit - (e)->stream.__buffer)
-#define map_vsize(e) ((e)->stream.__bufsize)
-#define map_filepos(e) ((e)->stream.__offset)
-#define map_set_fsize(e, fsize) \
- ((e)->stream.__get_limit = (e)->stream.__buffer + (fsize))
-#endif
-
-#endif
-
-#ifdef BFD
- bfd *bfd;
-#endif
-
union /* Interpreter section giving name of file. */
{
asection *section;
@@ -138,10 +105,6 @@ struct execdata
union
{
- /* Vector indexed by section index,
- information passed from check_section to load_section.
- Set by caller of check_section and load. */
- vm_offset_t *bfd_locations;
struct
{
/* Program header table read from the executable.
diff --git a/ext2fs/balloc.c b/ext2fs/balloc.c
index b2d2eab..efef8ae 100644
--- a/ext2fs/balloc.c
+++ b/ext2fs/balloc.c
@@ -92,7 +92,7 @@ ext2_free_blocks (block_t block, unsigned long count)
block, count);
}
gdp = group_desc (block_group);
- bh = bptr (gdp->bg_block_bitmap);
+ bh = disk_cache_block_ref (gdp->bg_block_bitmap);
if (in_range (gdp->bg_block_bitmap, block, gcount) ||
in_range (gdp->bg_inode_bitmap, block, gcount) ||
@@ -114,6 +114,7 @@ ext2_free_blocks (block_t block, unsigned long count)
}
record_global_poke (bh);
+ disk_cache_block_ref_ptr (gdp);
record_global_poke (gdp);
block += gcount;
@@ -139,7 +140,7 @@ ext2_new_block (block_t goal,
block_t prealloc_goal,
block_t *prealloc_count, block_t *prealloc_block)
{
- char *bh;
+ char *bh = NULL;
char *p, *r;
int i, j, k, tmp;
unsigned long lmap;
@@ -165,6 +166,7 @@ ext2_new_block (block_t goal,
ext2_debug ("goal=%u", goal);
repeat:
+ assert (bh == NULL);
/*
* First, test whether the goal block is free.
*/
@@ -179,7 +181,7 @@ repeat:
if (j)
goal_attempts++;
#endif
- bh = bptr (gdp->bg_block_bitmap);
+ bh = disk_cache_block_ref (gdp->bg_block_bitmap);
ext2_debug ("goal is at %d:%d", i, j);
@@ -245,6 +247,9 @@ repeat:
j = k;
goto got_block;
}
+
+ disk_cache_block_deref (bh);
+ bh = NULL;
}
ext2_debug ("bit not found in block group %d", i);
@@ -267,7 +272,8 @@ repeat:
pthread_spin_unlock (&global_lock);
return 0;
}
- bh = bptr (gdp->bg_block_bitmap);
+ assert (bh == NULL);
+ bh = disk_cache_block_ref (gdp->bg_block_bitmap);
r = memscan (bh, 0, sblock->s_blocks_per_group >> 3);
j = (r - bh) << 3;
if (j < sblock->s_blocks_per_group)
@@ -277,12 +283,15 @@ repeat:
sblock->s_blocks_per_group);
if (j >= sblock->s_blocks_per_group)
{
+ disk_cache_block_deref (bh);
+ bh = NULL;
ext2_error ("free blocks count corrupted for block group %d", i);
pthread_spin_unlock (&global_lock);
return 0;
}
search_back:
+ assert (bh != NULL);
/*
* We have succeeded in finding a free byte in the block
* bitmap. Now search backwards up to 7 bits to find the
@@ -291,6 +300,7 @@ search_back:
for (k = 0; k < 7 && j > 0 && !test_bit (j - 1, bh); k++, j--);
got_block:
+ assert (bh != NULL);
ext2_debug ("using block group %d (%d)", i, gdp->bg_free_blocks_count);
@@ -304,6 +314,8 @@ got_block:
if (set_bit (j, bh))
{
ext2_warning ("bit already set for block %d", j);
+ disk_cache_block_deref (bh);
+ bh = NULL;
goto repeat;
}
@@ -351,6 +363,7 @@ got_block:
j = tmp;
record_global_poke (bh);
+ bh = NULL;
if (j >= sblock->s_blocks_count)
{
@@ -363,12 +376,14 @@ got_block:
j, goal_hits, goal_attempts);
gdp->bg_free_blocks_count--;
+ disk_cache_block_ref_ptr (gdp);
record_global_poke (gdp);
sblock->s_free_blocks_count--;
sblock_dirty = 1;
sync_out:
+ assert (bh == NULL);
pthread_spin_unlock (&global_lock);
alloc_sync (0);
@@ -390,9 +405,12 @@ ext2_count_free_blocks ()
gdp = NULL;
for (i = 0; i < groups_count; i++)
{
+ void *bh;
gdp = group_desc (i);
desc_count += gdp->bg_free_blocks_count;
- x = count_free (bptr (gdp->bg_block_bitmap), block_size);
+ bh = disk_cache_block_ref (gdp->bg_block_bitmap);
+ x = count_free (bh, block_size);
+ disk_cache_block_deref (bh);
printf ("group %d: stored = %d, counted = %lu",
i, gdp->bg_free_blocks_count, x);
bitmap_count += x;
@@ -453,7 +471,7 @@ ext2_check_blocks_bitmap ()
gdp = group_desc (i);
desc_count += gdp->bg_free_blocks_count;
- bh = bptr (gdp->bg_block_bitmap);
+ bh = disk_cache_block_ref (gdp->bg_block_bitmap);
if (!EXT2_HAS_RO_COMPAT_FEATURE (sblock,
EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)
@@ -479,6 +497,7 @@ ext2_check_blocks_bitmap ()
ext2_error ("block #%d of the inode table in group %d is marked
free", j, i);
x = count_free (bh, block_size);
+ disk_cache_block_deref (bh);
if (gdp->bg_free_blocks_count != x)
ext2_error ("wrong free blocks count for group %d,"
" stored = %d, counted = %lu",
diff --git a/ext2fs/ext2fs.c b/ext2fs/ext2fs.c
index 993f199..128b6ed 100644
--- a/ext2fs/ext2fs.c
+++ b/ext2fs/ext2fs.c
@@ -181,9 +181,9 @@ main (int argc, char **argv)
/* Map the entire disk. */
create_disk_pager ();
- pokel_init (&global_pokel, diskfs_disk_pager, disk_image);
+ pokel_init (&global_pokel, diskfs_disk_pager, disk_cache);
- get_hypermetadata();
+ map_hypermetadata ();
inode_init ();
@@ -211,6 +211,8 @@ diskfs_reload_global_state ()
{
pokel_flush (&global_pokel);
pager_flush (diskfs_disk_pager, 1);
+ sblock = NULL;
get_hypermetadata ();
+ map_hypermetadata ();
return 0;
}
diff --git a/ext2fs/ext2fs.h b/ext2fs/ext2fs.h
index 52bf2b1..e01d1a5 100644
--- a/ext2fs/ext2fs.h
+++ b/ext2fs/ext2fs.h
@@ -23,7 +23,9 @@
#include <hurd/pager.h>
#include <hurd/fshelp.h>
#include <hurd/iohelp.h>
+#include <hurd/store.h>
#include <hurd/diskfs.h>
+#include <hurd/ihash.h>
#include <assert.h>
#include <pthread.h>
#include <sys/mman.h>
@@ -195,6 +197,8 @@ struct user_pager_info
/* ---------------------------------------------------------------- */
/* pager.c */
+#define DISK_CACHE_BLOCKS 65536
+
#include <hurd/diskfs-pager.h>
/* Set up the disk pager. */
@@ -218,10 +222,54 @@ extern struct store *store;
/* What the user specified. */
extern struct store_parsed *store_parsed;
-/* Mapped image of the disk. */
-extern void *disk_image;
+/* Mapped image of cached blocks of the disk. */
+extern void *disk_cache;
+extern store_offset_t disk_cache_size;
+extern int disk_cache_blocks;
+
+#define DC_INCORE 0x01 /* Not in core. */
+#define DC_UNTOUCHED 0x02 /* Not touched by disk_pager_read_paged
+ or disk_cache_block_ref. */
+#define DC_FIXED 0x04 /* Must not be re-associated. */
+
+/* Flags that forbid re-association of page. DC_UNTOUCHED is included
+ because this flag is used only when page is already to be
+ re-associated, so it's not good candidate for another
+ remapping. */
+#define DC_DONT_REUSE (DC_INCORE | DC_UNTOUCHED | DC_FIXED)
+
+#define DC_NO_BLOCK ((block_t) -1L)
+
+#ifndef NDEBUG
+#define DISK_CACHE_LAST_READ_XOR 0xDEADBEEF
+#endif
+
+/* Disk cache blocks' meta info. */
+struct disk_cache_info
+{
+ block_t block;
+ uint16_t flags;
+ uint16_t ref_count;
+#ifndef NDEBUG
+ block_t last_read, last_read_xor;
+#endif
+};
-/* Our in-core copy of the super-block (pointer into the disk_image). */
+/* block num --> pointer to in-memory block */
+extern hurd_ihash_t disk_cache_bptr;
+/* Metadata about cached block. */
+extern struct disk_cache_info *disk_cache_info;
+/* Lock for these mappings */
+extern pthread_mutex_t disk_cache_lock;
+/* Fired when a re-association is done. */
+extern pthread_cond_t disk_cache_reassociation;
+
+void *disk_cache_block_ref (block_t block);
+void disk_cache_block_ref_ptr (void *ptr);
+void disk_cache_block_deref (void *ptr);
+int disk_cache_block_is_ref (block_t block);
+
+/* Our in-core copy of the super-block (pointer into the disk_cache). */
struct ext2_super_block *sblock;
/* True if sblock has been modified. */
int sblock_dirty;
@@ -251,6 +299,9 @@ vm_address_t zeroblock;
/* Get the superblock from the disk, & setup various global info from it. */
void get_hypermetadata ();
+
+/* Map `sblock' and `group_desc_image' pointers to disk cache. */
+void map_hypermetadata ();
/* ---------------------------------------------------------------- */
/* Random stuff calculated from the super block. */
@@ -274,21 +325,51 @@ pthread_spinlock_t generation_lock;
unsigned long next_generation;
/* ---------------------------------------------------------------- */
-/* Functions for looking inside disk_image */
+/* Functions for looking inside disk_cache */
-#define trunc_block(offs) (((offs) >> log2_block_size) << log2_block_size)
+#define trunc_block(offs) \
+ ((off_t) ((offs) >> log2_block_size) << log2_block_size)
#define round_block(offs) \
- ((((offs) + block_size - 1) >> log2_block_size) << log2_block_size)
+ ((off_t) (((offs) + block_size - 1) >> log2_block_size) << log2_block_size)
/* block num --> byte offset on disk */
-#define boffs(block) ((block) << log2_block_size)
+#define boffs(block) ((off_t) (block) << log2_block_size)
/* byte offset on disk --> block num */
#define boffs_block(offs) ((offs) >> log2_block_size)
+/* pointer to in-memory block -> index in disk_cache_info */
+#define bptr_index(ptr) (((char *)ptr - (char *)disk_cache) >> log2_block_size)
+
/* byte offset on disk --> pointer to in-memory block */
-#define boffs_ptr(offs) (((char *)disk_image) + (offs))
+EXT2FS_EI char *
+boffs_ptr (off_t offset)
+{
+ block_t block = boffs_block (offset);
+ pthread_mutex_lock (&disk_cache_lock);
+ char *ptr = hurd_ihash_find (disk_cache_bptr, block);
+ pthread_mutex_unlock (&disk_cache_lock);
+ assert (ptr);
+ ptr += offset % block_size;
+ ext2_debug ("(%lld) = %p", offset, ptr);
+ return ptr;
+}
+
/* pointer to in-memory block --> byte offset on disk */
-#define bptr_offs(ptr) ((char *)(ptr) - ((char *)disk_image))
+EXT2FS_EI off_t
+bptr_offs (void *ptr)
+{
+ vm_offset_t mem_offset = (char *)ptr - (char *)disk_cache;
+ off_t offset;
+ assert (mem_offset < disk_cache_size);
+ pthread_mutex_lock (&disk_cache_lock);
+ offset = (off_t) disk_cache_info[boffs_block (mem_offset)].block
+ << log2_block_size;
+ assert (offset || mem_offset < block_size);
+ offset += mem_offset % block_size;
+ pthread_mutex_unlock (&disk_cache_lock);
+ ext2_debug ("(%p) = %lld", ptr, offset);
+ return offset;
+}
/* block num --> pointer to in-memory block */
#define bptr(block) boffs_ptr(boffs(block))
@@ -308,14 +389,24 @@ extern struct ext2_inode *dino (ino_t inum);
#if defined(__USE_EXTERN_INLINES) || defined(EXT2FS_DEFINE_EI)
/* Convert an inode number to the dinode on disk. */
EXT2FS_EI struct ext2_inode *
-dino (ino_t inum)
+dino_ref (ino_t inum)
{
unsigned long inodes_per_group = sblock->s_inodes_per_group;
unsigned long bg_num = (inum - 1) / inodes_per_group;
unsigned long group_inum = (inum - 1) % inodes_per_group;
- struct ext2_group_desc *bg = group_desc(bg_num);
+ struct ext2_group_desc *bg = group_desc (bg_num);
block_t block = bg->bg_inode_table + (group_inum / inodes_per_block);
- return ((struct ext2_inode *)bptr(block)) + group_inum % inodes_per_block;
+ struct ext2_inode *inode = disk_cache_block_ref (block);
+ inode += group_inum % inodes_per_block;
+ ext2_debug ("(%llu) = %p", inum, inode);
+ return inode;
+}
+
+EXT2FS_EI void
+dino_deref (struct ext2_inode *inode)
+{
+ ext2_debug ("(%p)", inode);
+ disk_cache_block_deref (inode);
}
#endif /* Use extern inlines. */
@@ -377,27 +468,38 @@ global_block_modified (block_t block)
EXT2FS_EI void
record_global_poke (void *ptr)
{
- int boffs = trunc_block (bptr_offs (ptr));
- global_block_modified (boffs_block (boffs));
- pokel_add (&global_pokel, boffs_ptr(boffs), block_size);
+ block_t block = boffs_block (bptr_offs (ptr));
+ void *block_ptr = bptr (block);
+ ext2_debug ("(%p = %p)", ptr, block_ptr);
+ assert (disk_cache_block_is_ref (block));
+ global_block_modified (block);
+ pokel_add (&global_pokel, block_ptr, block_size);
}
/* This syncs a modification to a non-file block. */
EXT2FS_EI void
sync_global_ptr (void *bptr, int wait)
{
- vm_offset_t boffs = trunc_block (bptr_offs (bptr));
- global_block_modified (boffs_block (boffs));
- pager_sync_some (diskfs_disk_pager, trunc_page (boffs), vm_page_size, wait);
+ block_t block = boffs_block (bptr_offs (bptr));
+ void *block_ptr = bptr (block);
+ ext2_debug ("(%p -> %u)", bptr, block);
+ global_block_modified (block);
+ disk_cache_block_deref (block_ptr);
+ pager_sync_some (diskfs_disk_pager,
+ block_ptr - disk_cache, block_size, wait);
+
}
/* This records a modification to one of a file's indirect blocks. */
EXT2FS_EI void
record_indir_poke (struct node *node, void *ptr)
{
- int boffs = trunc_block (bptr_offs (ptr));
- global_block_modified (boffs_block (boffs));
- pokel_add (&node->dn->indir_pokel, boffs_ptr(boffs), block_size);
+ block_t block = boffs_block (bptr_offs (ptr));
+ void *block_ptr = bptr (block);
+ ext2_debug ("(%llu, %p)", node->cache_id, ptr);
+ assert (disk_cache_block_is_ref (block));
+ global_block_modified (block);
+ pokel_add (&node->dn->indir_pokel, block_ptr, block_size);
}
/* ---------------------------------------------------------------- */
@@ -405,6 +507,7 @@ record_indir_poke (struct node *node, void *ptr)
EXT2FS_EI void
sync_global (int wait)
{
+ ext2_debug ("%d", wait);
pokel_sync (&global_pokel, wait);
}
diff --git a/ext2fs/getblk.c b/ext2fs/getblk.c
index 23ba645..bde66e1 100644
--- a/ext2fs/getblk.c
+++ b/ext2fs/getblk.c
@@ -104,7 +104,7 @@ ext2_alloc_block (struct node *node, block_t goal, int zero)
if (result && zero)
{
- char *bh = bptr (result);
+ char *bh = disk_cache_block_ref (result);
bzero (bh, block_size);
record_indir_poke (node, bh);
}
@@ -122,6 +122,8 @@ inode_getblk (struct node *node, int nr, int create, int
zero,
block_t hint;
#endif
+ assert (0 <= nr && nr < EXT2_N_BLOCKS);
+
*result = node->dn->info.i_data[nr];
if (*result)
return 0;
@@ -180,14 +182,20 @@ block_getblk (struct node *node, block_t block, int nr,
int create, int zero,
{
int i;
block_t goal = 0;
- block_t *bh = (block_t *)bptr (block);
+ block_t *bh = (block_t *)disk_cache_block_ref (block);
*result = bh[nr];
if (*result)
- return 0;
+ {
+ disk_cache_block_deref (bh);
+ return 0;
+ }
if (!create)
- return EINVAL;
+ {
+ disk_cache_block_deref (bh);
+ return EINVAL;
+ }
if (node->dn->info.i_next_alloc_block == new_block)
goal = node->dn->info.i_next_alloc_goal;
@@ -207,7 +215,10 @@ block_getblk (struct node *node, block_t block, int nr,
int create, int zero,
*result = ext2_alloc_block (node, goal, zero);
if (!*result)
- return ENOSPC;
+ {
+ disk_cache_block_deref (bh);
+ return ENOSPC;
+ }
bh[nr] = *result;
diff --git a/ext2fs/hyper.c b/ext2fs/hyper.c
index bee4175..5bcc2ab 100644
--- a/ext2fs/hyper.c
+++ b/ext2fs/hyper.c
@@ -58,11 +58,14 @@ static int ext2fs_clean; /* fs clean before we started
writing? */
void
get_hypermetadata (void)
{
- error_t err = diskfs_catch_exception ();
- if (err)
- ext2_panic ("can't read superblock: %s", strerror (err));
+ error_t err;
+ size_t read = 0;
- sblock = (struct ext2_super_block *) boffs_ptr (SBLOCK_OFFS);
+ assert (! sblock);
+ err = store_read (store, SBLOCK_OFFS >> store->log2_block_size,
+ SBLOCK_SIZE, (void **)&sblock, &read);
+ if (err || read != SBLOCK_SIZE)
+ ext2_panic ("Cannot read hypermetadata");
if (sblock->s_magic != EXT2_SUPER_MAGIC
#ifdef EXT2FS_PRE_02B_COMPAT
@@ -152,15 +155,25 @@ get_hypermetadata (void)
allocate_mod_map ();
- diskfs_end_catch_exception ();
+ /* A handy source of page-aligned zeros. */
+ if (zeroblock == 0)
+ {
+ zeroblock = (vm_address_t) mmap (0, block_size, PROT_READ, MAP_ANON, 0,
0);
+ assert (zeroblock != (vm_address_t) MAP_FAILED);
+ }
+
+ munmap (sblock, SBLOCK_SIZE);
+ sblock = NULL;
+}
+
+void
+map_hypermetadata (void)
+{
+ sblock = (struct ext2_super_block *) boffs_ptr (SBLOCK_OFFS);
/* Cache a convenient pointer to the block group descriptors for allocation.
These are stored in the filesystem blocks following the superblock. */
group_desc_image = (struct ext2_group_desc *) bptr (bptr_block (sblock) + 1);
-
- /* A handy source of page-aligned zeros. */
- if (zeroblock == 0)
- zeroblock = (vm_address_t) mmap (0, block_size, PROT_READ, MAP_ANON, 0, 0);
}
error_t
@@ -183,6 +196,7 @@ diskfs_set_hypermetadata (int wait, int clean)
if (sblock_dirty)
{
sblock_dirty = 0;
+ disk_cache_block_ref_ptr (sblock);
record_global_poke (sblock);
}
@@ -199,7 +213,8 @@ diskfs_readonly_changed (int readonly)
(*(readonly ? store_set_flags : store_clear_flags)) (store, STORE_READONLY);
- mprotect (disk_image, store->size, PROT_READ | (readonly ? 0 : PROT_WRITE));
+ mprotect (disk_cache, disk_cache_size,
+ PROT_READ | (readonly ? 0 : PROT_WRITE));
if (!readonly && !(sblock->s_state & EXT2_VALID_FS))
ext2_warning ("UNCLEANED FILESYSTEM NOW WRITABLE");
diff --git a/ext2fs/ialloc.c b/ext2fs/ialloc.c
index aa018d9..2d8e51e 100644
--- a/ext2fs/ialloc.c
+++ b/ext2fs/ialloc.c
@@ -75,22 +75,25 @@ diskfs_free_node (struct node *np, mode_t old_mode)
bit = (inum - 1) % sblock->s_inodes_per_group;
gdp = group_desc (block_group);
- bh = bptr (gdp->bg_inode_bitmap);
+ bh = disk_cache_block_ref (gdp->bg_inode_bitmap);
if (!clear_bit (bit, bh))
ext2_warning ("bit already cleared for inode %Ld", inum);
else
{
+ disk_cache_block_ref_ptr (bh);
record_global_poke (bh);
gdp->bg_free_inodes_count++;
if (S_ISDIR (old_mode))
gdp->bg_used_dirs_count--;
+ disk_cache_block_ref_ptr (gdp);
record_global_poke (gdp);
sblock->s_free_inodes_count++;
}
+ disk_cache_block_deref (bh);
sblock_dirty = 1;
pthread_spin_unlock (&global_lock);
alloc_sync(0);
@@ -111,7 +114,7 @@ diskfs_free_node (struct node *np, mode_t old_mode)
ino_t
ext2_alloc_inode (ino_t dir_inum, mode_t mode)
{
- char *bh;
+ char *bh = NULL;
int i, j, inum, avefreei;
struct ext2_group_desc *gdp;
struct ext2_group_desc *tmp;
@@ -119,6 +122,7 @@ ext2_alloc_inode (ino_t dir_inum, mode_t mode)
pthread_spin_lock (&global_lock);
repeat:
+ assert (bh == NULL);
gdp = NULL;
i = 0;
@@ -213,7 +217,7 @@ repeat:
return 0;
}
- bh = bptr (gdp->bg_inode_bitmap);
+ bh = disk_cache_block_ref (gdp->bg_inode_bitmap);
if ((inum =
find_first_zero_bit ((unsigned long *) bh, sblock->s_inodes_per_group))
< sblock->s_inodes_per_group)
@@ -221,12 +225,17 @@ repeat:
if (set_bit (inum, bh))
{
ext2_warning ("bit already set for inode %d", inum);
+ disk_cache_block_deref (bh);
+ bh = NULL;
goto repeat;
}
record_global_poke (bh);
+ bh = NULL;
}
else
{
+ disk_cache_block_deref (bh);
+ bh = NULL;
if (gdp->bg_free_inodes_count != 0)
{
ext2_error ("free inodes count corrupted in group %d", i);
@@ -248,15 +257,25 @@ repeat:
gdp->bg_free_inodes_count--;
if (S_ISDIR (mode))
gdp->bg_used_dirs_count++;
+ disk_cache_block_ref_ptr (gdp);
record_global_poke (gdp);
sblock->s_free_inodes_count--;
sblock_dirty = 1;
sync_out:
+ assert (bh == NULL);
pthread_spin_unlock (&global_lock);
alloc_sync (0);
+ /* Make sure the coming read_node won't complain about bad
+ fields. */
+ {
+ struct ext2_inode *di = dino_ref (inum);
+ memset (di, 0, sizeof *di);
+ dino_deref (di);
+ }
+
return inum;
}
@@ -353,10 +372,12 @@ ext2_count_free_inodes ()
gdp = NULL;
for (i = 0; i < groups_count; i++)
{
+ void *bh;
gdp = group_desc (i);
desc_count += gdp->bg_free_inodes_count;
- x = count_free (bptr (gdp->bg_inode_bitmap),
- sblock->s_inodes_per_group / 8);
+ bh = disk_cache_block_ref (gdp->bg_inode_bitmap);
+ x = count_free (bh, sblock->s_inodes_per_group / 8);
+ disk_cache_block_deref (bh);
ext2_debug ("group %d: stored = %d, counted = %lu",
i, gdp->bg_free_inodes_count, x);
bitmap_count += x;
@@ -386,10 +407,12 @@ ext2_check_inodes_bitmap ()
gdp = NULL;
for (i = 0; i < groups_count; i++)
{
+ void *bh;
gdp = group_desc (i);
desc_count += gdp->bg_free_inodes_count;
- x = count_free (bptr (gdp->bg_inode_bitmap),
- sblock->s_inodes_per_group / 8);
+ bh = disk_cache_block_ref (gdp->bg_inode_bitmap);
+ x = count_free (bh, sblock->s_inodes_per_group / 8);
+ disk_cache_block_deref (bh);
if (gdp->bg_free_inodes_count != x)
ext2_error ("wrong free inodes count in group %d, "
"stored = %d, counted = %lu",
diff --git a/ext2fs/inode.c b/ext2fs/inode.c
index 2c44279..e75c63f 100644
--- a/ext2fs/inode.c
+++ b/ext2fs/inode.c
@@ -92,7 +92,7 @@ diskfs_cached_lookup (ino_t inum, struct node **npp)
dn->dir_idx = 0;
dn->pager = 0;
pthread_rwlock_init (&dn->alloc_lock, NULL);
- pokel_init (&dn->indir_pokel, diskfs_disk_pager, disk_image);
+ pokel_init (&dn->indir_pokel, diskfs_disk_pager, disk_cache);
/* Create the new node. */
np = diskfs_make_node (dn);
@@ -201,13 +201,17 @@ read_node (struct node *np)
error_t err;
struct stat *st = &np->dn_stat;
struct disknode *dn = np->dn;
- struct ext2_inode *di = dino (np->cache_id);
+ struct ext2_inode *di;
struct ext2_inode_info *info = &dn->info;
+ ext2_debug ("(%llu)", np->cache_id);
+
err = diskfs_catch_exception ();
if (err)
return err;
+ di = dino_ref (np->cache_id);
+
st->st_fstype = FSTYPE_EXT2FS;
st->st_fsid = getpid (); /* This call is very cheap. */
st->st_ino = np->cache_id;
@@ -285,7 +289,9 @@ read_node (struct node *np)
info->i_high_size = di->i_size_high;
if (info->i_high_size) /* XXX */
{
+ dino_deref (di);
ext2_warning ("cannot handle large file inode %Ld", np->cache_id);
+ diskfs_end_catch_exception ();
return EFBIG;
}
}
@@ -307,6 +313,7 @@ read_node (struct node *np)
}
dn->info_i_translator = di->i_translator;
+ dino_deref (di);
diskfs_end_catch_exception ();
if (S_ISREG (st->st_mode) || S_ISDIR (st->st_mode)
@@ -408,7 +415,9 @@ write_node (struct node *np)
{
error_t err;
struct stat *st = &np->dn_stat;
- struct ext2_inode *di = dino (np->cache_id);
+ struct ext2_inode *di;
+
+ ext2_debug ("(%llu)", np->cache_id);
if (np->dn->info.i_prealloc_count)
ext2_discard_prealloc (np);
@@ -425,6 +434,8 @@ write_node (struct node *np)
if (err)
return NULL;
+ di = dino_ref (np->cache_id);
+
di->i_generation = st->st_gen;
/* We happen to know that the stat mode bits are the same
@@ -505,6 +516,7 @@ write_node (struct node *np)
diskfs_end_catch_exception ();
np->dn_stat_dirty = 0;
+ /* Leave invoking dino_deref (di) to the caller. */
return di;
}
else
@@ -674,7 +686,7 @@ diskfs_set_translator (struct node *np, const char *name,
unsigned namelen,
if (err)
return err;
- di = dino (np->cache_id);
+ di = dino_ref (np->cache_id);
blkno = di->i_translator;
if (namelen && !blkno)
@@ -687,6 +699,7 @@ diskfs_set_translator (struct node *np, const char *name,
unsigned namelen,
0, 0, 0);
if (blkno == 0)
{
+ dino_deref (di);
diskfs_end_catch_exception ();
return ENOSPC;
}
@@ -710,15 +723,20 @@ diskfs_set_translator (struct node *np, const char *name,
unsigned namelen,
np->dn_stat.st_mode &= ~S_IPTRANS;
np->dn_set_ctime = 1;
}
+ else
+ dino_deref (di);
if (namelen)
{
+ void *blkptr;
+
buf[0] = namelen & 0xFF;
buf[1] = (namelen >> 8) & 0xFF;
bcopy (name, buf + 2, namelen);
- bcopy (buf, bptr (blkno), block_size);
- record_global_poke (bptr (blkno));
+ blkptr = disk_cache_block_ref (blkno);
+ memcpy (blkptr, buf, block_size);
+ record_global_poke (blkptr);
np->dn_stat.st_mode |= S_IPTRANS;
np->dn_set_ctime = 1;
@@ -736,7 +754,8 @@ diskfs_get_translator (struct node *np, char **namep,
unsigned *namelen)
error_t err = 0;
daddr_t blkno;
unsigned datalen;
- const void *transloc;
+ void *transloc;
+ struct ext2_inode *di;
assert (sblock->s_creator_os == EXT2_OS_HURD);
@@ -744,9 +763,11 @@ diskfs_get_translator (struct node *np, char **namep,
unsigned *namelen)
if (err)
return err;
- blkno = (dino (np->cache_id))->i_translator;
+ di = dino_ref (np->cache_id);
+ blkno = di->i_translator;
+ dino_deref (di);
assert (blkno);
- transloc = bptr (blkno);
+ transloc = disk_cache_block_ref (blkno);
datalen =
((unsigned char *)transloc)[0] + (((unsigned char *)transloc)[1] << 8);
@@ -761,6 +782,7 @@ diskfs_get_translator (struct node *np, char **namep,
unsigned *namelen)
memcpy (*namep, transloc + 2, datalen);
}
+ disk_cache_block_deref (transloc);
diskfs_end_catch_exception ();
*namelen = datalen;
diff --git a/ext2fs/pager.c b/ext2fs/pager.c
index f740434..6e99c83 100644
--- a/ext2fs/pager.c
+++ b/ext2fs/pager.c
@@ -18,17 +18,18 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <hurd/store.h>
#include "ext2fs.h"
+/* XXX */
+#include "../libpager/priv.h"
+
/* A ports bucket to hold pager ports. */
struct port_bucket *pager_bucket;
-/* Mapped image of the disk. */
-void *disk_image;
-
pthread_spinlock_t node_to_page_lock = PTHREAD_SPINLOCK_INITIALIZER;
@@ -165,6 +166,9 @@ file_pager_read_page (struct node *node, vm_offset_t page,
block_t pending_blocks = 0;
int num_pending_blocks = 0;
+ ext2_debug ("reading inode %llu page %lu[%u]",
+ node->cache_id, page, vm_page_size);
+
/* Read the NUM_PENDING_BLOCKS blocks in PENDING_BLOCKS, into the buffer
pointed to by BUF (allocating it if necessary) at offset OFFS. OFFS in
adjusted by the amount read, and NUM_PENDING_BLOCKS is zeroed. Any read
@@ -173,7 +177,8 @@ file_pager_read_page (struct node *node, vm_offset_t page,
{
if (num_pending_blocks > 0)
{
- block_t dev_block = pending_blocks << log2_dev_blocks_per_fs_block;
+ store_offset_t dev_block = (store_offset_t) pending_blocks
+ << log2_dev_blocks_per_fs_block;
size_t amount = num_pending_blocks << log2_block_size;
/* The buffer we try to read into; on the first read, we pass in a
size of zero, so that the read is guaranteed to allocate a new
@@ -297,7 +302,8 @@ pending_blocks_write (struct pending_blocks *pb)
if (pb->num > 0)
{
error_t err;
- block_t dev_block = pb->block << log2_dev_blocks_per_fs_block;
+ store_offset_t dev_block = (store_offset_t) pb->block
+ << log2_dev_blocks_per_fs_block;
size_t length = pb->num << log2_block_size, amount;
ext2_debug ("writing block %u[%ld]", pb->block, pb->num);
@@ -359,7 +365,7 @@ pending_blocks_add (struct pending_blocks *pb, block_t
block)
return 0;
}
-/* Write one page for the pager backing NODE, at offset PAGE, into BUF. This
+/* Write one page for the pager backing NODE, at OFFSET, into BUF. This
may need to write several filesystem blocks to satisfy one page, and tries
to consolidate the i/o if possible. */
static error_t
@@ -411,12 +417,28 @@ disk_pager_read_page (vm_offset_t page, void **buf, int
*writelock)
{
error_t err;
size_t length = vm_page_size, read = 0;
- vm_size_t dev_end = store->size;
+ store_offset_t offset = page, dev_end = store->size;
+ int index = offset >> log2_block_size;
+
+ pthread_mutex_lock (&disk_cache_lock);
+ offset = ((store_offset_t) disk_cache_info[index].block << log2_block_size)
+ + offset % block_size;
+ disk_cache_info[index].flags |= DC_INCORE;
+ disk_cache_info[index].flags &=~ DC_UNTOUCHED;
+#ifndef NDEBUG
+ disk_cache_info[index].last_read = disk_cache_info[index].block;
+ disk_cache_info[index].last_read_xor
+ = disk_cache_info[index].block ^ DISK_CACHE_LAST_READ_XOR;
+#endif
+ pthread_mutex_unlock (&disk_cache_lock);
+
+ ext2_debug ("(%lld)", offset >> log2_block_size);
- if (page + vm_page_size > dev_end)
- length = dev_end - page;
+ if (offset + vm_page_size > dev_end)
+ length = dev_end - offset;
- err = store_read (store, page >> store->log2_block_size, length, buf, &read);
+ err = store_read (store, offset >> store->log2_block_size, length,
+ buf, &read);
if (read != length)
return EIO;
if (!err && length != vm_page_size)
@@ -432,26 +454,38 @@ disk_pager_write_page (vm_offset_t page, void *buf)
{
error_t err = 0;
size_t length = vm_page_size, amount;
- vm_size_t dev_end = store->size;
+ store_offset_t offset = page, dev_end = store->size;
+ int index = offset >> log2_block_size;
+
+ pthread_mutex_lock (&disk_cache_lock);
+ assert (disk_cache_info[index].block != DC_NO_BLOCK);
+ offset = ((store_offset_t) disk_cache_info[index].block << log2_block_size)
+ + offset % block_size;
+#ifndef NDEBUG /* Not strictly needed. */
+ assert ((disk_cache_info[index].last_read ^ DISK_CACHE_LAST_READ_XOR)
+ == disk_cache_info[index].last_read_xor);
+ assert (disk_cache_info[index].last_read
+ == disk_cache_info[index].block);
+#endif
+ pthread_mutex_unlock (&disk_cache_lock);
- if (page + vm_page_size > dev_end)
- length = dev_end - page;
+ if (offset + vm_page_size > dev_end)
+ length = dev_end - offset;
- ext2_debug ("writing disk page %d[%d]", page, length);
+ ext2_debug ("writing disk page %lld[%zu]", offset, length);
STAT_INC (disk_pageouts);
if (modified_global_blocks)
/* Be picky about which blocks in a page that we write. */
{
- vm_offset_t offs = page;
struct pending_blocks pb;
pending_blocks_init (&pb, buf);
while (length > 0 && !err)
{
- block_t block = boffs_block (offs);
+ block_t block = boffs_block (offset);
/* We don't clear the block modified bit here because this paging
write request may not be the same one that actually set the bit,
@@ -469,7 +503,7 @@ disk_pager_write_page (vm_offset_t page, void *buf)
/* Otherwise just skip it. */
err = pending_blocks_skip (&pb);
- offs += block_size;
+ offset += block_size;
length -= block_size;
}
@@ -478,7 +512,7 @@ disk_pager_write_page (vm_offset_t page, void *buf)
}
else
{
- err = store_write (store, page >> store->log2_block_size,
+ err = store_write (store, offset >> store->log2_block_size,
buf, length, &amount);
if (!err && length != amount)
err = EIO;
@@ -486,6 +520,18 @@ disk_pager_write_page (vm_offset_t page, void *buf)
return err;
}
+
+static void
+disk_pager_notify_evict (vm_offset_t page)
+{
+ unsigned long index = page >> log2_block_size;
+
+ ext2_debug ("(block %lu)", index);
+
+ pthread_mutex_lock (&disk_cache_lock);
+ disk_cache_info[index].flags &= ~DC_INCORE;
+ pthread_mutex_unlock (&disk_cache_lock);
+}
/* Satisfy a pager read request for either the disk pager or file pager
PAGER, to the page at offset PAGE into BUF. WRITELOCK should be set if
@@ -511,6 +557,14 @@ pager_write_page (struct user_pager_info *pager,
vm_offset_t page,
else
return file_pager_write_page (pager->node, page, (void *)buf);
}
+
+void
+pager_notify_evict (struct user_pager_info *pager, vm_offset_t page)
+{
+ if (pager->type == DISK)
+ disk_pager_notify_evict (page);
+}
+
/* Make page PAGE writable, at least up to ALLOCSIZE. This function and
diskfs_grow are the only places that blocks are actually added to the
@@ -767,6 +821,373 @@ pager_dropweak (struct user_pager_info *p __attribute__
((unused)))
{
}
+/* Cached blocks from disk. */
+void *disk_cache;
+
+/* DISK_CACHE size in bytes and blocks. */
+store_offset_t disk_cache_size;
+int disk_cache_blocks;
+
+/* block num --> pointer to in-memory block */
+hurd_ihash_t disk_cache_bptr;
+/* Cached blocks' info. */
+struct disk_cache_info *disk_cache_info;
+/* Hint index for which cache block to reuse next. */
+int disk_cache_hint;
+/* Lock for these structures. */
+pthread_mutex_t disk_cache_lock;
+/* Fired when a re-association is done. */
+pthread_cond_t disk_cache_reassociation;
+
+/* Finish mapping initialization. */
+static void
+disk_cache_init (void)
+{
+ if (block_size != vm_page_size)
+ ext2_panic ("Block size %u != vm_page_size %u",
+ block_size, vm_page_size);
+
+ pthread_mutex_init (&disk_cache_lock, NULL);
+ pthread_cond_init (&disk_cache_reassociation, NULL);
+
+ /* Allocate space for block num -> in-memory pointer mapping. */
+ if (hurd_ihash_create (&disk_cache_bptr, HURD_IHASH_NO_LOCP))
+ ext2_panic ("Can't allocate memory for disk_pager_bptr");
+
+ /* Allocate space for disk cache blocks' info. */
+ disk_cache_info = malloc ((sizeof *disk_cache_info) * disk_cache_blocks);
+ if (!disk_cache_info)
+ ext2_panic ("Cannot allocate space for disk cache info");
+
+ /* Initialize disk_cache_info. */
+ for (int i = 0; i < disk_cache_blocks; i++)
+ {
+ disk_cache_info[i].block = DC_NO_BLOCK;
+ disk_cache_info[i].flags = 0;
+ disk_cache_info[i].ref_count = 0;
+#ifndef NDEBUG
+ disk_cache_info[i].last_read = DC_NO_BLOCK;
+ disk_cache_info[i].last_read_xor
+ = DC_NO_BLOCK ^ DISK_CACHE_LAST_READ_XOR;
+#endif
+ }
+ disk_cache_hint = 0;
+
+ /* Map the superblock and the block group descriptors. */
+ block_t fixed_first = boffs_block (SBLOCK_OFFS);
+ block_t fixed_last = fixed_first
+ + (round_block ((sizeof *group_desc_image) * groups_count)
+ >> log2_block_size);
+ ext2_debug ("%u-%u\n", fixed_first, fixed_last);
+ assert (fixed_last - fixed_first + 1 <= (block_t)disk_cache_blocks + 3);
+ for (block_t i = fixed_first; i <= fixed_last; i++)
+ {
+ disk_cache_block_ref (i);
+ assert (disk_cache_info[i-fixed_first].block == i);
+ disk_cache_info[i-fixed_first].flags |= DC_FIXED;
+ }
+}
+
+static void
+disk_cache_return_unused (void)
+{
+ int index;
+
+ /* XXX: Touch all pages. It seems that sometimes GNU Mach "forgets"
+ to notify us about evicted pages. Disk cache must be
+ unlocked. */
+ for (vm_offset_t i = 0; i < disk_cache_size; i += vm_page_size)
+ *(volatile char *)(disk_cache + i);
+
+ /* Release some references to cached blocks. */
+ pokel_sync (&global_pokel, 1);
+
+ /* Return unused pages that are in core. */
+ int pending_begin = -1, pending_end = -1;
+ pthread_mutex_lock (&disk_cache_lock);
+ for (index = 0; index < disk_cache_blocks; index++)
+ if (! (disk_cache_info[index].flags & (DC_DONT_REUSE & ~DC_INCORE))
+ && ! disk_cache_info[index].ref_count)
+ {
+ ext2_debug ("return %u -> %d",
+ disk_cache_info[index].block, index);
+ if (index != pending_end)
+ {
+ /* Return previous region, if there is such, ... */
+ if (pending_end >= 0)
+ {
+ pthread_mutex_unlock (&disk_cache_lock);
+ pager_return_some (diskfs_disk_pager,
+ pending_begin * vm_page_size,
+ (pending_end - pending_begin)
+ * vm_page_size, 1);
+ pthread_mutex_lock (&disk_cache_lock);
+ }
+ /* ... and start new region. */
+ pending_begin = index;
+ }
+ pending_end = index + 1;
+ }
+
+ pthread_mutex_unlock (&disk_cache_lock);
+
+ /* Return last region, if there is such. */
+ if (pending_end >= 0)
+ pager_return_some (diskfs_disk_pager,
+ pending_begin * vm_page_size,
+ (pending_end - pending_begin) * vm_page_size,
+ 1);
+ else
+ {
+ printf ("ext2fs: disk cache is starving\n");
+
+ /* Give it some time. This should happen rarely. */
+ sleep (1);
+ }
+}
+
+/* Map block and return pointer to it. */
+void *
+disk_cache_block_ref (block_t block)
+{
+ int index;
+ void *bptr;
+
+ assert (0 <= block && block < store->size >> log2_block_size);
+
+ ext2_debug ("(%u)", block);
+
+retry_ref:
+ pthread_mutex_lock (&disk_cache_lock);
+
+ bptr = hurd_ihash_find (disk_cache_bptr, block);
+ if (bptr)
+ /* Already mapped. */
+ {
+ index = bptr_index (bptr);
+
+ /* In process of re-associating? */
+ if (disk_cache_info[index].flags & DC_UNTOUCHED)
+ {
+ /* Wait re-association to finish. */
+ pthread_cond_wait (&disk_cache_reassociation, &disk_cache_lock);
+ pthread_mutex_unlock (&disk_cache_lock);
+
+#if 0
+ printf ("Re-association -- wait finished.\n");
+#endif
+
+ goto retry_ref;
+ }
+
+ /* Just increment reference and return. */
+ assert (disk_cache_info[index].ref_count + 1
+ > disk_cache_info[index].ref_count);
+ disk_cache_info[index].ref_count++;
+
+ ext2_debug ("cached %u -> %d (ref_count = %hu, flags = %#hx, ptr = %p)",
+ disk_cache_info[index].block, index,
+ disk_cache_info[index].ref_count,
+ disk_cache_info[index].flags, bptr);
+
+ pthread_mutex_unlock (&disk_cache_lock);
+
+ return bptr;
+ }
+
+ /* Search for a block that is not in core and is not referenced. */
+ index = disk_cache_hint;
+ while ((disk_cache_info[index].flags & DC_DONT_REUSE)
+ || (disk_cache_info[index].ref_count))
+ {
+ ext2_debug ("reject %u -> %d (ref_count = %hu, flags = %#hx)",
+ disk_cache_info[index].block, index,
+ disk_cache_info[index].ref_count,
+ disk_cache_info[index].flags);
+
+ /* Just move to next block. */
+ index++;
+ if (index >= disk_cache_blocks)
+ index -= disk_cache_blocks;
+
+ /* If we return to where we started, than there is no suitable
+ block. */
+ if (index == disk_cache_hint)
+ break;
+ }
+
+ /* The next place in the disk cache becomes the current hint. */
+ disk_cache_hint = index + 1;
+ if (disk_cache_hint >= disk_cache_blocks)
+ disk_cache_hint -= disk_cache_blocks;
+
+ /* Is suitable place found? */
+ if ((disk_cache_info[index].flags & DC_DONT_REUSE)
+ || disk_cache_info[index].ref_count)
+ /* No place is found. Try to release some blocks and try
+ again. */
+ {
+ ext2_debug ("flush %u -> %d", disk_cache_info[index].block, index);
+
+ pthread_mutex_unlock (&disk_cache_lock);
+
+ disk_cache_return_unused ();
+
+ goto retry_ref;
+ }
+
+ /* Suitable place is found. */
+
+ /* Calculate pointer to data. */
+ bptr = (char *)disk_cache + (index << log2_block_size);
+ ext2_debug ("map %u -> %d (%p)", block, index, bptr);
+
+ /* This pager_return_some is used only to set PM_FORCEREAD for the
+ page. DC_UNTOUCHED is set so that we catch if someone has
+ referenced the block while we didn't hold disk_cache_lock. */
+ disk_cache_info[index].flags |= DC_UNTOUCHED;
+
+#if 0 /* XXX: Let's see if this is needed at all. */
+
+ pthread_mutex_unlock (&disk_cache_lock);
+ pager_return_some (diskfs_disk_pager, bptr - disk_cache, vm_page_size, 1);
+ pthread_mutex_lock (&disk_cache_lock);
+
+ /* Has someone used our bptr? Has someone mapped requested block
+ while we have unlocked disk_cache_lock? If so, environment has
+ changed and we have to restart operation. */
+ if ((! (disk_cache_info[index].flags & DC_UNTOUCHED))
+ || hurd_ihash_find (disk_cache_bptr, block))
+ {
+ pthread_mutex_unlock (&disk_cache_lock);
+ goto retry_ref;
+ }
+
+#elif 0
+
+ /* XXX: Use libpager internals. */
+
+ pthread_mutex_lock (&diskfs_disk_pager->interlock);
+ int page = (bptr - disk_cache) / vm_page_size;
+ assert (page >= 0);
+ int is_incore = (page < diskfs_disk_pager->pagemapsize
+ && (diskfs_disk_pager->pagemap[page] & PM_INCORE));
+ pthread_mutex_unlock (&diskfs_disk_pager->interlock);
+ if (is_incore)
+ {
+ pthread_mutex_unlock (&disk_cache_lock);
+ printf ("INCORE\n");
+ goto retry_ref;
+ }
+
+#endif
+
+ /* Re-associate. */
+ if (disk_cache_info[index].block != DC_NO_BLOCK)
+ /* Remove old association. */
+ hurd_ihash_remove (disk_cache_bptr, disk_cache_info[index].block);
+ /* New association. */
+ if (hurd_ihash_add (disk_cache_bptr, block, bptr))
+ ext2_panic ("Couldn't hurd_ihash_add new disk block");
+ assert (! (disk_cache_info[index].flags & DC_DONT_REUSE & ~DC_UNTOUCHED));
+ disk_cache_info[index].block = block;
+ assert (! disk_cache_info[index].ref_count);
+ disk_cache_info[index].ref_count = 1;
+
+ /* All data structures are set up. */
+ pthread_mutex_unlock (&disk_cache_lock);
+
+ /* Try to read page. */
+ *(volatile char *) bptr;
+
+ /* Check if it's actually read. */
+ pthread_mutex_lock (&disk_cache_lock);
+ if (disk_cache_info[index].flags & DC_UNTOUCHED)
+ /* It's not read. */
+ {
+ /* Remove newly created association. */
+ hurd_ihash_remove (disk_cache_bptr, block);
+ disk_cache_info[index].block = DC_NO_BLOCK;
+ disk_cache_info[index].flags &=~ DC_UNTOUCHED;
+ disk_cache_info[index].ref_count = 0;
+ pthread_mutex_unlock (&disk_cache_lock);
+
+ /* Prepare next time association of this page to succeed. */
+ pager_flush_some (diskfs_disk_pager, bptr - disk_cache,
+ vm_page_size, 0);
+
+#if 0
+ printf ("Re-association failed.\n");
+#endif
+
+ goto retry_ref;
+ }
+
+ /* Re-association was successful. */
+ pthread_cond_broadcast (&disk_cache_reassociation);
+
+ pthread_mutex_unlock (&disk_cache_lock);
+
+ ext2_debug ("(%u) = %p", block, bptr);
+ return bptr;
+}
+
+void
+disk_cache_block_ref_ptr (void *ptr)
+{
+ int index;
+
+ pthread_mutex_lock (&disk_cache_lock);
+ index = bptr_index (ptr);
+ assert (disk_cache_info[index].ref_count >= 1);
+ assert (disk_cache_info[index].ref_count + 1
+ > disk_cache_info[index].ref_count);
+ disk_cache_info[index].ref_count++;
+ assert (! (disk_cache_info[index].flags & DC_UNTOUCHED));
+ ext2_debug ("(%p) (ref_count = %hu, flags = %#hx)",
+ ptr,
+ disk_cache_info[index].ref_count,
+ disk_cache_info[index].flags);
+ pthread_mutex_unlock (&disk_cache_lock);
+}
+
+void
+disk_cache_block_deref (void *ptr)
+{
+ int index;
+
+ assert (disk_cache <= ptr && ptr <= disk_cache + disk_cache_size);
+
+ pthread_mutex_lock (&disk_cache_lock);
+ index = bptr_index (ptr);
+ ext2_debug ("(%p) (ref_count = %hu, flags = %#hx)",
+ ptr,
+ disk_cache_info[index].ref_count - 1,
+ disk_cache_info[index].flags);
+ assert (! (disk_cache_info[index].flags & DC_UNTOUCHED));
+ assert (disk_cache_info[index].ref_count >= 1);
+ disk_cache_info[index].ref_count--;
+ pthread_mutex_unlock (&disk_cache_lock);
+}
+
+/* Not used. */
+int
+disk_cache_block_is_ref (block_t block)
+{
+ int ref;
+ void *ptr;
+
+ pthread_mutex_lock (&disk_cache_lock);
+ ptr = hurd_ihash_find (disk_cache_bptr, block);
+ if (ptr == NULL)
+ ref = 0;
+ else /* XXX: Should check for DC_UNTOUCHED too. */
+ ref = disk_cache_info[bptr_index (ptr)].ref_count;
+ pthread_mutex_unlock (&disk_cache_lock);
+
+ return ref;
+}
+
/* Create the DISK pager. */
void
create_disk_pager (void)
@@ -776,8 +1197,12 @@ create_disk_pager (void)
ext2_panic ("can't create disk pager: %s", strerror (errno));
upi->type = DISK;
pager_bucket = ports_create_bucket ();
- diskfs_start_disk_pager (upi, pager_bucket, MAY_CACHE, store->size,
- &disk_image);
+ get_hypermetadata ();
+ disk_cache_blocks = DISK_CACHE_BLOCKS;
+ disk_cache_size = disk_cache_blocks << log2_block_size;
+ diskfs_start_disk_pager (upi, pager_bucket, MAY_CACHE, 1,
+ disk_cache_size, &disk_cache);
+ disk_cache_init ();
}
/* Call this to create a FILE_DATA pager and return a send right.
@@ -817,7 +1242,7 @@ diskfs_get_filemap (struct node *node, vm_prot_t prot)
diskfs_nref_light (node);
node->dn->pager =
pager_create (upi, pager_bucket, MAY_CACHE,
- MEMORY_OBJECT_COPY_DELAY);
+ MEMORY_OBJECT_COPY_DELAY, 0);
if (node->dn->pager == 0)
{
diskfs_nrele_light (node);
diff --git a/ext2fs/pokel.c b/ext2fs/pokel.c
index a8b16c9..3afb32e 100644
--- a/ext2fs/pokel.c
+++ b/ext2fs/pokel.c
@@ -67,12 +67,27 @@ pokel_add (struct pokel *pokel, void *loc, vm_size_t length)
vm_offset_t p_offs = pl->offset;
vm_size_t p_end = p_offs + pl->length;
- if (p_offs == offset && p_end == end)
- break;
+ if (p_offs <= offset && end <= p_end)
+ {
+ if (pokel->image == disk_cache)
+ for (vm_offset_t i = offset; i < end; i += block_size)
+ disk_cache_block_deref (disk_cache + i);
+
+ break;
+ }
else if (p_end >= offset && end >= p_offs)
{
pl->offset = offset < p_offs ? offset : p_offs;
pl->length = (end > p_end ? end : p_end) - pl->offset;
+
+ if (pokel->image == disk_cache)
+ {
+ vm_offset_t i_begin = p_offs > offset ? p_offs : offset;
+ vm_offset_t i_end = p_end < end ? p_end : end;
+ for (vm_offset_t i = i_begin; i < i_end; i += block_size)
+ disk_cache_block_deref (disk_cache + i);
+ }
+
ext2_debug ("extended 0x%x[%ul] to 0x%x[%ul]",
p_offs, p_end - p_offs, pl->offset, pl->length);
break;
@@ -113,11 +128,21 @@ _pokel_exec (struct pokel *pokel, int sync, int wait)
pthread_spin_unlock (&pokel->lock);
for (pl = pokes; pl; last = pl, pl = pl->next)
- if (sync)
- {
- ext2_debug ("syncing 0x%x[%ul]", pl->offset, pl->length);
- pager_sync_some (pokel->pager, pl->offset, pl->length, wait);
- }
+ {
+ if (sync)
+ {
+ ext2_debug ("syncing 0x%lx[%ul]", pl->offset, pl->length);
+ pager_sync_some (pokel->pager, pl->offset, pl->length, wait);
+ }
+
+ if (pokel->image == disk_cache)
+ {
+ vm_offset_t begin = trunc_block (pl->offset);
+ vm_offset_t end = round_block (pl->offset + pl->length);
+ for (vm_offset_t i = begin; i != end; i += block_size)
+ disk_cache_block_deref (pokel->image + i);
+ }
+ }
if (last)
{
diff --git a/ext2fs/truncate.c b/ext2fs/truncate.c
index 37e360b..63d2295 100644
--- a/ext2fs/truncate.c
+++ b/ext2fs/truncate.c
@@ -124,7 +124,7 @@ trunc_indirect (struct node *node, block_t end,
{
unsigned index;
int modified = 0, all_freed = 1;
- block_t *ind_bh = (block_t *)bptr (*p);
+ block_t *ind_bh = (block_t *) disk_cache_block_ref (*p);
unsigned first = end < offset ? 0 : end - offset;
for (index = first; index < addr_per_block; index++)
@@ -139,11 +139,16 @@ trunc_indirect (struct node *node, block_t end,
if (first == 0 && all_freed)
{
- pager_flush_some (diskfs_disk_pager, boffs (*p), block_size, 1);
+ pager_flush_some (diskfs_disk_pager,
+ bptr_index (ind_bh) << log2_block_size,
+ block_size, 1);
free_block_run_free_ptr (fbr, p);
+ disk_cache_block_deref (ind_bh);
}
else if (modified)
record_indir_poke (node, ind_bh);
+ else
+ disk_cache_block_deref (ind_bh);
}
}
diff --git a/fatfs/pager.c b/fatfs/pager.c
index f892c88..8146e64 100644
--- a/fatfs/pager.c
+++ b/fatfs/pager.c
@@ -596,6 +596,13 @@ pager_unlock_page (struct user_pager_info *pager,
return 0;
}
+void
+pager_notify_evict (struct user_pager_info *pager,
+ vm_offset_t page)
+{
+ assert (!"unrequested notification on eviction");
+}
+
/* Grow the disk allocated to locked node NODE to be at least SIZE
bytes, and set NODE->allocsize to the actual allocated size. (If
the allocated size is already SIZE bytes, do nothing.) CRED
@@ -752,7 +759,7 @@ create_fat_pager (void)
struct user_pager_info *upi = malloc (sizeof (struct user_pager_info));
upi->type = FAT;
pager_bucket = ports_create_bucket ();
- diskfs_start_disk_pager (upi, pager_bucket, MAY_CACHE,
+ diskfs_start_disk_pager (upi, pager_bucket, MAY_CACHE, 0,
bytes_per_sector * sectors_per_fat,
&fat_image);
}
@@ -794,7 +801,7 @@ diskfs_get_filemap (struct node *node, vm_prot_t prot)
diskfs_nref_light (node);
node->dn->pager =
pager_create (upi, pager_bucket, MAY_CACHE,
- MEMORY_OBJECT_COPY_DELAY);
+ MEMORY_OBJECT_COPY_DELAY, 0);
if (node->dn->pager == 0)
{
diskfs_nrele_light (node);
diff --git a/hurd/fsys.defs b/hurd/fsys.defs
index 979a6cf..c031da7 100644
--- a/hurd/fsys.defs
+++ b/hurd/fsys.defs
@@ -1,5 +1,5 @@
/* Definitions for the filesystem control interface
- Copyright (C) 1992,93,94,95,96,97, 2002 Free Software Foundation
+ Copyright (C) 1992,93,94,95,96,97, 2002,13 Free Software Foundation
This file is part of the GNU Hurd.
@@ -127,3 +127,23 @@ routine fsys_get_options (
server: fsys_t;
RPT
out options: data_t, dealloc);
+
+/* Return any active translators bound to nodes of the receiving
+ filesystem. CHILDREN is an argz vector containing file names
+ relative to the root of the receiving translator. */
+routine fsys_get_children (
+ server: fsys_t;
+ RPT
+ out children: data_t);
+
+/* Return information about the source of the receiving filesystem.
+ If the concept of a source is applicable, SOURCE should refer to
+ the source of the receiving translator and should be a description
+ considered appropriate in the context of the translator. For
+ example for the case of block device based filesystems, SOURCE
+ should be the file name of the underlying block device. */
+routine fsys_get_source (
+ server: fsys_t;
+ RPT
+ out source: string_t);
+
diff --git a/hurd/fsys_reply.defs b/hurd/fsys_reply.defs
index e203169..2f5b035 100644
--- a/hurd/fsys_reply.defs
+++ b/hurd/fsys_reply.defs
@@ -1,6 +1,6 @@
/* Reply half of fsys
- Copyright (C) 1991, 1993, 1994, 1995, 2001, 2007
+ Copyright (C) 1991, 1993, 1994, 1995, 2001, 2007, 2013
Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -76,3 +76,13 @@ simpleroutine fsys_get_options_reply (
reply_port: reply_port_t;
RETURN_CODE_ARG;
options: data_t);
+
+simpleroutine fsys_get_children (
+ server: fsys_t;
+ RETURN_CODE_ARG;
+ children: data_t);
+
+simpleroutine fsys_get_source (
+ server: fsys_t;
+ RETURN_CODE_ARG;
+ source: string_t);
diff --git a/hurd/process.defs b/hurd/process.defs
index 43cc9f2..bf90556 100644
--- a/hurd/process.defs
+++ b/hurd/process.defs
@@ -1,5 +1,5 @@
/* Definitions for process server interface
- Copyright (C) 1992,93,94,95,96,97,2001 Free Software Foundation
+ Copyright (C) 1992,93,94,95,96,97,2001,2013 Free Software Foundation
This file is part of the GNU Hurd.
@@ -370,3 +370,33 @@ routine proc_getnports (
process: process_t;
which: pid_t;
out nports: mach_msg_type_number_t);
+
+/*** Routines related to early server bootstrapping ***/
+
+skip; /* Reserved for proc_set_init_task */
+
+/* Inform the process server that the process is important. */
+routine proc_mark_important (
+ process: process_t);
+
+/* Query whether the process is important. */
+routine proc_is_important (
+ process: process_t;
+ out essential: boolean_t);
+
+/* Set the processes start_code and end_code locations. Any
+ executable segments loaded from the ELF binary are in this
+ range. */
+routine proc_set_code (
+ process: process_t;
+ start_code: vm_address_t;
+ end_code: vm_address_t);
+
+/* Get the processes start_code and end_code locations. Any
+ executable segments loaded from the ELF binary are in this range.
+ If zero is returned for these values, the requested information has
+ never been set. */
+routine proc_get_code (
+ process: process_t;
+ out start_code: vm_address_t;
+ out end_code: vm_address_t);
diff --git a/hurd/process_reply.defs b/hurd/process_reply.defs
index 80d3929..66a7551 100644
--- a/hurd/process_reply.defs
+++ b/hurd/process_reply.defs
@@ -1,5 +1,5 @@
/* Reply half of wait
- Copyright (C) 1991,93,94,96,2001 Free Software Foundation, Inc.
+ Copyright (C) 1991,93,94,96,2001,13 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -60,3 +60,135 @@ simpleroutine proc_wait_reply (
in sigcode: int;
in rusage: rusage_t;
in pid_status: pid_t);
+
+skip; /* proc_dostop */
+skip; /* proc_handle_exceptions */
+skip; /* proc_mark_stop */
+skip; /* proc_mark_cont */
+skip; /* proc_mark_exit */
+skip; /* proc_mark_exec */
+skip; /* proc_mark_traced */
+skip; /* proc_mod_stopchild */
+
+simpleroutine proc_pid2task (
+ reply_port: reply_port_t;
+ RETURN_CODE_ARG;
+ task: task_t);
+
+simpleroutine proc_task2pid (
+ reply_port: reply_port_t;
+ RETURN_CODE_ARG;
+ pid: pid_t);
+
+simpleroutine proc_task2proc (
+ reply_port: reply_port_t;
+ RETURN_CODE_ARG;
+ proc: mach_port_make_send_t);
+
+simpleroutine proc_proc2task (
+ reply_port: reply_port_t;
+ RETURN_CODE_ARG;
+ task: task_t);
+
+simpleroutine proc_pid2proc (
+ reply_port: reply_port_t;
+ RETURN_CODE_ARG;
+ proc: mach_port_make_send_t);
+
+simpleroutine proc_getprocinfo (
+ reply_port: reply_port_t;
+ RETURN_CODE_ARG;
+ flags: int;
+ procinfo: procinfo_t, dealloc;
+ threadwaits: data_t, dealloc);
+
+simpleroutine proc_getprocargs (
+ reply_port: reply_port_t;
+ RETURN_CODE_ARG;
+ procargs: data_t, dealloc);
+
+simpleroutine proc_getprocenv (
+ reply_port: reply_port_t;
+ RETURN_CODE_ARG;
+ procenv: data_t, dealloc);
+
+skip; /* proc_make_login_coll */
+
+simpleroutine proc_getloginid (
+ reply_port: reply_port_t;
+ RETURN_CODE_ARG;
+ login_id: pid_t);
+
+simpleroutine proc_getloginpids (
+ reply_port: reply_port_t;
+ RETURN_CODE_ARG;
+ pids: pidarray_t, dealloc);
+
+skip; /* proc_setlogin */
+
+simpleroutine proc_getlogin (
+ reply_port: reply_port_t;
+ RETURN_CODE_ARG;
+ logname: string_t);
+
+skip; /* proc_setsid */
+
+simpleroutine proc_getsid (
+ reply_port: reply_port_t;
+ RETURN_CODE_ARG;
+ sid: pid_t);
+
+simpleroutine proc_getsessionpgids (
+ reply_port: reply_port_t;
+ RETURN_CODE_ARG;
+ pgidset: pidarray_t, dealloc);
+
+simpleroutine proc_getsessionpids (
+ reply_port: reply_port_t;
+ RETURN_CODE_ARG;
+ pidset: pidarray_t, dealloc);
+
+simpleroutine proc_getsidport (
+ reply_port: reply_port_t;
+ RETURN_CODE_ARG;
+ sessport: mach_port_send_t);
+
+skip; /* proc_setpgrp */
+
+simpleroutine proc_getpgrp (
+ reply_port: reply_port_t;
+ RETURN_CODE_ARG;
+ pgrp: pid_t);
+
+simpleroutine proc_getpgrppids (
+ reply_port: reply_port_t;
+ RETURN_CODE_ARG;
+ pidset: pidarray_t, dealloc);
+
+simpleroutine proc_get_tty (
+ reply_port: reply_port_t;
+ RETURN_CODE_ARG;
+ tty: mach_port_send_t);
+
+simpleroutine proc_getnports (
+ reply_port: reply_port_t;
+ RETURN_CODE_ARG;
+ nports: mach_msg_type_number_t);
+
+/*** Routines related to early server bootstrapping ***/
+
+skip; /* Reserved for proc_set_init_task */
+skip; /* proc_mark_important */
+
+simpleroutine proc_is_important (
+ reply_port: reply_port_t;
+ RETURN_CODE_ARG;
+ essential: boolean_t);
+
+skip; /* proc_set_code */
+
+simpleroutine proc_get_code (
+ reply_port: reply_port_t;
+ RETURN_CODE_ARG;
+ start_code: vm_address_t;
+ end_code: vm_address_t);
diff --git a/hurd/process_request.defs b/hurd/process_request.defs
index 80a2828..38e7146 100644
--- a/hurd/process_request.defs
+++ b/hurd/process_request.defs
@@ -1,6 +1,6 @@
/* Definitions for process server interface (request-only version)
- Copyright (C) 1992, 93, 94, 95, 96, 98 Free Software Foundation, Inc.
+ Copyright (C) 1992, 93, 94, 95, 96, 98, 2013 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -371,3 +371,34 @@ simpleroutine proc_getnports_request (
process: process_t;
ureplyport reply: reply_port_t;
which: pid_t);
+
+/*** Routines related to early server bootstrapping ***/
+
+skip; /* Reserved for proc_set_init_task */
+
+/* Inform the process server that the process is important. */
+simpleroutine proc_mark_important_request (
+ process: process_t;
+ ureplyport reply: reply_port_t);
+
+/* Query whether the process is important. */
+simpleroutine proc_is_important_request (
+ process: process_t;
+ ureplyport reply: reply_port_t);
+
+/* Set the processes start_code and end_code locations. Any
+ executable segments loaded from the ELF binary are in this
+ range. */
+simpleroutine proc_set_code_request (
+ process: process_t;
+ ureplyport reply: reply_port_t;
+ start_code: vm_address_t;
+ end_code: vm_address_t);
+
+/* Get the processes start_code and end_code locations. Any
+ executable segments loaded from the ELF binary are in this range.
+ If zero is returned for these values, the requested information has
+ never been set. */
+simpleroutine proc_get_code_request (
+ process: process_t;
+ ureplyport reply: reply_port_t);
diff --git a/include/pids.h b/include/pids.h
new file mode 100644
index 0000000..485916b
--- /dev/null
+++ b/include/pids.h
@@ -0,0 +1,29 @@
+/* List of special processes.
+
+ Copyright (C) 2013 Free Software Foundation
+ Written by Justus Winter <address@hidden>
+
+ This file is part of the GNU Hurd.
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _HURD_PROCESSES_H
+#define _HURD_PROCESSES_H
+
+#define HURD_PID_PROC 0
+#define HURD_PID_STARTUP 1
+#define HURD_PID_KERNEL 2
+
+#endif /* _HURD_PROCESSES_H */
diff --git a/init/init.c b/init/init.c
index 930408e..94f1a9b 100644
--- a/init/init.c
+++ b/init/init.c
@@ -1,7 +1,7 @@
/* Start and maintain hurd core servers and system run state
Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2005, 2008 Free Software Foundation, Inc.
+ 2005, 2008, 2013 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
@@ -49,6 +49,7 @@
#include <maptime.h>
#include <version.h>
#include <argp.h>
+#include <pids.h>
#include "startup_notify_U.h"
#include "startup_reply_U.h"
@@ -642,6 +643,8 @@ launch_core_servers (void)
device_master = 0;
}
+ /* Mark us as important. */
+ proc_mark_important (procserver);
proc_mark_exec (procserver);
/* Declare that the filesystem and auth are our children. */
@@ -649,6 +652,7 @@ launch_core_servers (void)
proc_child (procserver, authtask);
proc_task2proc (procserver, authtask, &authproc);
+ proc_mark_important (authproc);
proc_mark_exec (authproc);
startup_authinit_reply (authreply, authreplytype, 0, authproc,
MACH_MSG_TYPE_COPY_SEND);
@@ -671,6 +675,7 @@ launch_core_servers (void)
err = proc_task2proc (procserver, proctask, &procproc);
if (!err)
{
+ proc_mark_important (procproc);
proc_mark_exec (procproc);
mach_port_deallocate (mach_task_self (), procproc);
}
@@ -680,6 +685,7 @@ launch_core_servers (void)
/* Get the bootstrap filesystem's proc server port.
We must do this before calling proc_setmsgport below. */
proc_task2proc (procserver, fstask, &fsproc);
+ proc_mark_important (fsproc);
proc_mark_exec (fsproc);
#if 0
@@ -770,7 +776,7 @@ frob_kernel_process (void)
task_t task;
process_t proc, kbs;
- err = proc_pid2task (procserver, 2, &task);
+ err = proc_pid2task (procserver, HURD_PID_KERNEL, &task);
if (err)
{
error (0, err, "cannot get kernel task port");
@@ -784,8 +790,10 @@ frob_kernel_process (void)
return;
}
- /* Mark the kernel task as an essential task so that we never
- want to task_terminate it. */
+ /* Mark the kernel task as an essential task so that we or the proc server
+ never want to task_terminate it. */
+ proc_mark_important (proc);
+
err = record_essential_task ("kernel", task);
assert_perror (err);
@@ -1066,6 +1074,7 @@ start_child (const char *prog, char **progargs)
default_ports, MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX,
default_ints, INIT_INT_MAX,
NULL, 0, NULL, 0);
+ proc_mark_important (default_ports[INIT_PORT_PROC]);
mach_port_deallocate (mach_task_self (), default_ports[INIT_PORT_PROC]);
mach_port_deallocate (mach_task_self (), file);
if (err)
@@ -1206,7 +1215,12 @@ S_startup_essential_task (mach_port_t server,
if (!strcmp (name, "auth"))
authinit = 1;
else if (!strcmp (name, "exec"))
- execinit = 1;
+ {
+ execinit = 1;
+ mach_port_t execproc;
+ proc_task2proc (procserver, task, &execproc);
+ proc_mark_important (execproc);
+ }
else if (!strcmp (name, "proc"))
procinit = 1;
diff --git a/isofs/pager.c b/isofs/pager.c
index f93e0c8..7a38ba3 100644
--- a/isofs/pager.c
+++ b/isofs/pager.c
@@ -94,6 +94,13 @@ pager_unlock_page (struct user_pager_info *pager,
return EROFS;
}
+void
+pager_notify_evict (struct user_pager_info *pager,
+ vm_offset_t page)
+{
+ assert (!"unrequested notification on eviction");
+}
+
/* Tell how big the file is. */
error_t
pager_report_extent (struct user_pager_info *pager,
@@ -137,7 +144,7 @@ create_disk_pager (void)
upi->type = DISK;
upi->np = 0;
pager_bucket = ports_create_bucket ();
- diskfs_start_disk_pager (upi, pager_bucket, 1, store->size, &disk_image);
+ diskfs_start_disk_pager (upi, pager_bucket, 1, 0, store->size, &disk_image);
upi->p = diskfs_disk_pager;
}
@@ -168,7 +175,8 @@ diskfs_get_filemap (struct node *np, vm_prot_t prot)
upi->type = FILE_DATA;
upi->np = np;
diskfs_nref_light (np);
- upi->p = pager_create (upi, pager_bucket, 1, MEMORY_OBJECT_COPY_DELAY);
+ upi->p = pager_create (upi, pager_bucket, 1,
+ MEMORY_OBJECT_COPY_DELAY, 0);
if (upi->p == 0)
{
diskfs_nrele_light (np);
diff --git a/libdiskfs/Makefile b/libdiskfs/Makefile
index 3c8de4c..03c2e2b 100644
--- a/libdiskfs/Makefile
+++ b/libdiskfs/Makefile
@@ -34,7 +34,8 @@ IOSRCS= io-async-icky.c io-async.c io-duplicate.c
io-get-conch.c io-revoke.c \
io-reauthenticate.c io-rel-conch.c io-restrict-auth.c io-seek.c \
io-select.c io-stat.c io-stubs.c io-write.c io-version.c io-sigio.c
FSYSSRCS=fsys-getroot.c fsys-goaway.c fsys-startup.c fsys-getfile.c \
- fsys-options.c fsys-syncfs.c fsys-forward.c
+ fsys-options.c fsys-syncfs.c fsys-forward.c \
+ fsys-get-children.c fsys-get-source.c
IFSOCKSRCS=ifsock.c
OTHERSRCS = conch-fetch.c conch-set.c dir-clear.c dir-init.c dir-renamed.c \
extern-inline.c \
@@ -51,7 +52,7 @@ OTHERSRCS = conch-fetch.c conch-set.c dir-clear.c dir-init.c
dir-renamed.c \
remount.c console.c disk-pager.c \
name-cache.c direnter.c dirrewrite.c dirremove.c lookup.c dead-name.c \
validate-mode.c validate-group.c validate-author.c validate-flags.c \
- validate-rdev.c validate-owner.c extra-version.c
+ validate-rdev.c validate-owner.c extra-version.c get-source.c
SRCS = $(OTHERSRCS) $(FSSRCS) $(IOSRCS) $(FSYSSRCS) $(IFSOCKSRCS)
installhdrs = diskfs.h diskfs-pager.h
diff --git a/libdiskfs/boot-start.c b/libdiskfs/boot-start.c
index b62d5f3..6d9a773 100644
--- a/libdiskfs/boot-start.c
+++ b/libdiskfs/boot-start.c
@@ -33,6 +33,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA
02139, USA. */
#include <string.h>
#include <argz.h>
#include <error.h>
+#include <pids.h>
#include "fsys_S.h"
#include "fsys_reply_U.h"
@@ -606,7 +607,7 @@ diskfs_S_fsys_init (mach_port_t port,
proc_register_version (procserver, host, diskfs_server_name, "",
diskfs_server_version);
- err = proc_getmsgport (procserver, 1, &startup);
+ err = proc_getmsgport (procserver, HURD_PID_STARTUP, &startup);
if (!err)
{
startup_essential_task (startup, mach_task_self (), MACH_PORT_NULL,
diff --git a/libdiskfs/dead-name.c b/libdiskfs/dead-name.c
index 760b36f..6ca208e 100644
--- a/libdiskfs/dead-name.c
+++ b/libdiskfs/dead-name.c
@@ -40,6 +40,8 @@ ports_dead_name (void *notify, mach_port_t dead_name)
else
pthread_mutex_unlock (&np->lock);
}
-
+
+ fshelp_remove_active_translator (dead_name);
+
ports_interrupt_notified_rpcs (notify, dead_name, MACH_NOTIFY_DEAD_NAME);
}
diff --git a/libdiskfs/dir-lookup.c b/libdiskfs/dir-lookup.c
index 923be03..15a9b0c 100644
--- a/libdiskfs/dir-lookup.c
+++ b/libdiskfs/dir-lookup.c
@@ -1,6 +1,6 @@
/* libdiskfs implementation of fs.defs:dir_lookup
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
- 2002, 2008 Free Software Foundation, Inc.
+ 2002, 2008, 2013 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
@@ -41,6 +41,7 @@ diskfs_S_dir_lookup (struct protid *dircred,
struct node *np;
int nsymlink = 0;
char *nextname;
+ char *relpath;
int nextnamelen;
error_t error = 0;
char *pathbuf = 0;
@@ -68,6 +69,11 @@ diskfs_S_dir_lookup (struct protid *dircred,
while (path[0] == '/')
path++;
+ /* Preserve the path relative to diruser->po->path. */
+ relpath = strdup (path);
+ if (! relpath)
+ return ENOMEM;
+
*returned_port_poly = MACH_MSG_TYPE_MAKE_SEND;
*retry = FS_RETRY_NORMAL;
retryname[0] = '\0';
@@ -479,6 +485,22 @@ diskfs_S_dir_lookup (struct protid *dircred,
if (! error)
{
+ free (newpi->po->path);
+ if (dircred->po->path == NULL)
+ {
+ /* dircred is the root directory. */
+ newpi->po->path = relpath;
+ relpath = NULL; /* Do not free relpath. */
+ }
+ else
+ {
+ newpi->po->path = NULL;
+ asprintf (&newpi->po->path, "%s/%s", dircred->po->path, relpath);
+ }
+
+ if (! newpi->po->path)
+ error = errno;
+
*returned_port = ports_get_right (newpi);
ports_port_deref (newpi);
newpi = 0;
@@ -500,5 +522,7 @@ diskfs_S_dir_lookup (struct protid *dircred,
if (newpo)
diskfs_release_peropen (newpo);
+ free (relpath);
+
return error;
}
diff --git a/libdiskfs/disk-pager.c b/libdiskfs/disk-pager.c
index 5795a28..8fe8f80 100644
--- a/libdiskfs/disk-pager.c
+++ b/libdiskfs/disk-pager.c
@@ -49,7 +49,8 @@ service_paging_requests (void *arg)
void
diskfs_start_disk_pager (struct user_pager_info *upi,
- struct port_bucket *pager_bucket, int may_cache,
+ struct port_bucket *pager_bucket,
+ int may_cache, int notify_on_evict,
size_t size, void **image)
{
pthread_t thread;
@@ -68,7 +69,8 @@ diskfs_start_disk_pager (struct user_pager_info *upi,
/* Create the pager. */
diskfs_disk_pager = pager_create (upi, pager_bucket,
- may_cache, MEMORY_OBJECT_COPY_NONE);
+ may_cache, MEMORY_OBJECT_COPY_NONE,
+ notify_on_evict);
assert (diskfs_disk_pager);
/* Get a port to the disk pager. */
diff --git a/libdiskfs/diskfs-pager.h b/libdiskfs/diskfs-pager.h
index bd0a050..a253069 100644
--- a/libdiskfs/diskfs-pager.h
+++ b/libdiskfs/diskfs-pager.h
@@ -35,7 +35,8 @@ extern __thread struct disk_image_user *diskfs_exception_diu;
mapped is returned in IMAGE. INFO, PAGER_BUCKET, & MAY_CACHE are passed
to `pager_create'. */
extern void diskfs_start_disk_pager (struct user_pager_info *info,
- struct port_bucket *pager_bucket, int
may_cache,
+ struct port_bucket *pager_bucket,
+ int may_cache, int notify_on_evict,
size_t size, void **image);
extern struct pager *diskfs_disk_pager;
diff --git a/libdiskfs/diskfs.h b/libdiskfs/diskfs.h
index 0f9c1d3..22262aa 100644
--- a/libdiskfs/diskfs.h
+++ b/libdiskfs/diskfs.h
@@ -1,7 +1,7 @@
/* Definitions for fileserver helper functions
Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2001, 2002, 2007, 2008,
- 2009 Free Software Foundation, Inc.
+ 2009, 2013 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
@@ -69,6 +69,9 @@ struct peropen
mach_port_t shadow_root_parent;
/* If in a shadow tree, its root node in this translator. */
struct node *shadow_root;
+
+ /* Path relative to the root of the translator. */
+ char *path;
};
/* A unique one of these exists for each node currently in use (and
@@ -564,6 +567,12 @@ error_t (*diskfs_create_symlink_hook)(struct node *np,
const char *target);
isn't set, then the normal method (reading from the file data) is
used. If it returns any other error, it is returned to the user. */
error_t (*diskfs_read_symlink_hook)(struct node *np, char *target);
+
+/* The user may define this function. The function must set source to
+ the source device of the filesystem. The function may return an
+ EOPNOTSUPP to indicate that the concept of a source device is not
+ applicable. The default function always returns EOPNOTSUPP. */
+error_t diskfs_get_source (char *source);
/* The library exports the following functions for general use */
diff --git a/libdiskfs/file-set-trans.c b/libdiskfs/file-set-trans.c
index 49303e7..8de2e64 100644
--- a/libdiskfs/file-set-trans.c
+++ b/libdiskfs/file-set-trans.c
@@ -1,5 +1,6 @@
/* libdiskfs implementation of fs.defs: file_set_translator
- Copyright (C) 1992,93,94,95,96,99,2001,02 Free Software Foundation, Inc.
+ Copyright (C) 1992,93,94,95,96,99,2001,02,13
+ 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
@@ -206,5 +207,21 @@ diskfs_S_file_set_translator (struct protid *cred,
}
pthread_mutex_unlock (&np->lock);
+
+ if (! error && cred->po->path)
+ error = fshelp_set_active_translator (cred->po->path, active);
+
+ if (! error && active != MACH_PORT_NULL)
+ {
+ mach_port_t old;
+ error = mach_port_request_notification (mach_task_self (), active,
+ MACH_NOTIFY_DEAD_NAME, 0,
+ cred->pi.port_right,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &old);
+ if (old != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), old);
+ }
+
return error;
}
diff --git a/libdiskfs/fsys-get-children.c b/libdiskfs/fsys-get-children.c
new file mode 100644
index 0000000..69c9963
--- /dev/null
+++ b/libdiskfs/fsys-get-children.c
@@ -0,0 +1,99 @@
+/* fsys_get_children
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ Written by Justus Winter <address@hidden>
+
+ 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "priv.h"
+#include "fsys_S.h"
+
+#include <argz.h>
+
+/* Return any active translators bound to nodes of the receiving
+ filesystem. CHILDREN is an argz vector containing file names
+ relative to the root of the receiving translator. */
+error_t
+diskfs_S_fsys_get_children (fsys_t server,
+ mach_port_t reply,
+ mach_msg_type_name_t replyPoly,
+ char **children,
+ mach_msg_type_number_t *children_len)
+{
+ error_t err;
+
+ struct protid *cred = ports_lookup_port (diskfs_port_bucket,
+ server,
+ diskfs_protid_class);
+ if (! cred)
+ return EOPNOTSUPP;
+
+ /* check_access performs the same permission check as is normally
+ done, i.e. it checks that all but the last path components are
+ executable by the requesting user and that the last component is
+ readable. */
+ error_t check_access (const char *path)
+ {
+ error_t err;
+ char *elements = NULL;
+ size_t elements_len = 0;
+
+ err = argz_create_sep (path, '/', &elements, &elements_len);
+ if (err)
+ return err;
+
+ struct node *dp = diskfs_root_node;
+
+ for (char *entry = elements;
+ entry;
+ entry = argz_next (elements, elements_len, entry))
+ {
+ struct node *next;
+ err = diskfs_lookup (dp, entry, LOOKUP, &next, NULL, cred);
+
+ if (dp != diskfs_root_node)
+ diskfs_nput (dp);
+
+ if (err)
+ return err;
+
+ dp = next;
+ }
+
+ err = fshelp_access (&dp->dn_stat, S_IRUSR, cred->user);
+ diskfs_nput (dp);
+ return err;
+ }
+
+
+ char *c = NULL;
+ size_t c_len = 0;
+
+ err = fshelp_get_active_translators (&c, &c_len, check_access);
+ if (err)
+ goto errout;
+
+ err = iohelp_return_malloced_buffer (c, c_len, children, children_len);
+ if (err)
+ goto errout;
+
+ c = NULL; /* c was freed by iohelp_return_malloced_buffer. */
+
+ errout:
+ free (c);
+ return err;
+}
diff --git a/libdiskfs/fsys-get-source.c b/libdiskfs/fsys-get-source.c
new file mode 100644
index 0000000..08f227c
--- /dev/null
+++ b/libdiskfs/fsys-get-source.c
@@ -0,0 +1,34 @@
+/* fsys_get_source
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ Written by Justus Winter <address@hidden>
+
+ 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "priv.h"
+#include "fsys_S.h"
+
+/* Return information about the source of the receiving
+ filesystem. */
+error_t
+diskfs_S_fsys_get_source (fsys_t server,
+ mach_port_t reply,
+ mach_msg_type_name_t replyPoly,
+ char *source)
+{
+ return diskfs_get_source (source);
+}
diff --git a/libdiskfs/fsys-getroot.c b/libdiskfs/fsys-getroot.c
index 2e11da4..39973a8 100644
--- a/libdiskfs/fsys-getroot.c
+++ b/libdiskfs/fsys-getroot.c
@@ -51,7 +51,8 @@ diskfs_S_fsys_getroot (fsys_t controlport,
{
root_parent: dotdot,
shadow_root_parent: MACH_PORT_NULL,
- shadow_root: _diskfs_chroot_directory ? diskfs_root_node : NULL /* XXX */
+ shadow_root: _diskfs_chroot_directory ? diskfs_root_node : NULL, /* XXX */
+ path: NULL,
};
if (!pt)
diff --git a/libdiskfs/get-source.c b/libdiskfs/get-source.c
new file mode 100644
index 0000000..d0c143b
--- /dev/null
+++ b/libdiskfs/get-source.c
@@ -0,0 +1,28 @@
+/* Default version of diskfs_get_source
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ Written by Justus Winter <address@hidden>
+
+ 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "priv.h"
+
+error_t
+diskfs_get_source (char *source)
+{
+ return EOPNOTSUPP;
+}
diff --git a/libdiskfs/init-startup.c b/libdiskfs/init-startup.c
index 2c0814f..bf955d2 100644
--- a/libdiskfs/init-startup.c
+++ b/libdiskfs/init-startup.c
@@ -26,6 +26,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA
02139, USA. */
#include <error.h>
#include <hurd/fsys.h>
#include <hurd/startup.h>
+#include <pids.h>
char *_diskfs_chroot_directory;
@@ -190,7 +191,14 @@ _diskfs_init_completed ()
if (err)
goto errout;
- err = proc_getmsgport (proc, 1, &init);
+ /* Mark us as important. */
+ err = proc_mark_important (proc);
+ /* This might fail due to permissions or because the old proc server
+ is still running, ignore any such errors. */
+ if (err && err != EPERM && err != EMIG_BAD_ID)
+ goto errout;
+
+ err = proc_getmsgport (proc, HURD_PID_STARTUP, &init);
mach_port_deallocate (mach_task_self (), proc);
if (err)
goto errout;
diff --git a/libdiskfs/peropen-make.c b/libdiskfs/peropen-make.c
index d37516c..b11b2ad 100644
--- a/libdiskfs/peropen-make.c
+++ b/libdiskfs/peropen-make.c
@@ -34,6 +34,7 @@ diskfs_make_peropen (struct node *np, int flags, struct
peropen *context,
po->refcnt = 0;
po->openstat = flags;
po->np = np;
+ po->path = NULL;
if (context)
{
@@ -50,6 +51,13 @@ diskfs_make_peropen (struct node *np, int flags, struct
peropen *context,
if (po->shadow_root_parent != MACH_PORT_NULL)
mach_port_mod_refs (mach_task_self (), po->shadow_root_parent,
MACH_PORT_RIGHT_SEND, 1);
+
+ if (context->path)
+ {
+ po->path = strdup (context->path);
+ if (! po->path)
+ return ENOMEM;
+ }
}
else
{
diff --git a/libdiskfs/peropen-rele.c b/libdiskfs/peropen-rele.c
index 08276ec..d3f7492 100644
--- a/libdiskfs/peropen-rele.c
+++ b/libdiskfs/peropen-rele.c
@@ -45,5 +45,6 @@ diskfs_release_peropen (struct peropen *po)
diskfs_nput (po->np);
+ free (po->path);
free (po);
}
diff --git a/libfshelp/Makefile b/libfshelp/Makefile
index 4de3837..6ba6a14 100644
--- a/libfshelp/Makefile
+++ b/libfshelp/Makefile
@@ -20,6 +20,7 @@ makemode := library
libname = libfshelp
SRCS = lock-acquire.c lock-init.c \
+ translator-list.c \
start-translator-long.c start-translator.c \
fetch-root.c transbox-init.c set-active.c fetch-control.c \
drop-transbox.c translated.c \
@@ -32,7 +33,7 @@ SRCS = lock-acquire.c lock-init.c \
touch.c
installhdrs = fshelp.h
-HURDLIBS = shouldbeinlibc iohelp ports
+HURDLIBS = shouldbeinlibc iohelp ports ihash
LDLIBS += -lpthread
OBJS = $(subst .c,.o,$(SRCS))
diff --git a/libfshelp/fshelp.h b/libfshelp/fshelp.h
index cf39fbc..43fbcd7 100644
--- a/libfshelp/fshelp.h
+++ b/libfshelp/fshelp.h
@@ -1,5 +1,6 @@
/* FS helper library definitions
- Copyright (C) 1994,95,96,97,98,99,2000,01,02 Free Software Foundation, Inc.
+ Copyright (C) 1994,95,96,97,98,99,2000,01,02,13
+ 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
@@ -32,6 +33,36 @@
#include <maptime.h>
+/* Keeping track of active translators */
+/* These routines keep a list of active translators. They are
+ self-contained and do not require multi threading or the ports
+ library. */
+
+/* Record an active translator being bound to the given file name
+ NAME. ACTIVE is the control port of the translator. */
+error_t
+fshelp_set_active_translator (const char *name, mach_port_t active);
+
+/* Remove the active translator specified by its control port ACTIVE.
+ If there is no active translator with the given control port, this
+ does nothing. */
+error_t
+fshelp_remove_active_translator (mach_port_t active);
+
+/* This kind of function is used by fshelp_get_active_translators to
+ filter the list of translators to return. If a filter returns an
+ error for a given PATH, the translator bound to the PATH is not
+ included in the list. */
+typedef error_t (*fshelp_filter) (const char *path);
+
+/* Records the list of active translators into the argz vector
+ specified by TRANSLATORS filtered by FILTER. */
+error_t
+fshelp_get_active_translators (char **translators,
+ size_t *translators_len,
+ fshelp_filter filter);
+
+
/* Passive translator linkage */
/* These routines are self-contained and start passive translators,
returning the control port. They do not require multi threading
diff --git a/libfshelp/translator-list.c b/libfshelp/translator-list.c
new file mode 100644
index 0000000..a24d976
--- /dev/null
+++ b/libfshelp/translator-list.c
@@ -0,0 +1,169 @@
+/* A list of active translators.
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ Written by Justus Winter <address@hidden>
+
+ 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <argz.h>
+#include <hurd/fsys.h>
+#include <hurd/ihash.h>
+#include <mach.h>
+#include <mach/notify.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "fshelp.h"
+
+struct translator
+{
+ char *name;
+ mach_port_t active;
+};
+
+/* The list of active translators. */
+static struct hurd_ihash translator_ihash
+ = HURD_IHASH_INITIALIZER (HURD_IHASH_NO_LOCP);
+
+/* The lock protecting the translator_ihash. */
+static pthread_mutex_t translator_ihash_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static void
+translator_ihash_cleanup (void *element, void *arg)
+{
+ /* No need to deallocate port, we only keep the name of the
+ port, not a reference. */
+ free (element);
+}
+
+/* Record an active translator being bound to the given file name
+ NAME. ACTIVE is the control port of the translator. */
+error_t
+fshelp_set_active_translator (const char *name, mach_port_t active)
+{
+ error_t err = 0;
+ pthread_mutex_lock (&translator_ihash_lock);
+
+ if (! translator_ihash.cleanup)
+ hurd_ihash_set_cleanup (&translator_ihash, translator_ihash_cleanup, NULL);
+
+ struct translator *t = NULL;
+ HURD_IHASH_ITERATE (&translator_ihash, value)
+ {
+ t = value;
+ if (strcmp (name, t->name) == 0)
+ goto update; /* Entry exists. */
+ }
+
+ t = malloc (sizeof (struct translator));
+ if (! t)
+ return ENOMEM;
+
+ t->active = MACH_PORT_NULL;
+ t->name = strdup (name);
+ if (! t->name)
+ {
+ err = errno;
+ free (t);
+ goto out;
+ }
+
+ err = hurd_ihash_add (&translator_ihash, (hurd_ihash_key_t) t, t);
+ if (err)
+ goto out;
+
+ update:
+ if (active)
+ /* No need to increment the reference count, we only keep the
+ name, not a reference. */
+ t->active = active;
+ else
+ hurd_ihash_remove (&translator_ihash, (hurd_ihash_key_t) t);
+
+ out:
+ pthread_mutex_unlock (&translator_ihash_lock);
+ return err;
+}
+
+/* Remove the active translator specified by its control port ACTIVE.
+ If there is no active translator with the given control port, this
+ does nothing. */
+error_t
+fshelp_remove_active_translator (mach_port_t active)
+{
+ error_t err = 0;
+ pthread_mutex_lock (&translator_ihash_lock);
+
+ struct translator *t = NULL;
+ HURD_IHASH_ITERATE (&translator_ihash, value)
+ {
+ struct translator *v = value;
+ if (active == v->active)
+ {
+ t = v;
+ break;
+ }
+ }
+
+ if (t)
+ hurd_ihash_remove (&translator_ihash, (hurd_ihash_key_t) t);
+
+ pthread_mutex_unlock (&translator_ihash_lock);
+ return err;
+}
+
+/* Records the list of active translators into the argz vector
+ specified by TRANSLATORS filtered by FILTER. */
+error_t
+fshelp_get_active_translators (char **translators,
+ size_t *translators_len,
+ fshelp_filter filter)
+{
+ error_t err = 0;
+ pthread_mutex_lock (&translator_ihash_lock);
+
+ HURD_IHASH_ITERATE (&translator_ihash, value)
+ {
+ struct translator *t = value;
+ if (filter)
+ {
+ char *dir = strdup (t->name);
+ if (! dir)
+ {
+ err = ENOMEM;
+ break;
+ }
+
+ err = filter (dirname (dir));
+ free (dir);
+ if (err)
+ {
+ err = 0;
+ continue; /* Skip this entry. */
+ }
+ }
+
+ err = argz_add (translators, translators_len,
+ t->name);
+ if (err)
+ break;
+ }
+
+ pthread_mutex_unlock (&translator_ihash_lock);
+ return err;
+}
diff --git a/libihash/ihash.h b/libihash/ihash.h
index a4e76dc..3ca5ec3 100644
--- a/libihash/ihash.h
+++ b/libihash/ihash.h
@@ -218,6 +218,23 @@ hurd_ihash_value_t hurd_ihash_find (hurd_ihash_t ht,
hurd_ihash_key_t key);
(((_hurd_ihash_item_t) _hurd_ihash_valuep) + 1)) \
if (val != _HURD_IHASH_EMPTY && val != _HURD_IHASH_DELETED)
+/* Iterate over all elements in the hash table making both the key and
+ the value available. You use this macro with a block, for example
+ like this:
+
+ HURD_IHASH_ITERATE_ITEMS (ht, item)
+ foo (item->key, item->value);
+
+ The block will be run for every element in the hash table HT. The
+ key and value of the current element is available as ITEM->key and
+ ITEM->value. */
+#define HURD_IHASH_ITERATE_ITEMS(ht, item) \
+ for (_hurd_ihash_item_t item = (ht)->size? &(ht)->items[0]: 0; \
+ (ht)->size && item - &(ht)->items[0] < (ht)->size; \
+ item++) \
+ if (item->value != _HURD_IHASH_EMPTY && \
+ item->value != _HURD_IHASH_DELETED)
+
/* Remove the entry with the key KEY from the hash table HT. If such
an entry was found and removed, 1 is returned, otherwise 0. */
int hurd_ihash_remove (hurd_ihash_t ht, hurd_ihash_key_t key);
diff --git a/libnetfs/Makefile b/libnetfs/Makefile
index 24b5aca..1a71b49 100644
--- a/libnetfs/Makefile
+++ b/libnetfs/Makefile
@@ -34,7 +34,8 @@ FSSRCS= dir-link.c dir-lookup.c dir-mkdir.c dir-mkfile.c \
file-get-translator.c file-getcontrol.c file-getlinknode.c \
file-lock-stat.c file-lock.c file-set-size.c \
file-set-translator.c file-statfs.c file-sync.c file-syncfs.c \
- file-utimes.c file-reparent.c fsstubs.c
+ file-utimes.c file-reparent.c fsstubs.c file-get-transcntl.c \
+ get-source.c
IOSRCS= io-read.c io-readable.c io-seek.c io-write.c io-stat.c
io-async.c \
io-set-all-openmodes.c io-get-openmodes.c io-set-some-openmodes.c \
@@ -44,7 +45,7 @@ IOSRCS= io-read.c io-readable.c io-seek.c io-write.c
io-stat.c io-async.c \
io-version.c
FSYSSRCS= fsys-syncfs.c fsys-getroot.c fsys-get-options.c fsys-set-options.c \
- fsys-goaway.c fsysstubs.c
+ fsys-goaway.c fsysstubs.c fsys-get-children.c fsys-get-source.c
IFSOCKSRCS=
OTHERSRCS= drop-node.c init-init.c make-node.c make-peropen.c make-protid.c \
@@ -52,7 +53,7 @@ OTHERSRCS= drop-node.c init-init.c make-node.c make-peropen.c
make-protid.c \
init-startup.c startup-argp.c set-options.c append-args.c \
runtime-argp.c std-runtime-argp.c std-startup-argp.c \
append-std-options.c trans-callback.c set-get-trans.c \
- nref.c nrele.c nput.c file-get-storage-info-default.c
+ nref.c nrele.c nput.c file-get-storage-info-default.c dead-name.c
SRCS= $(OTHERSRCS) $(FSSRCS) $(IOSRCS) $(FSYSSRCS) $(IFSOCKSRCS)
diff --git a/libdiskfs/dead-name.c b/libnetfs/dead-name.c
similarity index 88%
copy from libdiskfs/dead-name.c
copy to libnetfs/dead-name.c
index 760b36f..6f2d78d 100644
--- a/libdiskfs/dead-name.c
+++ b/libnetfs/dead-name.c
@@ -23,10 +23,10 @@
void
ports_dead_name (void *notify, mach_port_t dead_name)
{
- struct protid *pi = ports_lookup_port (diskfs_port_bucket, dead_name,
- diskfs_protid_class);
+ struct protid *pi = ports_lookup_port (netfs_port_bucket, dead_name,
+ netfs_protid_class);
struct node *np;
-
+
if (pi)
{
np = pi->po->np;
@@ -35,11 +35,13 @@ ports_dead_name (void *notify, mach_port_t dead_name)
{
mach_port_deallocate (mach_task_self (), np->sockaddr);
np->sockaddr = MACH_PORT_NULL;
- diskfs_nput (np);
+ netfs_nput (np);
}
else
pthread_mutex_unlock (&np->lock);
}
-
+
+ fshelp_remove_active_translator (dead_name);
+
ports_interrupt_notified_rpcs (notify, dead_name, MACH_NOTIFY_DEAD_NAME);
}
diff --git a/libnetfs/dir-lookup.c b/libnetfs/dir-lookup.c
index f1b6438..10ea2d0 100644
--- a/libnetfs/dir-lookup.c
+++ b/libnetfs/dir-lookup.c
@@ -1,5 +1,6 @@
/*
- Copyright (C) 1995,96,97,98,99,2000,01,02 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,97,98,99,2000,01,02,13
+ Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -46,6 +47,7 @@ netfs_S_dir_lookup (struct protid *diruser,
int nsymlinks = 0;
struct node *dnp, *np;
char *nextname;
+ char *relpath;
error_t error;
struct protid *newpi;
struct iouser *user;
@@ -60,6 +62,11 @@ netfs_S_dir_lookup (struct protid *diruser,
while (*filename == '/')
filename++;
+ /* Preserve the path relative to diruser->po->path. */
+ relpath = strdup (filename);
+ if (! relpath)
+ return ENOMEM;
+
*retry_port_type = MACH_MSG_TYPE_MAKE_SEND;
*do_retry = FS_RETRY_NORMAL;
*retry_name = '\0';
@@ -390,6 +397,22 @@ netfs_S_dir_lookup (struct protid *diruser,
goto out;
}
+ free (newpi->po->path);
+ if (diruser->po->path == NULL)
+ {
+ /* diruser is the root directory. */
+ newpi->po->path = relpath;
+ relpath = NULL; /* Do not free relpath. */
+ }
+ else
+ {
+ newpi->po->path = NULL;
+ asprintf (&newpi->po->path, "%s/%s", diruser->po->path, relpath);
+ }
+
+ if (! newpi->po->path)
+ error = errno;
+
*retry_port = ports_get_right (newpi);
ports_port_deref (newpi);
@@ -398,5 +421,6 @@ netfs_S_dir_lookup (struct protid *diruser,
netfs_nput (np);
if (dnp)
netfs_nrele (dnp);
+ free (relpath);
return error;
}
diff --git a/libnetfs/file-get-transcntl.c b/libnetfs/file-get-transcntl.c
new file mode 100644
index 0000000..04596d7
--- /dev/null
+++ b/libnetfs/file-get-transcntl.c
@@ -0,0 +1,52 @@
+/* libnetfs implementation of fs.defs: file_get_translator_cntl
+
+ Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation
+
+ This is a trivially adapted version of
+ libdiskfs/file-get-transcntl.c.
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "priv.h"
+#include "fs_S.h"
+
+/* Implement file_get_translator_cntl as described in <hurd/fs.defs>. */
+error_t
+netfs_S_file_get_translator_cntl (struct protid *cred,
+ mach_port_t *ctl,
+ mach_msg_type_name_t *ctltype)
+{
+ struct node *np;
+ error_t err;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ np = cred->po->np;
+
+ pthread_mutex_lock (&np->lock);
+
+ err = fshelp_isowner (&np->nn_stat, cred->user);
+ if (!err)
+ err = fshelp_fetch_control (&np->transbox, ctl);
+ if (!err && *ctl == MACH_PORT_NULL)
+ err = ENXIO;
+ if (!err)
+ *ctltype = MACH_MSG_TYPE_MOVE_SEND;
+
+ pthread_mutex_unlock (&np->lock);
+
+ return err;
+}
diff --git a/libnetfs/file-get-translator.c b/libnetfs/file-get-translator.c
index 59e6102..3a54ff1 100644
--- a/libnetfs/file-get-translator.c
+++ b/libnetfs/file-get-translator.c
@@ -109,6 +109,20 @@ netfs_S_file_get_translator (struct protid *user,
*translen = len;
err = 0;
}
+ else if (np->nn_translated & S_IPTRANS)
+ {
+ char *string = NULL;
+ size_t len = 0;
+ err = netfs_get_translator (np, &string, &len);
+ if (!err)
+ {
+ if (len > *translen)
+ *trans = mmap (0, len, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ memcpy (*trans, string, len);
+ *translen = len;
+ free (string);
+ }
+ }
else
err = EINVAL;
diff --git a/libnetfs/file-set-translator.c b/libnetfs/file-set-translator.c
index b107ccd..a9883a3 100644
--- a/libnetfs/file-set-translator.c
+++ b/libnetfs/file-set-translator.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1996, 1997, 1999, 2001 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1999, 2001, 2013 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -175,6 +175,21 @@ netfs_S_file_set_translator (struct protid *user,
}
}
+ if (! err && user->po->path)
+ err = fshelp_set_active_translator (user->po->path, active);
+
+ if (! err && active != MACH_PORT_NULL)
+ {
+ mach_port_t old;
+ err = mach_port_request_notification (mach_task_self (), active,
+ MACH_NOTIFY_DEAD_NAME, 0,
+ user->pi.port_right,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &old);
+ if (old != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), old);
+ }
+
out:
pthread_mutex_unlock (&np->lock);
return err;
diff --git a/libnetfs/fsstubs.c b/libnetfs/fsstubs.c
index 708cbb8..f1b9bf7 100644
--- a/libnetfs/fsstubs.c
+++ b/libnetfs/fsstubs.c
@@ -30,14 +30,6 @@ netfs_S_file_notice_changes (struct protid *user,
}
error_t
-netfs_S_file_get_translator_cntl (struct protid *user,
- mach_port_t *trans,
- mach_msg_type_name_t *transtype)
-{
- return EOPNOTSUPP;
-}
-
-error_t
netfs_S_file_getfh (struct protid *user,
char **data, mach_msg_type_number_t *ndata)
{
diff --git a/libnetfs/fsys-get-children.c b/libnetfs/fsys-get-children.c
new file mode 100644
index 0000000..fb3af91
--- /dev/null
+++ b/libnetfs/fsys-get-children.c
@@ -0,0 +1,112 @@
+/* fsys_get_children
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ Written by Justus Winter <address@hidden>
+
+ 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "priv.h"
+
+#include <argz.h>
+
+/* Return any active translators bound to nodes of the receiving
+ filesystem. CHILDREN is an argz vector containing file names
+ relative to the root of the receiving translator. */
+error_t
+netfs_S_fsys_get_children (fsys_t server,
+ mach_port_t reply,
+ mach_msg_type_name_t replyPoly,
+ char **children,
+ mach_msg_type_number_t *children_len)
+{
+ error_t err;
+
+ struct protid *cred = ports_lookup_port (netfs_port_bucket,
+ server,
+ netfs_protid_class);
+ if (! cred)
+ return EOPNOTSUPP;
+
+ /* check_access performs the same permission check as is normally
+ done, i.e. it checks that all but the last path components are
+ executable by the requesting user and that the last component is
+ readable. */
+ error_t check_access (const char *path)
+ {
+ error_t err;
+ char *elements = NULL;
+ size_t elements_len = 0;
+
+ err = argz_create_sep (path, '/', &elements, &elements_len);
+ if (err)
+ return err;
+
+ struct node *dp = netfs_root_node;
+
+ /* Lock the root node. netfs_attempt_lookup expects the directory to
+ be locked. */
+ pthread_mutex_lock (&dp->lock);
+
+ /* Increase the reference count, it will be decremented in the loop
+ ahead. */
+ netfs_nref (dp);
+
+ for (char *entry = elements;
+ entry;
+ entry = argz_next (elements, elements_len, entry))
+ {
+ struct node *next;
+ err = netfs_attempt_lookup (cred->user, dp, entry, &next);
+ /* netfs_attempt_lookup has unlocked dp and returned next
+ locked, so there is no locking to do here. */
+
+ /* Decrease reference count. */
+ netfs_nrele (dp);
+
+ if (err)
+ goto errout;
+
+ dp = next;
+ }
+
+ err = fshelp_access (&dp->nn_stat, S_IRUSR, cred->user);
+
+ errout:
+ /* Unlock and unreference the last node. */
+ netfs_nput (dp);
+
+ free (elements);
+ return err;
+ }
+
+ char *c = NULL;
+ size_t c_len = 0;
+
+ err = fshelp_get_active_translators (&c, &c_len, check_access);
+ if (err)
+ goto errout;
+
+ err = iohelp_return_malloced_buffer (c, c_len, children, children_len);
+ if (err)
+ goto errout;
+
+ c = NULL; /* c was freed by iohelp_return_malloced_buffer. */
+
+ errout:
+ free (c);
+ return err;
+}
diff --git a/libnetfs/fsys-get-source.c b/libnetfs/fsys-get-source.c
new file mode 100644
index 0000000..6143d10
--- /dev/null
+++ b/libnetfs/fsys-get-source.c
@@ -0,0 +1,34 @@
+/* fsys_get_source
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ Written by Justus Winter <address@hidden>
+
+ 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "priv.h"
+#include "fsys_S.h"
+
+/* Return information about the source of the receiving
+ filesystem. */
+error_t
+netfs_S_fsys_get_source (fsys_t server,
+ mach_port_t reply,
+ mach_msg_type_name_t replyPoly,
+ char *source)
+{
+ return netfs_get_source (source);
+}
diff --git a/libnetfs/fsys-getroot.c b/libnetfs/fsys-getroot.c
index a1dd5e5..0d80111 100644
--- a/libnetfs/fsys-getroot.c
+++ b/libnetfs/fsys-getroot.c
@@ -43,7 +43,11 @@ netfs_S_fsys_getroot (mach_port_t cntl,
error_t err;
struct protid *newpi;
mode_t type;
- struct peropen peropen_context = { root_parent: dotdot };
+ struct peropen peropen_context =
+ {
+ root_parent: dotdot,
+ path: NULL,
+ };
if (!pt)
return EOPNOTSUPP;
diff --git a/libnetfs/get-source.c b/libnetfs/get-source.c
new file mode 100644
index 0000000..71a9639
--- /dev/null
+++ b/libnetfs/get-source.c
@@ -0,0 +1,28 @@
+/* Default version of netfs_get_source
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ Written by Justus Winter <address@hidden>
+
+ 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "priv.h"
+
+error_t
+netfs_get_source (char *source)
+{
+ return EOPNOTSUPP;
+}
diff --git a/libnetfs/init-startup.c b/libnetfs/init-startup.c
index 2e0f43a..e17c4f1 100644
--- a/libnetfs/init-startup.c
+++ b/libnetfs/init-startup.c
@@ -48,5 +48,19 @@ netfs_startup (mach_port_t bootstrap, int flags)
mach_port_deallocate (mach_task_self (), bootstrap);
+ /* Mark us as important. */
+ mach_port_t proc = getproc ();
+ if (proc == MACH_PORT_NULL)
+ error (12, err, "Translator startup failure: getproc");
+
+ err = proc_mark_important (proc);
+
+ /* This might fail due to permissions or because the old proc server
+ is still running, ignore any such errors. */
+ if (err && err != EPERM && err != EMIG_BAD_ID)
+ error (13, err, "Translator startup failure: proc_mark_important");
+
+ mach_port_deallocate (mach_task_self (), proc);
+
return realnode;
}
diff --git a/libnetfs/make-peropen.c b/libnetfs/make-peropen.c
index 92f58da..733bfdc 100644
--- a/libnetfs/make-peropen.c
+++ b/libnetfs/make-peropen.c
@@ -31,6 +31,7 @@ netfs_make_peropen (struct node *np, int flags, struct
peropen *context)
po->refcnt = 0;
po->openstat = flags;
po->np = np;
+ po->path = NULL;
if (context)
{
@@ -47,6 +48,13 @@ netfs_make_peropen (struct node *np, int flags, struct
peropen *context)
if (po->shadow_root_parent != MACH_PORT_NULL)
mach_port_mod_refs (mach_task_self (), po->shadow_root_parent,
MACH_PORT_RIGHT_SEND, 1);
+
+ if (context->path)
+ {
+ po->path = strdup (context->path);
+ if (! po->path)
+ return ENOMEM;
+ }
}
netfs_nref (np);
diff --git a/libnetfs/netfs.h b/libnetfs/netfs.h
index d1ebed0..e10ccae 100644
--- a/libnetfs/netfs.h
+++ b/libnetfs/netfs.h
@@ -1,6 +1,6 @@
/*
- Copyright (C) 1994,95,96,97,99,2000,02 Free Software Foundation, Inc.
+ Copyright (C) 1994,95,96,97,99,2000,02,13 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
@@ -63,6 +63,8 @@ struct peropen
mach_port_t shadow_root_parent;
/* If in a shadow tree, its root node in this translator. */
struct node *shadow_root;
+
+ char *path;
};
/* A unique one of these exists for each node currently in use. */
@@ -311,6 +313,12 @@ error_t netfs_file_get_storage_info (struct iouser *cred,
mach_msg_type_number_t *num_offsets,
char **data,
mach_msg_type_number_t *data_len);
+
+/* The user may define this function. The function must set source to
+ the source device of the filesystem. The function may return an
+ EOPNOTSUPP to indicate that the concept of a source device is not
+ applicable. The default function always returns EOPNOTSUPP. */
+error_t netfs_get_source (char *source);
/* Option parsing */
diff --git a/libnetfs/release-peropen.c b/libnetfs/release-peropen.c
index 3e65099..d4d3574 100644
--- a/libnetfs/release-peropen.c
+++ b/libnetfs/release-peropen.c
@@ -41,6 +41,7 @@ netfs_release_peropen (struct peropen *po)
netfs_nput (po->np);
+ free (po->path);
free (po);
}
}
diff --git a/libpager/data-request.c b/libpager/data-request.c
index 4454fac..34b8b43 100644
--- a/libpager/data-request.c
+++ b/libpager/data-request.c
@@ -119,7 +119,8 @@ _pager_seqnos_memory_object_data_request (mach_port_t
object,
goto error_read;
memory_object_data_supply (p->memobjcntl, offset, page, length, 1,
- write_lock ? VM_PROT_WRITE : VM_PROT_NONE, 0,
+ write_lock ? VM_PROT_WRITE : VM_PROT_NONE,
+ p->notify_on_evict ? 1 : 0,
MACH_PORT_NULL);
pthread_mutex_lock (&p->interlock);
_pager_mark_object_error (p, offset, length, 0);
diff --git a/libpager/data-return.c b/libpager/data-return.c
index c70f0e8..6a3b903 100644
--- a/libpager/data-return.c
+++ b/libpager/data-return.c
@@ -39,6 +39,7 @@ _pager_do_write_request (mach_port_t object,
struct pager *p;
short *pm_entries;
int npages, i;
+ char *notified;
error_t *pagerrs;
struct lock_request *lr;
struct lock_list {struct lock_request *lr;
@@ -71,9 +72,6 @@ _pager_do_write_request (mach_port_t object,
goto release_out;
}
- if (! dirty)
- goto release_out;
-
if (p->pager_state != NORMAL)
{
printf ("pager in wrong state for write\n");
@@ -83,6 +81,11 @@ _pager_do_write_request (mach_port_t object,
npages = length / __vm_page_size;
pagerrs = alloca (npages * sizeof (error_t));
+ notified = alloca (npages * (sizeof *notified));
+#ifndef NDEBUG
+ memset (notified, -1, npages * (sizeof *notified));
+#endif
+
_pager_block_termination (p); /* until we are done with the pagemap
when the write completes. */
@@ -90,6 +93,24 @@ _pager_do_write_request (mach_port_t object,
pm_entries = &p->pagemap[offset / __vm_page_size];
+ if (! dirty)
+ {
+ munmap ((void *) data, length);
+ if (!kcopy) {
+ /* Prepare notified array. */
+ for (i = 0; i < npages; i++)
+ notified[i] = (p->notify_on_evict
+ && ! (pm_entries[i] & PM_PAGEINWAIT));
+
+ _pager_release_seqno (p, seqno);
+ goto notify;
+ }
+ else {
+ _pager_allow_termination (p);
+ goto release_out;
+ }
+ }
+
/* Make sure there are no other in-progress writes for any of these
pages before we begin. This imposes a little more serialization
than we really have to require (because *all* future writes on
@@ -120,10 +141,6 @@ _pager_do_write_request (mach_port_t object,
for (i = 0; i < npages; i++)
pm_entries[i] |= PM_PAGINGOUT | PM_INIT;
- if (!kcopy)
- for (i = 0; i < npages; i++)
- pm_entries[i] &= ~PM_INCORE;
-
/* If this write occurs while a lock is pending, record
it. We have to keep this list because a lock request
might come in while we do the I/O; in that case there
@@ -163,7 +180,10 @@ _pager_do_write_request (mach_port_t object,
for (i = 0; i < npages; i++)
{
if (omitdata & (1 << i))
- continue;
+ {
+ notified[i] = 0;
+ continue;
+ }
if (pm_entries[i] & PM_WRITEWAIT)
wakeup = 1;
@@ -179,14 +199,22 @@ _pager_do_write_request (mach_port_t object,
pm_entries[i] |= PM_INVALID;
if (pm_entries[i] & PM_PAGEINWAIT)
- memory_object_data_supply (p->memobjcntl,
- offset + (vm_page_size * i),
- data + (vm_page_size * i),
- vm_page_size, 1,
- VM_PROT_NONE, 0, MACH_PORT_NULL);
+ {
+ memory_object_data_supply (p->memobjcntl,
+ offset + (vm_page_size * i),
+ data + (vm_page_size * i),
+ vm_page_size, 1,
+ VM_PROT_NONE, 0, MACH_PORT_NULL);
+ notified[i] = 0;
+ }
else
- munmap ((caddr_t) (data + (vm_page_size * i)),
- vm_page_size);
+ {
+ munmap ((void *) (data + (vm_page_size * i)),
+ vm_page_size);
+ notified[i] = (! kcopy && p->notify_on_evict);
+ if (! kcopy)
+ pm_entries[i] &= ~PM_INCORE;
+ }
pm_entries[i] &= ~(PM_PAGINGOUT | PM_PAGEINWAIT | PM_WRITEWAIT);
}
@@ -198,10 +226,29 @@ _pager_do_write_request (mach_port_t object,
if (wakeup)
pthread_cond_broadcast (&p->wakeup);
+ notify:
_pager_allow_termination (p);
-
pthread_mutex_unlock (&p->interlock);
+ for (i = 0; i < npages; i++)
+ {
+ assert (notified[i] == 0 || notified[i] == 1);
+ if (notified[i])
+ {
+ short *pm_entry = &pm_entries[i];
+
+ /* Do notify user. */
+ pager_notify_evict (p->upi, offset + (i * vm_page_size));
+
+ /* Clear any error that is left. Notification on eviction
+ is used only to change association of page, so any
+ error may no longer be valid. */
+ pthread_mutex_lock (&p->interlock);
+ *pm_entry = SET_PM_ERROR (SET_PM_NEXTERROR (*pm_entry, 0), 0);
+ pthread_mutex_unlock (&p->interlock);
+ }
+ }
+
ports_port_deref (p);
return 0;
diff --git a/libpager/pager-create.c b/libpager/pager-create.c
index 318c9f1..1aea6e9 100644
--- a/libpager/pager-create.c
+++ b/libpager/pager-create.c
@@ -22,7 +22,8 @@ struct pager *
pager_create (struct user_pager_info *upi,
struct port_bucket *bucket,
boolean_t may_cache,
- memory_object_copy_strategy_t copy_strategy)
+ memory_object_copy_strategy_t copy_strategy,
+ boolean_t notify_on_evict)
{
struct pager *p;
@@ -38,6 +39,7 @@ pager_create (struct user_pager_info *upi,
p->attribute_requests = 0;
p->may_cache = may_cache;
p->copy_strategy = copy_strategy;
+ p->notify_on_evict = notify_on_evict;
p->memobjcntl = MACH_PORT_NULL;
p->memobjname = MACH_PORT_NULL;
p->seqno = -1;
diff --git a/libpager/pager.h b/libpager/pager.h
index 99fb384..75ff108 100644
--- a/libpager/pager.h
+++ b/libpager/pager.h
@@ -36,14 +36,17 @@ int pager_demuxer (mach_msg_header_t *inp,
to receive requests. U_PAGER will be provided to later calls to
pager_find_address. The pager will have one user reference
created. MAY_CACHE and COPY_STRATEGY are the original values of
- those attributes as for memory_object_ready. Users may create
- references to pagers by use of the relevant ports library
- functions. On errors, return null and set errno. */
+ those attributes as for memory_object_ready. If NOTIFY_ON_EVICT is
+ non-zero, pager_notify_evict user callback will be called when page
+ is evicted. Users may create references to pagers by use of the
+ relevant ports library functions. On errors, return null and set
+ errno. */
struct pager *
pager_create (struct user_pager_info *u_pager,
struct port_bucket *bucket,
boolean_t may_cache,
- memory_object_copy_strategy_t copy_strategy);
+ memory_object_copy_strategy_t copy_strategy,
+ boolean_t notify_on_evict);
/* Return the user_pager_info struct associated with a pager. */
struct user_pager_info *
@@ -172,6 +175,18 @@ error_t
pager_unlock_page (struct user_pager_info *pager,
vm_offset_t address);
+/* The user must define this function. It is used when you want be
+ able to change association of pages to backing store. To use it,
+ pass non-zero value in NOTIFY_ON_EVICT when pager is created with
+ pager_create. You can change association of page only when
+ pager_notify_evict has been called and you haven't touched page
+ content after that. Note there is a possibility that a page is
+ evicted, but user is not notified about that. The user should be
+ able to handle this case. */
+void
+pager_notify_evict (struct user_pager_info *pager,
+ vm_offset_t page);
+
/* The user must define this function. It should report back (in
*OFFSET and *SIZE the minimum valid address the pager will accept
and the size of the object. */
diff --git a/libpager/priv.h b/libpager/priv.h
index e6b2546..7aa0fb4 100644
--- a/libpager/priv.h
+++ b/libpager/priv.h
@@ -49,6 +49,7 @@ struct pager
boolean_t may_cache;
memory_object_copy_strategy_t copy_strategy;
+ boolean_t notify_on_evict;
/* Interface ports */
memory_object_control_t memobjcntl;
diff --git a/libshouldbeinlibc/Makefile b/libshouldbeinlibc/Makefile
index 31a940f..14a7939 100644
--- a/libshouldbeinlibc/Makefile
+++ b/libshouldbeinlibc/Makefile
@@ -27,9 +27,9 @@ SRCS = termsize.c timefmt.c exec-reauth.c maptime-funcs.c \
idvec-impgids.c idvec-verify.c idvec-rep.c \
ugids.c ugids-argp.c ugids-rep.c ugids-verify.c ugids-subtract.c \
ugids-auth.c ugids-xinl.c ugids-merge.c ugids-imply.c ugids-posix.c \
- ugids-verify-auth.c
+ ugids-verify-auth.c nullauth.c
installhdrs = idvec.h timefmt.h maptime.h \
- wire.h portinfo.h portxlate.h cacheq.h ugids.h
+ wire.h portinfo.h portxlate.h cacheq.h ugids.h nullauth.h
installhdrsubdir = .
OBJS = $(SRCS:.c=.o)
diff --git a/libshouldbeinlibc/nullauth.c b/libshouldbeinlibc/nullauth.c
new file mode 100644
index 0000000..4ba10a7
--- /dev/null
+++ b/libshouldbeinlibc/nullauth.c
@@ -0,0 +1,47 @@
+/* Drop all authentication credentials.
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ Written by Justus Winter <address@hidden>
+
+ This file is part of the GNU Hurd.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#include <error.h>
+#include <errno.h>
+#include <hurd.h>
+
+/* Obtain an empty authentication handle and use it for further
+ authentication purposes. This effectively drops all Unix
+ privileges. */
+error_t
+setnullauth (void)
+{
+ error_t err;
+
+ auth_t nullauth;
+ err = auth_makeauth (getauth (),
+ NULL, MACH_MSG_TYPE_COPY_SEND, 0,
+ NULL, 0,
+ NULL, 0,
+ NULL, 0,
+ NULL, 0,
+ &nullauth);
+ if (err)
+ return err;
+
+ err = setauth (nullauth);
+ return err;
+}
diff --git a/libshouldbeinlibc/nullauth.h b/libshouldbeinlibc/nullauth.h
new file mode 100644
index 0000000..efdb5f3
--- /dev/null
+++ b/libshouldbeinlibc/nullauth.h
@@ -0,0 +1,31 @@
+/* Drop all authentication credentials.
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ Written by Justus Winter <address@hidden>
+
+ This file is part of the GNU Hurd.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#ifndef __NULLAUTH_H__
+#define __NULLAUTH_H__
+
+/* Obtain an empty authentication handle and use it for further
+ authentication purposes. This effectively drops all Unix
+ privileges. */
+error_t
+setnullauth (void);
+
+#endif /* __NULLAUTH_H__ */
diff --git a/libstore/Makefile b/libstore/Makefile
index eafdd0a..607940b 100644
--- a/libstore/Makefile
+++ b/libstore/Makefile
@@ -60,10 +60,6 @@ OBJS = $(SRCS:.c=.o) $(GUNZIP_OBJS) $(BUNZIP2_OBJS)
include ../Makeconf
-# Look for zip stuff
-vpath %.c $(srcdir)/../exec
-CPPFLAGS += -I$(srcdir)/../exec
-
module-CPPFLAGS = -D'STORE_SONAME_SUFFIX=".so.$(hurd-version)"'
module-DEPS = $(..)config.make
diff --git a/libstore/crypt.h b/libstore/crypt.h
new file mode 100644
index 0000000..2a4c203
--- /dev/null
+++ b/libstore/crypt.h
@@ -0,0 +1,12 @@
+/* crypt.h (dummy version) -- do not perform encryption
+ * Hardly worth copyrighting :-)
+ */
+
+#ifdef CRYPT
+# undef CRYPT /* dummy version */
+#endif
+
+#define RAND_HEAD_LEN 12 /* length of encryption random header */
+
+#define zencode
+#define zdecode
diff --git a/libstore/do-bunzip2.c b/libstore/do-bunzip2.c
new file mode 100644
index 0000000..716a0cd
--- /dev/null
+++ b/libstore/do-bunzip2.c
@@ -0,0 +1,1745 @@
+/* bunzip2 engine, modified by address@hidden */
+
+/* Stolen from util.c. */
+#include <stdio.h>
+#include <sys/types.h>
+
+/* I/O interface */
+extern int (*unzip_read) (char *buf, size_t maxread);
+extern void (*unzip_write) (const char *buf, size_t nwrite);
+extern void (*unzip_read_error) (void);
+extern void (*unzip_error) (const char *msg);
+
+/* bzip2 doesn't require window sliding. Just for buffering. */
+#define INBUFSIZ 0x1000
+#define OUTBUFSIZ 0x1000
+
+static unsigned char inbuf[INBUFSIZ];
+static unsigned char outbuf[OUTBUFSIZ];
+static unsigned inptr;
+static unsigned insize;
+static unsigned outcnt;
+
+/* ===========================================================================
+ * Fill the input buffer. This is called only when the buffer is empty.
+ */
+static int
+fill_inbuf (int eof_ok)
+{
+ int len;
+
+ /* Read as much as possible */
+ insize = 0;
+ do
+ {
+ len = (*unzip_read)((char*)inbuf+insize, INBUFSIZ-insize);
+ if (len == 0 || len == EOF)
+ break;
+ insize += len;
+ }
+ while (insize < INBUFSIZ);
+
+ if (insize == 0)
+ {
+ if (eof_ok)
+ return EOF;
+ unzip_read_error();
+ }
+
+ inptr = 1;
+ return inbuf[0];
+}
+
+static void
+flush_outbuf (void)
+{
+ if (outcnt == 0)
+ return;
+
+ (*unzip_write) ((char *) outbuf, outcnt);
+ outcnt = 0;
+}
+
+static inline int
+bz2_getc (void *stream)
+{
+ return inptr < insize ? inbuf[inptr++] : fill_inbuf (1);
+}
+
+static inline int
+bz2_putc (int c, void *stream)
+{
+ if (outcnt == OUTBUFSIZ)
+ flush_outbuf ();
+ outbuf[outcnt++] = c;
+ return c;
+}
+
+static inline int
+bz2_ferror (void *stream)
+{
+ return 0;
+}
+
+static inline int
+bz2_fflush (void *stream)
+{
+ flush_outbuf ();
+ return 0;
+}
+
+static inline int
+bz2_fclose (void *stream)
+{
+ flush_outbuf ();
+ return 0;
+}
+
+#define fprintf(s, f...) /**/
+
+
+/*-----------------------------------------------------------*/
+/*--- A block-sorting, lossless compressor bzip2.c ---*/
+/*-----------------------------------------------------------*/
+
+/*--
+ This program is bzip2, a lossless, block-sorting data compressor,
+ version 0.1pl2, dated 29-Aug-1997.
+
+ Copyright (C) 1996, 1997 by Julian Seward.
+ Guildford, Surrey, UK
+ email: address@hidden
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The GNU General Public License is contained in the file LICENSE.
+
+ This program is based on (at least) the work of:
+ Mike Burrows
+ David Wheeler
+ Peter Fenwick
+ Alistair Moffat
+ Radford Neal
+ Ian H. Witten
+ Robert Sedgewick
+ Jon L. Bentley
+
+ For more information on these sources, see the file ALGORITHMS.
+--*/
+
+/*----------------------------------------------------*/
+/*--- IMPORTANT ---*/
+/*----------------------------------------------------*/
+
+/*--
+ WARNING:
+ This program (attempts to) compress data by performing several
+ non-trivial transformations on it. Unless you are 100% familiar
+ with *all* the algorithms contained herein, and with the
+ consequences of modifying them, you should NOT meddle with the
+ compression or decompression machinery. Incorrect changes can
+ and very likely *will* lead to disastrous loss of data.
+
+ DISCLAIMER:
+ I TAKE NO RESPONSIBILITY FOR ANY LOSS OF DATA ARISING FROM THE
+ USE OF THIS PROGRAM, HOWSOEVER CAUSED.
+
+ Every compression of a file implies an assumption that the
+ compressed file can be decompressed to reproduce the original.
+ Great efforts in design, coding and testing have been made to
+ ensure that this program works correctly. However, the
+ complexity of the algorithms, and, in particular, the presence
+ of various special cases in the code which occur with very low
+ but non-zero probability make it impossible to rule out the
+ possibility of bugs remaining in the program. DO NOT COMPRESS
+ ANY DATA WITH THIS PROGRAM UNLESS YOU ARE PREPARED TO ACCEPT THE
+ POSSIBILITY, HOWEVER SMALL, THAT THE DATA WILL NOT BE RECOVERABLE.
+
+ That is not to say this program is inherently unreliable.
+ Indeed, I very much hope the opposite is true. bzip2 has been
+ carefully constructed and extensively tested.
+
+ PATENTS:
+ To the best of my knowledge, bzip2 does not use any patented
+ algorithms. However, I do not have the resources available to
+ carry out a full patent search. Therefore I cannot give any
+ guarantee of the above statement.
+--*/
+
+
+
+/*----------------------------------------------------*/
+/*--- and now for something much more pleasant :-) ---*/
+/*----------------------------------------------------*/
+
+/*---------------------------------------------*/
+/*--
+ Place a 1 beside your platform, and 0 elsewhere.
+--*/
+
+/*--
+ Generic 32-bit Unix.
+ Also works on 64-bit Unix boxes.
+--*/
+#define BZ_UNIX 1
+
+/*--
+ Win32, as seen by Jacob Navia's excellent
+ port of (Chris Fraser & David Hanson)'s excellent
+ lcc compiler.
+--*/
+#define BZ_LCCWIN32 0
+
+
+
+/*---------------------------------------------*/
+/*--
+ Some stuff for all platforms.
+--*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#if DEBUG
+ #include <assert.h>
+#endif
+#include <string.h>
+#include <signal.h>
+#include <math.h>
+
+#define ERROR_IF_EOF(i) { if ((i) == EOF) ioError(); }
+#define ERROR_IF_NOT_ZERO(i) { if ((i) != 0) ioError(); }
+#define ERROR_IF_MINUS_ONE(i) { if ((i) == (-1)) ioError(); }
+
+
+/*---------------------------------------------*/
+/*--
+ Platform-specific stuff.
+--*/
+
+#if BZ_UNIX
+ #include <sys/types.h>
+ #include <utime.h>
+ #include <unistd.h>
+ #include <malloc.h>
+ #include <sys/stat.h>
+ #include <sys/times.h>
+
+ #define Int32 int
+ #define UInt32 unsigned int
+ #define Char char
+ #define UChar unsigned char
+ #define Int16 short
+ #define UInt16 unsigned short
+
+ #define PATH_SEP '/'
+ #define MY_LSTAT lstat
+ #define MY_S_IFREG S_ISREG
+ #define MY_STAT stat
+
+ #define APPEND_FILESPEC(root, name) \
+ root=snocString((root), (name))
+
+ #define SET_BINARY_MODE(fd) /**/
+
+ /*--
+ You should try very hard to persuade your C compiler
+ to inline the bits marked INLINE. Otherwise bzip2 will
+ run rather slowly. gcc version 2.x is recommended.
+ --*/
+ #ifdef __GNUC__
+ #define INLINE inline
+ #define NORETURN __attribute__ ((noreturn))
+ #else
+ #define INLINE /**/
+ #define NORETURN /**/
+ #endif
+#endif
+
+
+
+#if BZ_LCCWIN32
+ #include <io.h>
+ #include <fcntl.h>
+ #include <sys\stat.h>
+
+ #define Int32 int
+ #define UInt32 unsigned int
+ #define Int16 short
+ #define UInt16 unsigned short
+ #define Char char
+ #define UChar unsigned char
+
+ #define INLINE /**/
+ #define NORETURN /**/
+ #define PATH_SEP '\\'
+ #define MY_LSTAT _stat
+ #define MY_STAT _stat
+ #define MY_S_IFREG(x) ((x) & _S_IFREG)
+
+ #if 0
+ /*-- lcc-win32 seems to expand wildcards itself --*/
+ #define APPEND_FILESPEC(root, spec) \
+ do { \
+ if ((spec)[0] == '-') { \
+ root = snocString((root), (spec)); \
+ } else { \
+ struct _finddata_t c_file; \
+ long hFile; \
+ hFile = _findfirst((spec), &c_file); \
+ if ( hFile == -1L ) { \
+ root = snocString ((root), (spec)); \
+ } else { \
+ int anInt = 0; \
+ while ( anInt == 0 ) { \
+ root = snocString((root), \
+ &c_file.name[0]); \
+ anInt = _findnext(hFile, &c_file); \
+ } \
+ } \
+ } \
+ } while ( 0 )
+ #else
+ #define APPEND_FILESPEC(root, name) \
+ root = snocString ((root), (name))
+ #endif
+
+ #define SET_BINARY_MODE(fd) \
+ do { \
+ int retVal = setmode ( fileno ( fd ), \
+ O_BINARY ); \
+ ERROR_IF_MINUS_ONE ( retVal ); \
+ } while ( 0 )
+
+#endif
+
+
+/*---------------------------------------------*/
+/*--
+ Some more stuff for all platforms :-)
+--*/
+
+#define Bool unsigned char
+#define True 1
+#define False 0
+
+/*--
+ IntNative is your platform's `native' int size.
+ Only here to avoid probs with 64-bit platforms.
+--*/
+#define IntNative int
+
+
+/*--
+ change to 1, or compile with -DDEBUG=1 to debug
+--*/
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+
+
+/*---------------------------------------------------*/
+/*--- ---*/
+/*---------------------------------------------------*/
+
+/*--
+ Implementation notes, July 1997
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Memory allocation
+ ~~~~~~~~~~~~~~~~~
+ All large data structures are allocated on the C heap,
+ for better or for worse. That includes the various
+ arrays of pointers, striped words, bytes, frequency
+ tables and buffers for compression and decompression.
+
+ bzip2 can operate at various block-sizes, ranging from
+ 100k to 900k in 100k steps, and it allocates only as
+ much as it needs to. When compressing, we know from the
+ command-line options what the block-size is going to be,
+ so all allocation can be done at start-up; if that
+ succeeds, there can be no further allocation problems.
+
+ Decompression is more complicated. Each compressed file
+ contains, in its header, a byte indicating the block
+ size used for compression. This means bzip2 potentially
+ needs to reallocate memory for each file it deals with,
+ which in turn opens the possibility for a memory allocation
+ failure part way through a run of files, by encountering
+ a file requiring a much larger block size than all the
+ ones preceding it.
+
+ The policy is to simply give up if a memory allocation
+ failure occurs. During decompression, it would be
+ possible to move on to subsequent files in the hope that
+ some might ask for a smaller block size, but the
+ complications for doing this seem more trouble than they
+ are worth.
+
+
+ Compressed file formats
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ [This is now entirely different from both 0.21, and from
+ any previous Huffman-coded variant of bzip.
+ See the associated file bzip2.txt for details.]
+
+
+ Error conditions
+ ~~~~~~~~~~~~~~~~
+ Dealing with error conditions is the least satisfactory
+ aspect of bzip2. The policy is to try and leave the
+ filesystem in a consistent state, then quit, even if it
+ means not processing some of the files mentioned in the
+ command line. `A consistent state' means that a file
+ exists either in its compressed or uncompressed form,
+ but not both. This boils down to the rule `delete the
+ output file if an error condition occurs, leaving the
+ input intact'. Input files are only deleted when we can
+ be pretty sure the output file has been written and
+ closed successfully.
+
+ Errors are a dog because there's so many things to
+ deal with. The following can happen mid-file, and
+ require cleaning up.
+
+ internal `panics' -- indicating a bug
+ corrupted or inconsistent compressed file
+ can't allocate enough memory to decompress this file
+ I/O error reading/writing/opening/closing
+ signal catches -- Control-C, SIGTERM, SIGHUP.
+
+ Other conditions, primarily pertaining to file names,
+ can be checked in-between files, which makes dealing
+ with them easier.
+--*/
+
+
+
+/*---------------------------------------------------*/
+/*--- Misc (file handling) data decls ---*/
+/*---------------------------------------------------*/
+
+static UInt32 bytesIn, bytesOut;
+static Int32 verbosity;
+static Bool smallMode;
+static UInt32 globalCrc;
+
+
+
+
+static void panic ( Char* );
+static void ioError ( void );
+static void uncompressOutOfMemory ( Int32, Int32 );
+static void blockOverrun ( void );
+static void badBlockHeader ( void );
+static void crcError ( UInt32, UInt32 );
+static void cleanUpAndFail ( Int32 );
+static void compressedStreamEOF ( void );
+
+
+
+/*---------------------------------------------------*/
+/*--- Data decls for the front end ---*/
+/*---------------------------------------------------*/
+
+/*--
+ The overshoot bytes allow us to avoid most of
+ the cost of pointer renormalisation during
+ comparison of rotations in sorting.
+ The figure of 20 is derived as follows:
+ qSort3 allows an overshoot of up to 10.
+ It then calls simpleSort, which calls
+ fullGtU, also with max overshoot 10.
+ fullGtU does up to 10 comparisons without
+ renormalising, giving 10+10 == 20.
+--*/
+#define NUM_OVERSHOOT_BYTES 20
+
+/*--
+ These are the main data structures for
+ the Burrows-Wheeler transform.
+--*/
+
+/*--
+ Pointers to compression and decompression
+ structures. Set by
+ allocateCompressStructures and
+ setDecompressStructureSizes
+
+ The structures are always set to be suitable
+ for a block of size 100000 * blockSize100k.
+--*/
+static UInt16 *ll16; /*-- small decompress --*/
+static UChar *ll4; /*-- small decompress --*/
+
+static Int32 *tt; /*-- fast decompress --*/
+static UChar *ll8; /*-- fast decompress --*/
+
+
+/*--
+ freq table collected to save a pass over the data
+ during decompression.
+--*/
+static Int32 unzftab[256];
+
+
+/*--
+ index of the last char in the block, so
+ the block size == last + 1.
+--*/
+static Int32 last;
+
+
+/*--
+ index in zptr[] of original string after sorting.
+--*/
+static Int32 origPtr;
+
+
+/*--
+ always: in the range 0 .. 9.
+ The current block size is 100000 * this number.
+--*/
+static Int32 blockSize100k;
+
+
+/*--
+ Used when sorting. If too many long comparisons
+ happen, we stop sorting, randomise the block
+ slightly, and try again.
+--*/
+
+static Bool blockRandomised;
+
+
+
+/*---------------------------------------------------*/
+/*--- Data decls for the back end ---*/
+/*---------------------------------------------------*/
+
+#define MAX_ALPHA_SIZE 258
+#define MAX_CODE_LEN 23
+
+#define RUNA 0
+#define RUNB 1
+
+#define N_GROUPS 6
+#define G_SIZE 50
+#define N_ITERS 4
+
+#define MAX_SELECTORS (2 + (900000 / G_SIZE))
+
+static Bool inUse[256];
+static Int32 nInUse;
+
+static UChar seqToUnseq[256];
+static UChar unseqToSeq[256];
+
+static UChar selector [MAX_SELECTORS];
+static UChar selectorMtf[MAX_SELECTORS];
+
+static UChar len [N_GROUPS][MAX_ALPHA_SIZE];
+
+/*-- decompress only --*/
+static Int32 limit [N_GROUPS][MAX_ALPHA_SIZE];
+static Int32 base [N_GROUPS][MAX_ALPHA_SIZE];
+static Int32 perm [N_GROUPS][MAX_ALPHA_SIZE];
+static Int32 minLens[N_GROUPS];
+
+
+/*---------------------------------------------------*/
+/*--- 32-bit CRC grunge ---*/
+/*---------------------------------------------------*/
+
+/*--
+ I think this is an implementation of the AUTODIN-II,
+ Ethernet & FDDI 32-bit CRC standard. Vaguely derived
+ from code by Rob Warnock, in Section 51 of the
+ comp.compression FAQ.
+--*/
+
+static UInt32 crc32Table[256] = {
+
+ /*-- Ugly, innit? --*/
+
+ 0x00000000UL, 0x04c11db7UL, 0x09823b6eUL, 0x0d4326d9UL,
+ 0x130476dcUL, 0x17c56b6bUL, 0x1a864db2UL, 0x1e475005UL,
+ 0x2608edb8UL, 0x22c9f00fUL, 0x2f8ad6d6UL, 0x2b4bcb61UL,
+ 0x350c9b64UL, 0x31cd86d3UL, 0x3c8ea00aUL, 0x384fbdbdUL,
+ 0x4c11db70UL, 0x48d0c6c7UL, 0x4593e01eUL, 0x4152fda9UL,
+ 0x5f15adacUL, 0x5bd4b01bUL, 0x569796c2UL, 0x52568b75UL,
+ 0x6a1936c8UL, 0x6ed82b7fUL, 0x639b0da6UL, 0x675a1011UL,
+ 0x791d4014UL, 0x7ddc5da3UL, 0x709f7b7aUL, 0x745e66cdUL,
+ 0x9823b6e0UL, 0x9ce2ab57UL, 0x91a18d8eUL, 0x95609039UL,
+ 0x8b27c03cUL, 0x8fe6dd8bUL, 0x82a5fb52UL, 0x8664e6e5UL,
+ 0xbe2b5b58UL, 0xbaea46efUL, 0xb7a96036UL, 0xb3687d81UL,
+ 0xad2f2d84UL, 0xa9ee3033UL, 0xa4ad16eaUL, 0xa06c0b5dUL,
+ 0xd4326d90UL, 0xd0f37027UL, 0xddb056feUL, 0xd9714b49UL,
+ 0xc7361b4cUL, 0xc3f706fbUL, 0xceb42022UL, 0xca753d95UL,
+ 0xf23a8028UL, 0xf6fb9d9fUL, 0xfbb8bb46UL, 0xff79a6f1UL,
+ 0xe13ef6f4UL, 0xe5ffeb43UL, 0xe8bccd9aUL, 0xec7dd02dUL,
+ 0x34867077UL, 0x30476dc0UL, 0x3d044b19UL, 0x39c556aeUL,
+ 0x278206abUL, 0x23431b1cUL, 0x2e003dc5UL, 0x2ac12072UL,
+ 0x128e9dcfUL, 0x164f8078UL, 0x1b0ca6a1UL, 0x1fcdbb16UL,
+ 0x018aeb13UL, 0x054bf6a4UL, 0x0808d07dUL, 0x0cc9cdcaUL,
+ 0x7897ab07UL, 0x7c56b6b0UL, 0x71159069UL, 0x75d48ddeUL,
+ 0x6b93dddbUL, 0x6f52c06cUL, 0x6211e6b5UL, 0x66d0fb02UL,
+ 0x5e9f46bfUL, 0x5a5e5b08UL, 0x571d7dd1UL, 0x53dc6066UL,
+ 0x4d9b3063UL, 0x495a2dd4UL, 0x44190b0dUL, 0x40d816baUL,
+ 0xaca5c697UL, 0xa864db20UL, 0xa527fdf9UL, 0xa1e6e04eUL,
+ 0xbfa1b04bUL, 0xbb60adfcUL, 0xb6238b25UL, 0xb2e29692UL,
+ 0x8aad2b2fUL, 0x8e6c3698UL, 0x832f1041UL, 0x87ee0df6UL,
+ 0x99a95df3UL, 0x9d684044UL, 0x902b669dUL, 0x94ea7b2aUL,
+ 0xe0b41de7UL, 0xe4750050UL, 0xe9362689UL, 0xedf73b3eUL,
+ 0xf3b06b3bUL, 0xf771768cUL, 0xfa325055UL, 0xfef34de2UL,
+ 0xc6bcf05fUL, 0xc27dede8UL, 0xcf3ecb31UL, 0xcbffd686UL,
+ 0xd5b88683UL, 0xd1799b34UL, 0xdc3abdedUL, 0xd8fba05aUL,
+ 0x690ce0eeUL, 0x6dcdfd59UL, 0x608edb80UL, 0x644fc637UL,
+ 0x7a089632UL, 0x7ec98b85UL, 0x738aad5cUL, 0x774bb0ebUL,
+ 0x4f040d56UL, 0x4bc510e1UL, 0x46863638UL, 0x42472b8fUL,
+ 0x5c007b8aUL, 0x58c1663dUL, 0x558240e4UL, 0x51435d53UL,
+ 0x251d3b9eUL, 0x21dc2629UL, 0x2c9f00f0UL, 0x285e1d47UL,
+ 0x36194d42UL, 0x32d850f5UL, 0x3f9b762cUL, 0x3b5a6b9bUL,
+ 0x0315d626UL, 0x07d4cb91UL, 0x0a97ed48UL, 0x0e56f0ffUL,
+ 0x1011a0faUL, 0x14d0bd4dUL, 0x19939b94UL, 0x1d528623UL,
+ 0xf12f560eUL, 0xf5ee4bb9UL, 0xf8ad6d60UL, 0xfc6c70d7UL,
+ 0xe22b20d2UL, 0xe6ea3d65UL, 0xeba91bbcUL, 0xef68060bUL,
+ 0xd727bbb6UL, 0xd3e6a601UL, 0xdea580d8UL, 0xda649d6fUL,
+ 0xc423cd6aUL, 0xc0e2d0ddUL, 0xcda1f604UL, 0xc960ebb3UL,
+ 0xbd3e8d7eUL, 0xb9ff90c9UL, 0xb4bcb610UL, 0xb07daba7UL,
+ 0xae3afba2UL, 0xaafbe615UL, 0xa7b8c0ccUL, 0xa379dd7bUL,
+ 0x9b3660c6UL, 0x9ff77d71UL, 0x92b45ba8UL, 0x9675461fUL,
+ 0x8832161aUL, 0x8cf30badUL, 0x81b02d74UL, 0x857130c3UL,
+ 0x5d8a9099UL, 0x594b8d2eUL, 0x5408abf7UL, 0x50c9b640UL,
+ 0x4e8ee645UL, 0x4a4ffbf2UL, 0x470cdd2bUL, 0x43cdc09cUL,
+ 0x7b827d21UL, 0x7f436096UL, 0x7200464fUL, 0x76c15bf8UL,
+ 0x68860bfdUL, 0x6c47164aUL, 0x61043093UL, 0x65c52d24UL,
+ 0x119b4be9UL, 0x155a565eUL, 0x18197087UL, 0x1cd86d30UL,
+ 0x029f3d35UL, 0x065e2082UL, 0x0b1d065bUL, 0x0fdc1becUL,
+ 0x3793a651UL, 0x3352bbe6UL, 0x3e119d3fUL, 0x3ad08088UL,
+ 0x2497d08dUL, 0x2056cd3aUL, 0x2d15ebe3UL, 0x29d4f654UL,
+ 0xc5a92679UL, 0xc1683bceUL, 0xcc2b1d17UL, 0xc8ea00a0UL,
+ 0xd6ad50a5UL, 0xd26c4d12UL, 0xdf2f6bcbUL, 0xdbee767cUL,
+ 0xe3a1cbc1UL, 0xe760d676UL, 0xea23f0afUL, 0xeee2ed18UL,
+ 0xf0a5bd1dUL, 0xf464a0aaUL, 0xf9278673UL, 0xfde69bc4UL,
+ 0x89b8fd09UL, 0x8d79e0beUL, 0x803ac667UL, 0x84fbdbd0UL,
+ 0x9abc8bd5UL, 0x9e7d9662UL, 0x933eb0bbUL, 0x97ffad0cUL,
+ 0xafb010b1UL, 0xab710d06UL, 0xa6322bdfUL, 0xa2f33668UL,
+ 0xbcb4666dUL, 0xb8757bdaUL, 0xb5365d03UL, 0xb1f740b4UL
+};
+
+
+/*---------------------------------------------*/
+
+static void initialiseCRC ( void )
+{
+ globalCrc = 0xffffffffUL;
+}
+
+
+/*---------------------------------------------*/
+
+static UInt32 getFinalCRC ( void )
+{
+ return ~globalCrc;
+}
+
+
+/*---------------------------------------------*/
+
+static UInt32 getGlobalCRC ( void )
+{
+ return globalCrc;
+}
+
+
+/*---------------------------------------------*/
+
+static void setGlobalCRC ( UInt32 newCrc )
+{
+ globalCrc = newCrc;
+}
+
+
+/*---------------------------------------------*/
+
+#define UPDATE_CRC(crcVar,cha) \
+{ \
+ crcVar = (crcVar << 8) ^ \
+ crc32Table[(crcVar >> 24) ^ \
+ ((UChar)cha)]; \
+}
+
+
+/*---------------------------------------------------*/
+/*--- Bit stream I/O ---*/
+/*---------------------------------------------------*/
+
+
+static UInt32 bsBuff;
+static Int32 bsLive;
+static void* bsStream;
+static Bool bsWriting;
+
+
+/*---------------------------------------------*/
+
+static void bsSetStream ( void* f, Bool wr )
+{
+ if (bsStream != NULL) panic ( "bsSetStream" );
+ bsStream = f;
+ bsLive = 0;
+ bsBuff = 0;
+ bytesOut = 0;
+ bytesIn = 0;
+ bsWriting = wr;
+}
+
+
+/*---------------------------------------------*/
+
+static void bsFinishedWithStream ( void )
+{
+ if (bsWriting)
+ while (bsLive > 0) {
+ bz2_putc ( (UChar)(bsBuff >> 24), bsStream );
+ bsBuff <<= 8;
+ bsLive -= 8;
+ bytesOut++;
+ }
+ bsStream = NULL;
+}
+
+
+/*---------------------------------------------*/
+
+#define bsNEEDR(nz) \
+{ \
+ while (bsLive < nz) { \
+ Int32 zzi = bz2_getc ( bsStream ); \
+ if (zzi == EOF) compressedStreamEOF(); \
+ bsBuff = (bsBuff << 8) | (zzi & 0xffL); \
+ bsLive += 8; \
+ } \
+}
+
+
+/*---------------------------------------------*/
+
+#define bsR1(vz) \
+{ \
+ bsNEEDR(1); \
+ vz = (bsBuff >> (bsLive-1)) & 1; \
+ bsLive--; \
+}
+
+
+/*---------------------------------------------*/
+
+static INLINE UInt32 bsR ( Int32 n )
+{
+ UInt32 v;
+ bsNEEDR ( n );
+ v = (bsBuff >> (bsLive-n)) & ((1 << n)-1);
+ bsLive -= n;
+ return v;
+}
+
+
+/*---------------------------------------------*/
+
+static UChar bsGetUChar ( void )
+{
+ return (UChar)bsR(8);
+}
+
+
+
+/*---------------------------------------------*/
+
+static Int32 bsGetUInt32 ( void )
+{
+ UInt32 u;
+ u = 0;
+ u = (u << 8) | bsR(8);
+ u = (u << 8) | bsR(8);
+ u = (u << 8) | bsR(8);
+ u = (u << 8) | bsR(8);
+ return u;
+}
+
+
+/*---------------------------------------------*/
+
+static UInt32 bsGetIntVS ( UInt32 numBits )
+{
+ return (UInt32)bsR(numBits);
+}
+
+
+
+/*---------------------------------------------------*/
+/*--- Huffman coding low-level stuff ---*/
+/*---------------------------------------------------*/
+
+
+/*---------------------------------------------*/
+
+static void hbCreateDecodeTables ( Int32 *limit,
+ Int32 *base,
+ Int32 *perm,
+ UChar *length,
+ Int32 minLen,
+ Int32 maxLen,
+ Int32 alphaSize )
+{
+ Int32 pp, i, j, vec;
+
+ pp = 0;
+ for (i = minLen; i <= maxLen; i++)
+ for (j = 0; j < alphaSize; j++)
+ if (length[j] == i) { perm[pp] = j; pp++; };
+
+ for (i = 0; i < MAX_CODE_LEN; i++) base[i] = 0;
+ for (i = 0; i < alphaSize; i++) base[length[i]+1]++;
+
+ for (i = 1; i < MAX_CODE_LEN; i++) base[i] += base[i-1];
+
+ for (i = 0; i < MAX_CODE_LEN; i++) limit[i] = 0;
+ vec = 0;
+
+ for (i = minLen; i <= maxLen; i++) {
+ vec += (base[i+1] - base[i]);
+ limit[i] = vec-1;
+ vec <<= 1;
+ }
+ for (i = minLen + 1; i <= maxLen; i++)
+ base[i] = ((limit[i-1] + 1) << 1) - base[i];
+}
+
+
+
+/*---------------------------------------------------*/
+/*--- Undoing the reversible transformation ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------*/
+
+#define SET_LL4(i,n) \
+ { if (((i) & 0x1) == 0) \
+ ll4[(i) >> 1] = (ll4[(i) >> 1] & 0xf0) | (n); else \
+ ll4[(i) >> 1] = (ll4[(i) >> 1] & 0x0f) | ((n) << 4); \
+ }
+
+
+#define GET_LL4(i) \
+ (((UInt32)(ll4[(i) >> 1])) >> (((i) << 2) & 0x4) & 0xF)
+
+
+#define SET_LL(i,n) \
+ { ll16[i] = (UInt16)(n & 0x0000ffff); \
+ SET_LL4(i, n >> 16); \
+ }
+
+
+#define GET_LL(i) \
+ (((UInt32)ll16[i]) | (GET_LL4(i) << 16))
+
+
+/*---------------------------------------------*/
+/*--
+ Manage memory for compression/decompression.
+ When compressing, a single block size applies to
+ all files processed, and that's set when the
+ program starts. But when decompressing, each file
+ processed could have been compressed with a
+ different block size, so we may have to free
+ and reallocate on a per-file basis.
+
+ A call with argument of zero means
+ `free up everything.' And a value of zero for
+ blockSize100k means no memory is currently allocated.
+--*/
+
+
+/*---------------------------------------------*/
+
+static void setDecompressStructureSizes ( Int32 newSize100k )
+{
+ if (! (0 <= newSize100k && newSize100k <= 9 &&
+ 0 <= blockSize100k && blockSize100k <= 9))
+ panic ( "setDecompressStructureSizes" );
+
+ if (newSize100k == blockSize100k) return;
+
+ blockSize100k = newSize100k;
+
+ if (ll16 != NULL) free ( ll16 );
+ if (ll4 != NULL) free ( ll4 );
+ if (ll8 != NULL) free ( ll8 );
+ if (tt != NULL) free ( tt );
+
+ if (newSize100k == 0) return;
+
+ if (smallMode) {
+
+ Int32 n = 100000 * newSize100k;
+ ll16 = malloc ( n * sizeof(UInt16) );
+ ll4 = malloc ( ((n+1) >> 1) * sizeof(UChar) );
+
+ if (ll4 == NULL || ll16 == NULL) {
+ Int32 totalDraw
+ = n * sizeof(Int16) + ((n+1) >> 1) * sizeof(UChar);
+ uncompressOutOfMemory ( totalDraw, n );
+ }
+
+ } else {
+
+ Int32 n = 100000 * newSize100k;
+ ll8 = malloc ( n * sizeof(UChar) );
+ tt = malloc ( n * sizeof(Int32) );
+
+ if (ll8 == NULL || tt == NULL) {
+ Int32 totalDraw
+ = n * sizeof(UChar) + n * sizeof(UInt32);
+ uncompressOutOfMemory ( totalDraw, n );
+ }
+
+ }
+}
+
+
+
+/*---------------------------------------------------*/
+/*--- The new back end ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------*/
+
+static void makeMaps ( void )
+{
+ Int32 i;
+ nInUse = 0;
+ for (i = 0; i < 256; i++)
+ if (inUse[i]) {
+ seqToUnseq[nInUse] = i;
+ unseqToSeq[i] = nInUse;
+ nInUse++;
+ }
+}
+
+
+
+/*---------------------------------------------*/
+
+static void recvDecodingTables ( void )
+{
+ Int32 i, j, t, nGroups, nSelectors, alphaSize;
+ Int32 minLen, maxLen;
+ Bool inUse16[16];
+
+ /*--- Receive the mapping table ---*/
+ for (i = 0; i < 16; i++)
+ if (bsR(1) == 1)
+ inUse16[i] = True; else
+ inUse16[i] = False;
+
+ for (i = 0; i < 256; i++) inUse[i] = False;
+
+ for (i = 0; i < 16; i++)
+ if (inUse16[i])
+ for (j = 0; j < 16; j++)
+ if (bsR(1) == 1) inUse[i * 16 + j] = True;
+
+ makeMaps();
+ alphaSize = nInUse+2;
+
+ /*--- Now the selectors ---*/
+ nGroups = bsR ( 3 );
+ nSelectors = bsR ( 15 );
+ for (i = 0; i < nSelectors; i++) {
+ j = 0;
+ while (bsR(1) == 1) j++;
+ selectorMtf[i] = j;
+ }
+
+ /*--- Undo the MTF values for the selectors. ---*/
+ {
+ UChar pos[N_GROUPS], tmp, v;
+ for (v = 0; v < nGroups; v++) pos[v] = v;
+
+ for (i = 0; i < nSelectors; i++) {
+ v = selectorMtf[i];
+ tmp = pos[v];
+ while (v > 0) { pos[v] = pos[v-1]; v--; }
+ pos[0] = tmp;
+ selector[i] = tmp;
+ }
+ }
+
+ /*--- Now the coding tables ---*/
+ for (t = 0; t < nGroups; t++) {
+ Int32 curr = bsR ( 5 );
+ for (i = 0; i < alphaSize; i++) {
+ while (bsR(1) == 1) {
+ if (bsR(1) == 0) curr++; else curr--;
+ }
+ len[t][i] = curr;
+ }
+ }
+
+ /*--- Create the Huffman decoding tables ---*/
+ for (t = 0; t < nGroups; t++) {
+ minLen = 32;
+ maxLen = 0;
+ for (i = 0; i < alphaSize; i++) {
+ if (len[t][i] > maxLen) maxLen = len[t][i];
+ if (len[t][i] < minLen) minLen = len[t][i];
+ }
+ hbCreateDecodeTables (
+ &limit[t][0], &base[t][0], &perm[t][0], &len[t][0],
+ minLen, maxLen, alphaSize
+ );
+ minLens[t] = minLen;
+ }
+}
+
+
+/*---------------------------------------------*/
+
+#define GET_MTF_VAL(lval) \
+{ \
+ Int32 zt, zn, zvec, zj; \
+ if (groupPos == 0) { \
+ groupNo++; \
+ groupPos = G_SIZE; \
+ } \
+ groupPos--; \
+ zt = selector[groupNo]; \
+ zn = minLens[zt]; \
+ zvec = bsR ( zn ); \
+ while (zvec > limit[zt][zn]) { \
+ zn++; bsR1(zj); \
+ zvec = (zvec << 1) | zj; \
+ }; \
+ lval = perm[zt][zvec - base[zt][zn]]; \
+}
+
+
+/*---------------------------------------------*/
+
+static void getAndMoveToFrontDecode ( void )
+{
+ UChar yy[256];
+ Int32 i, j, nextSym, limitLast;
+ Int32 EOB, groupNo, groupPos;
+
+ limitLast = 100000 * blockSize100k;
+ origPtr = bsGetIntVS ( 24 );
+
+ recvDecodingTables();
+ EOB = nInUse+1;
+ groupNo = -1;
+ groupPos = 0;
+
+ /*--
+ Setting up the unzftab entries here is not strictly
+ necessary, but it does save having to do it later
+ in a separate pass, and so saves a block's worth of
+ cache misses.
+ --*/
+ for (i = 0; i <= 255; i++) unzftab[i] = 0;
+
+ for (i = 0; i <= 255; i++) yy[i] = (UChar) i;
+
+ last = -1;
+
+ GET_MTF_VAL(nextSym);
+
+ while (True) {
+
+ if (nextSym == EOB) break;
+
+ if (nextSym == RUNA || nextSym == RUNB) {
+ UChar ch;
+ Int32 s = -1;
+ Int32 N = 1;
+ do {
+ if (nextSym == RUNA) s = s + (0+1) * N; else
+ if (nextSym == RUNB) s = s + (1+1) * N;
+ N = N * 2;
+ GET_MTF_VAL(nextSym);
+ }
+ while (nextSym == RUNA || nextSym == RUNB);
+
+ s++;
+ ch = seqToUnseq[yy[0]];
+ unzftab[ch] += s;
+
+ if (smallMode)
+ while (s > 0) {
+ last++;
+ ll16[last] = ch;
+ s--;
+ }
+ else
+ while (s > 0) {
+ last++;
+ ll8[last] = ch;
+ s--;
+ };
+
+ if (last >= limitLast) blockOverrun();
+ continue;
+
+ } else {
+
+ UChar tmp;
+ last++; if (last >= limitLast) blockOverrun();
+
+ tmp = yy[nextSym-1];
+ unzftab[seqToUnseq[tmp]]++;
+ if (smallMode)
+ ll16[last] = seqToUnseq[tmp]; else
+ ll8[last] = seqToUnseq[tmp];
+
+ /*--
+ This loop is hammered during decompression,
+ hence the unrolling.
+
+ for (j = nextSym-1; j > 0; j--) yy[j] = yy[j-1];
+ --*/
+
+ j = nextSym-1;
+ for (; j > 3; j -= 4) {
+ yy[j] = yy[j-1];
+ yy[j-1] = yy[j-2];
+ yy[j-2] = yy[j-3];
+ yy[j-3] = yy[j-4];
+ }
+ for (; j > 0; j--) yy[j] = yy[j-1];
+
+ yy[0] = tmp;
+ GET_MTF_VAL(nextSym);
+ continue;
+ }
+ }
+}
+
+
+/*---------------------------------------------------*/
+/*--- Stuff for randomising repetitive blocks ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------*/
+static Int32 rNums[512] = {
+ 619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
+ 985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
+ 733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
+ 419, 436, 278, 496, 867, 210, 399, 680, 480, 51,
+ 878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
+ 862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
+ 150, 238, 59, 379, 684, 877, 625, 169, 643, 105,
+ 170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
+ 73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
+ 909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
+ 641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
+ 161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
+ 382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
+ 98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
+ 227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
+ 469, 68, 770, 919, 190, 373, 294, 822, 808, 206,
+ 184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
+ 715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
+ 951, 160, 578, 722, 79, 804, 96, 409, 713, 940,
+ 652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
+ 645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
+ 609, 772, 154, 274, 580, 184, 79, 626, 630, 742,
+ 653, 282, 762, 623, 680, 81, 927, 626, 789, 125,
+ 411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
+ 170, 774, 972, 275, 999, 639, 495, 78, 352, 126,
+ 857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
+ 669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
+ 944, 375, 748, 52, 600, 747, 642, 182, 862, 81,
+ 344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
+ 897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
+ 433, 837, 553, 268, 926, 240, 102, 654, 459, 51,
+ 686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
+ 946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
+ 978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
+ 680, 879, 194, 572, 640, 724, 926, 56, 204, 700,
+ 707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
+ 297, 59, 87, 824, 713, 663, 412, 693, 342, 606,
+ 134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
+ 343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
+ 140, 206, 73, 263, 980, 736, 876, 478, 430, 305,
+ 170, 514, 364, 692, 829, 82, 855, 953, 676, 246,
+ 369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
+ 804, 378, 215, 828, 592, 281, 565, 555, 710, 82,
+ 896, 831, 547, 261, 524, 462, 293, 465, 502, 56,
+ 661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
+ 768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
+ 61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
+ 372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
+ 780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
+ 920, 176, 193, 713, 857, 265, 203, 50, 668, 108,
+ 645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
+ 936, 638
+};
+
+
+#define RAND_DECLS \
+ Int32 rNToGo = 0; \
+ Int32 rTPos = 0; \
+
+#define RAND_MASK ((rNToGo == 1) ? 1 : 0)
+
+#define RAND_UPD_MASK \
+ if (rNToGo == 0) { \
+ rNToGo = rNums[rTPos]; \
+ rTPos++; if (rTPos == 512) rTPos = 0; \
+ } \
+ rNToGo--;
+
+
+
+/*---------------------------------------------------*/
+/*--- The Reversible Transformation (tm) ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------*/
+
+
+static INLINE Int32 indexIntoF ( Int32 indx, Int32 *cftab )
+{
+ Int32 nb, na, mid;
+ nb = 0;
+ na = 256;
+ do {
+ mid = (nb + na) >> 1;
+ if (indx >= cftab[mid]) nb = mid; else na = mid;
+ }
+ while (na - nb != 1);
+ return nb;
+}
+
+
+
+#define GET_SMALL(cccc) \
+ \
+ cccc = indexIntoF ( tPos, cftab ); \
+ tPos = GET_LL(tPos);
+
+
+
+static void undoReversibleTransformation_small ( void* dst )
+{
+ Int32 cftab[257], cftabAlso[257];
+ Int32 i, j, tmp, tPos;
+ UChar ch;
+
+ /*--
+ We assume here that the global array unzftab will
+ already be holding the frequency counts for
+ ll8[0 .. last].
+ --*/
+
+ /*-- Set up cftab to facilitate generation of indexIntoF --*/
+ cftab[0] = 0;
+ for (i = 1; i <= 256; i++) cftab[i] = unzftab[i-1];
+ for (i = 1; i <= 256; i++) cftab[i] += cftab[i-1];
+
+ /*-- Make a copy of it, used in generation of T --*/
+ for (i = 0; i <= 256; i++) cftabAlso[i] = cftab[i];
+
+ /*-- compute the T vector --*/
+ for (i = 0; i <= last; i++) {
+ ch = (UChar)ll16[i];
+ SET_LL(i, cftabAlso[ch]);
+ cftabAlso[ch]++;
+ }
+
+ /*--
+ Compute T^(-1) by pointer reversal on T. This is rather
+ subtle, in that, if the original block was two or more
+ (in general, N) concatenated copies of the same thing,
+ the T vector will consist of N cycles, each of length
+ blocksize / N, and decoding will involve traversing one
+ of these cycles N times. Which particular cycle doesn't
+ matter -- they are all equivalent. The tricky part is to
+ make sure that the pointer reversal creates a correct
+ reversed cycle for us to traverse. So, the code below
+ simply reverses whatever cycle origPtr happens to fall into,
+ without regard to the cycle length. That gives one reversed
+ cycle, which for normal blocks, is the entire block-size long.
+ For repeated blocks, it will be interspersed with the other
+ N-1 non-reversed cycles. Providing that the F-subscripting
+ phase which follows starts at origPtr, all then works ok.
+ --*/
+ i = origPtr;
+ j = GET_LL(i);
+ do {
+ tmp = GET_LL(j);
+ SET_LL(j, i);
+ i = j;
+ j = tmp;
+ }
+ while (i != origPtr);
+
+ /*--
+ We recreate the original by subscripting F through T^(-1).
+ The run-length-decoder below requires characters incrementally,
+ so tPos is set to a starting value, and is updated by
+ the GET_SMALL macro.
+ --*/
+ tPos = origPtr;
+
+ /*-------------------------------------------------*/
+ /*--
+ This is pretty much a verbatim copy of the
+ run-length decoder present in the distribution
+ bzip-0.21; it has to be here to avoid creating
+ block[] as an intermediary structure. As in 0.21,
+ this code derives from some sent to me by
+ Christian von Roques.
+
+ It allows dst==NULL, so as to support the test (-t)
+ option without slowing down the fast decompression
+ code.
+ --*/
+ {
+ IntNative retVal;
+ Int32 i2, count, chPrev, ch2;
+ UInt32 localCrc;
+
+ count = 0;
+ i2 = 0;
+ ch2 = 256; /*-- not a char and not EOF --*/
+ localCrc = getGlobalCRC();
+
+ {
+ RAND_DECLS;
+ while ( i2 <= last ) {
+ chPrev = ch2;
+ GET_SMALL(ch2);
+ if (blockRandomised) {
+ RAND_UPD_MASK;
+ ch2 ^= (UInt32)RAND_MASK;
+ }
+ i2++;
+
+ if (dst)
+ retVal = bz2_putc ( ch2, dst );
+
+ UPDATE_CRC ( localCrc, (UChar)ch2 );
+
+ if (ch2 != chPrev) {
+ count = 1;
+ } else {
+ count++;
+ if (count >= 4) {
+ Int32 j2;
+ UChar z;
+ GET_SMALL(z);
+ if (blockRandomised) {
+ RAND_UPD_MASK;
+ z ^= RAND_MASK;
+ }
+ for (j2 = 0; j2 < (Int32)z; j2++) {
+ if (dst) retVal = bz2_putc (ch2, dst);
+ UPDATE_CRC ( localCrc, (UChar)ch2 );
+ }
+ i2++;
+ count = 0;
+ }
+ }
+ }
+ }
+
+ setGlobalCRC ( localCrc );
+ }
+ /*-- end of the in-line run-length-decoder. --*/
+}
+#undef GET_SMALL
+
+
+/*---------------------------------------------*/
+
+#define GET_FAST(cccc) \
+ \
+ cccc = ll8[tPos]; \
+ tPos = tt[tPos];
+
+
+
+static void undoReversibleTransformation_fast ( void* dst )
+{
+ Int32 cftab[257];
+ Int32 i, tPos;
+ UChar ch;
+
+ /*--
+ We assume here that the global array unzftab will
+ already be holding the frequency counts for
+ ll8[0 .. last].
+ --*/
+
+ /*-- Set up cftab to facilitate generation of T^(-1) --*/
+ cftab[0] = 0;
+ for (i = 1; i <= 256; i++) cftab[i] = unzftab[i-1];
+ for (i = 1; i <= 256; i++) cftab[i] += cftab[i-1];
+
+ /*-- compute the T^(-1) vector --*/
+ for (i = 0; i <= last; i++) {
+ ch = (UChar)ll8[i];
+ tt[cftab[ch]] = i;
+ cftab[ch]++;
+ }
+
+ /*--
+ We recreate the original by subscripting L through T^(-1).
+ The run-length-decoder below requires characters incrementally,
+ so tPos is set to a starting value, and is updated by
+ the GET_FAST macro.
+ --*/
+ tPos = tt[origPtr];
+
+ /*-------------------------------------------------*/
+ /*--
+ This is pretty much a verbatim copy of the
+ run-length decoder present in the distribution
+ bzip-0.21; it has to be here to avoid creating
+ block[] as an intermediary structure. As in 0.21,
+ this code derives from some sent to me by
+ Christian von Roques.
+ --*/
+ {
+ IntNative retVal;
+ Int32 i2, count, chPrev, ch2;
+ UInt32 localCrc;
+
+ count = 0;
+ i2 = 0;
+ ch2 = 256; /*-- not a char and not EOF --*/
+ localCrc = getGlobalCRC();
+
+ if (blockRandomised) {
+ RAND_DECLS;
+ while ( i2 <= last ) {
+ chPrev = ch2;
+ GET_FAST(ch2);
+ RAND_UPD_MASK;
+ ch2 ^= (UInt32)RAND_MASK;
+ i2++;
+
+ retVal = bz2_putc ( ch2, dst );
+ UPDATE_CRC ( localCrc, (UChar)ch2 );
+
+ if (ch2 != chPrev) {
+ count = 1;
+ } else {
+ count++;
+ if (count >= 4) {
+ Int32 j2;
+ UChar z;
+ GET_FAST(z);
+ RAND_UPD_MASK;
+ z ^= RAND_MASK;
+ for (j2 = 0; j2 < (Int32)z; j2++) {
+ retVal = bz2_putc (ch2, dst);
+ UPDATE_CRC ( localCrc, (UChar)ch2 );
+ }
+ i2++;
+ count = 0;
+ }
+ }
+ }
+
+ } else {
+
+ while ( i2 <= last ) {
+ chPrev = ch2;
+ GET_FAST(ch2);
+ i2++;
+
+ retVal = bz2_putc ( ch2, dst );
+ UPDATE_CRC ( localCrc, (UChar)ch2 );
+
+ if (ch2 != chPrev) {
+ count = 1;
+ } else {
+ count++;
+ if (count >= 4) {
+ Int32 j2;
+ UChar z;
+ GET_FAST(z);
+ for (j2 = 0; j2 < (Int32)z; j2++) {
+ retVal = bz2_putc (ch2, dst);
+ UPDATE_CRC ( localCrc, (UChar)ch2 );
+ }
+ i2++;
+ count = 0;
+ }
+ }
+ }
+
+ } /*-- if (blockRandomised) --*/
+
+ setGlobalCRC ( localCrc );
+ }
+ /*-- end of the in-line run-length-decoder. --*/
+}
+#undef GET_FAST
+
+
+
+/*---------------------------------------------------*/
+/*--- Processing of complete files and streams ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------*/
+
+static Bool uncompressStream ( void *zStream, void *stream )
+{
+ UChar magic1, magic2, magic3, magic4;
+ UChar magic5, magic6;
+ UInt32 storedBlockCRC, storedCombinedCRC;
+ UInt32 computedBlockCRC, computedCombinedCRC;
+ Int32 currBlockNo;
+ IntNative retVal;
+
+ SET_BINARY_MODE(stream);
+ SET_BINARY_MODE(zStream);
+
+ ERROR_IF_NOT_ZERO ( bz2_ferror(stream) );
+ ERROR_IF_NOT_ZERO ( bz2_ferror(zStream) );
+
+ bsSetStream ( zStream, False );
+
+ /*--
+ A bad magic number is `recoverable from';
+ return with False so the caller skips the file.
+ --*/
+ magic1 = bsGetUChar ();
+ magic2 = bsGetUChar ();
+ magic3 = bsGetUChar ();
+ magic4 = bsGetUChar ();
+ if (magic1 != 'B' ||
+ magic2 != 'Z' ||
+ magic3 != 'h' ||
+ magic4 < '1' ||
+ magic4 > '9') {
+ bsFinishedWithStream();
+ retVal = bz2_fclose ( stream );
+ ERROR_IF_EOF ( retVal );
+ return False;
+ }
+
+ setDecompressStructureSizes ( magic4 - '0' );
+ computedCombinedCRC = 0;
+
+ if (verbosity >= 2) fprintf ( stderr, "\n " );
+ currBlockNo = 0;
+
+ while (True) {
+ magic1 = bsGetUChar ();
+ magic2 = bsGetUChar ();
+ magic3 = bsGetUChar ();
+ magic4 = bsGetUChar ();
+ magic5 = bsGetUChar ();
+ magic6 = bsGetUChar ();
+ if (magic1 == 0x17 && magic2 == 0x72 &&
+ magic3 == 0x45 && magic4 == 0x38 &&
+ magic5 == 0x50 && magic6 == 0x90) break;
+
+ if (magic1 != 0x31 || magic2 != 0x41 ||
+ magic3 != 0x59 || magic4 != 0x26 ||
+ magic5 != 0x53 || magic6 != 0x59) badBlockHeader();
+
+ storedBlockCRC = bsGetUInt32 ();
+
+ if (bsR(1) == 1)
+ blockRandomised = True; else
+ blockRandomised = False;
+
+ currBlockNo++;
+ if (verbosity >= 2)
+ fprintf ( stderr, "[%d: huff+mtf ", currBlockNo );
+ getAndMoveToFrontDecode ();
+ ERROR_IF_NOT_ZERO ( bz2_ferror(zStream) );
+
+ initialiseCRC();
+ if (verbosity >= 2) fprintf ( stderr, "rt+rld" );
+ if (smallMode)
+ undoReversibleTransformation_small ( stream );
+ else
+ undoReversibleTransformation_fast ( stream );
+
+ ERROR_IF_NOT_ZERO ( bz2_ferror(stream) );
+
+ computedBlockCRC = getFinalCRC();
+ if (verbosity >= 3)
+ fprintf ( stderr, " {0x%x, 0x%x}", storedBlockCRC, computedBlockCRC );
+ if (verbosity >= 2) fprintf ( stderr, "] " );
+
+ /*-- A bad CRC is considered a fatal error. --*/
+ if (storedBlockCRC != computedBlockCRC)
+ crcError ( storedBlockCRC, computedBlockCRC );
+
+ computedCombinedCRC = (computedCombinedCRC << 1) | (computedCombinedCRC
>> 31);
+ computedCombinedCRC ^= computedBlockCRC;
+ };
+
+ if (verbosity >= 2) fprintf ( stderr, "\n " );
+
+ storedCombinedCRC = bsGetUInt32 ();
+ if (verbosity >= 2)
+ fprintf ( stderr,
+ "combined CRCs: stored = 0x%x, computed = 0x%x\n ",
+ storedCombinedCRC, computedCombinedCRC );
+ if (storedCombinedCRC != computedCombinedCRC)
+ crcError ( storedCombinedCRC, computedCombinedCRC );
+
+
+ bsFinishedWithStream ();
+ ERROR_IF_NOT_ZERO ( bz2_ferror(zStream) );
+ retVal = bz2_fclose ( zStream );
+ ERROR_IF_EOF ( retVal );
+
+ ERROR_IF_NOT_ZERO ( bz2_ferror(stream) );
+ retVal = bz2_fflush ( stream );
+ ERROR_IF_NOT_ZERO ( retVal );
+ return True;
+}
+
+
+#if 0
+
+#endif
+/*---------------------------------------------------*/
+/*--- Error [non-] handling grunge ---*/
+/*---------------------------------------------------*/
+
+
+
+static void
+myFree (void **p)
+{
+ free (*p);
+ *p = NULL;
+}
+
+/*---------------------------------------------*/
+/* Ugg... Orignal code doesn't free dynamic allocated memories. */
+
+static void cleanUpAndFail ( Int32 ec )
+{
+ myFree ((void **) &ll16);
+ myFree ((void **) &ll4);
+ myFree ((void **) &ll8);
+ myFree ((void **) &tt);
+
+ (*unzip_error) (NULL);
+}
+
+
+/*---------------------------------------------*/
+
+static void panic ( Char* s )
+{
+ cleanUpAndFail( 3 );
+}
+
+
+
+/*---------------------------------------------*/
+
+static void crcError ( UInt32 crcStored, UInt32 crcComputed )
+{
+ cleanUpAndFail( 2 );
+}
+
+
+/*---------------------------------------------*/
+
+static void compressedStreamEOF ( void )
+{
+ cleanUpAndFail( 2 );
+}
+
+
+/*---------------------------------------------*/
+
+static void ioError ( )
+{
+ cleanUpAndFail( 1 );
+}
+
+
+/*---------------------------------------------*/
+
+static void blockOverrun ()
+{
+ cleanUpAndFail( 2 );
+}
+
+
+/*---------------------------------------------*/
+
+static void badBlockHeader ()
+{
+ cleanUpAndFail( 2 );
+}
+
+
+
+/*---------------------------------------------*/
+static void uncompressOutOfMemory ( Int32 draw, Int32 blockSize )
+{
+ cleanUpAndFail(1);
+}
+
+
+
+/*-----------------------------------------------------------*/
+/*--- end bzip2.c ---*/
+/*-----------------------------------------------------------*/
+
+void
+do_bunzip2 (void)
+{
+ Bool ret;
+
+ /*-- Initialise --*/
+ ll4 = NULL;
+ ll16 = NULL;
+ ll8 = NULL;
+ tt = NULL;
+#ifdef SMALL_BZIP2
+ smallMode = True;
+#else
+ smallMode = False;
+#endif
+ verbosity = 0;
+ blockSize100k = 0;
+ bsStream = NULL;
+
+ outcnt = 0;
+ inptr = 0;
+ insize = 0;
+
+ ret = uncompressStream ((void *)1, (void *)2); /* Arguments ignored. */
+ if (ret != True)
+ cleanUpAndFail(1);
+}
diff --git a/libstore/gzip.h b/libstore/gzip.h
new file mode 100644
index 0000000..aedc257
--- /dev/null
+++ b/libstore/gzip.h
@@ -0,0 +1,315 @@
+/* gzip.h -- common declarations for all gzip modules
+ * Copyright (C) 1992-1993, 1996 Jean-loup Gailly.
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+#if defined(__STDC__) || defined(PROTO)
+# define OF(args) args
+#else
+# define OF(args) ()
+#endif
+
+#ifdef __STDC__
+ typedef void *voidp;
+#else
+ typedef char *voidp;
+#endif
+
+/* I don't like nested includes, but the string and io functions are used
+ * too often
+ */
+#include <stdio.h>
+#if !defined(NO_STRING_H) || defined(STDC_HEADERS)
+# include <string.h>
+# if !defined(STDC_HEADERS) && !defined(NO_MEMORY_H) && !defined(__GNUC__)
+# include <memory.h>
+# endif
+# define memzero(s, n) memset ((voidp)(s), 0, (n))
+#else
+# include <strings.h>
+# define strchr index
+# define strrchr rindex
+# define memcpy(d, s, n) bcopy((s), (d), (n))
+# define memcmp(s1, s2, n) bcmp((s1), (s2), (n))
+# define memzero(s, n) bzero((s), (n))
+#endif
+
+#ifndef RETSIGTYPE
+# define RETSIGTYPE void
+#endif
+
+#define local static
+
+typedef unsigned char uch;
+typedef unsigned short ush;
+typedef unsigned long ulg;
+
+/* Return codes from gzip */
+#define OK 0
+#define ERROR 1
+#define WARNING 2
+
+/* Compression methods (see algorithm.doc) */
+#define STORED 0
+#define COMPRESSED 1
+#define PACKED 2
+#define LZHED 3
+/* methods 4 to 7 reserved */
+#define DEFLATED 8
+#define MAX_METHODS 9
+extern int method; /* compression method */
+
+/* To save memory for 16 bit systems, some arrays are overlaid between
+ * the various modules:
+ * deflate: prev+head window d_buf l_buf outbuf
+ * unlzw: tab_prefix tab_suffix stack inbuf outbuf
+ * inflate: window inbuf
+ * unpack: window inbuf prefix_len
+ * unlzh: left+right window c_table inbuf c_len
+ * For compression, input is done in window[]. For decompression, output
+ * is done in window except for unlzw.
+ */
+
+#ifndef INBUFSIZ
+# ifdef SMALL_MEM
+# define INBUFSIZ 0x2000 /* input buffer size */
+# else
+# define INBUFSIZ 0x8000 /* input buffer size */
+# endif
+#endif
+#define INBUF_EXTRA 64 /* required by unlzw() */
+
+#ifndef OUTBUFSIZ
+# ifdef SMALL_MEM
+# define OUTBUFSIZ 8192 /* output buffer size */
+# else
+# define OUTBUFSIZ 16384 /* output buffer size */
+# endif
+#endif
+#define OUTBUF_EXTRA 2048 /* required by unlzw() */
+
+#ifndef DIST_BUFSIZE
+# ifdef SMALL_MEM
+# define DIST_BUFSIZE 0x2000 /* buffer for distances, see trees.c */
+# else
+# define DIST_BUFSIZE 0x8000 /* buffer for distances, see trees.c */
+# endif
+#endif
+
+#ifdef DYN_ALLOC
+# define EXTERN(type, array) extern type * near array
+# define DECLARE(type, array, size) type * near array
+# define ALLOC(type, array, size) { \
+ array = (type*)fcalloc((size_t)(((size)+1L)/2), 2*sizeof(type)); \
+ if (array == NULL) error("insufficient memory"); \
+ }
+# define FREE(array) {if (array != NULL) fcfree(array), array=NULL;}
+#else
+# define EXTERN(type, array) extern type array[]
+# define DECLARE(type, array, size) type array[size]
+# define ALLOC(type, array, size)
+# define FREE(array)
+#endif
+
+EXTERN(uch, inbuf); /* input buffer */
+EXTERN(uch, outbuf); /* output buffer */
+EXTERN(ush, d_buf); /* buffer for distances, see trees.c */
+EXTERN(uch, window); /* Sliding window and suffix table (unlzw) */
+#define tab_suffix window
+#ifndef MAXSEG_64K
+# define tab_prefix prev /* hash link (see deflate.c) */
+# define head (prev+WSIZE) /* hash head (see deflate.c) */
+ EXTERN(ush, tab_prefix); /* prefix code (see unlzw.c) */
+#else
+# define tab_prefix0 prev
+# define head tab_prefix1
+ EXTERN(ush, tab_prefix0); /* prefix for even codes */
+ EXTERN(ush, tab_prefix1); /* prefix for odd codes */
+#endif
+
+extern unsigned insize; /* valid bytes in inbuf */
+extern unsigned inptr; /* index of next byte to be processed in inbuf */
+extern unsigned outcnt; /* bytes in output buffer */
+
+extern long bytes_in; /* number of input bytes */
+extern long bytes_out; /* number of output bytes */
+extern long header_bytes;/* number of bytes in gzip header */
+
+#define isize bytes_in
+/* for compatibility with old zip sources (to be cleaned) */
+
+extern int ifd; /* input file descriptor */
+extern int ofd; /* output file descriptor */
+extern char ifname[]; /* input file name or "stdin" */
+extern char ofname[]; /* output file name or "stdout" */
+extern char *progname; /* program name */
+
+extern long time_stamp; /* original time stamp (modification time) */
+extern long ifile_size; /* input file size, -1 for devices (debug only) */
+
+typedef int file_t; /* Do not use stdio */
+#define NO_FILE (-1) /* in memory compression */
+
+
+#define PACK_MAGIC "\037\036" /* Magic header for packed files */
+#define GZIP_MAGIC "\037\213" /* Magic header for gzip files, 1F 8B
*/
+#define OLD_GZIP_MAGIC "\037\236" /* Magic header for gzip 0.5 = freeze
1.x */
+#define LZH_MAGIC "\037\240" /* Magic header for SCO LZH Compress
files*/
+#define PKZIP_MAGIC "\120\113\003\004" /* Magic header for pkzip files */
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
+#define RESERVED 0xC0 /* bit 6,7: reserved */
+
+/* internal file attribute */
+#define UNKNOWN 0xffff
+#define BINARY 0
+#define ASCII 1
+
+#ifndef WSIZE
+# define WSIZE 0x8000 /* window size--must be a power of two, and */
+#endif /* at least 32K for zip's deflate method */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST (WSIZE-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+extern int decrypt; /* flag to turn on decryption */
+extern int exit_code; /* program exit code */
+extern int verbose; /* be verbose (-v) */
+extern int quiet; /* be quiet (-q) */
+extern int level; /* compression level */
+extern int test; /* check .z file integrity */
+extern int to_stdout; /* output to stdout (-c) */
+extern int save_orig_name; /* set if original name must be saved */
+
+#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf(0))
+#define try_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf(1))
+
+/* put_byte is used for the compressed output, put_ubyte for the
+ * uncompressed output. However unlzw() uses window for its
+ * suffix table instead of its output buffer, so it does not use put_ubyte
+ * (to be cleaned up).
+ */
+#define put_byte(c) {outbuf[outcnt++]=(uch)(c); if (outcnt==OUTBUFSIZ)\
+ flush_outbuf();}
+#define put_ubyte(c) {window[outcnt++]=(uch)(c); if (outcnt==WSIZE)\
+ flush_window();}
+
+/* Output a 16 bit value, lsb first */
+#define put_short(w) \
+{ if (outcnt < OUTBUFSIZ-2) { \
+ outbuf[outcnt++] = (uch) ((w) & 0xff); \
+ outbuf[outcnt++] = (uch) ((ush)(w) >> 8); \
+ } else { \
+ put_byte((uch)((w) & 0xff)); \
+ put_byte((uch)((ush)(w) >> 8)); \
+ } \
+}
+
+/* Output a 32 bit value to the bit stream, lsb first */
+#define put_long(n) { \
+ put_short((n) & 0xffff); \
+ put_short(((ulg)(n)) >> 16); \
+}
+
+#define seekable() 0 /* force sequential output */
+#define translate_eol 0 /* no option -a yet */
+
+#define tolow(c) (isupper(c) ? (c)-'A'+'a' : (c)) /* force to lower case */
+
+/* Macros for getting two-byte and four-byte header values */
+#define SH(p) ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8))
+#define LG(p) ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16))
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# define Assert(cond,msg) {if(!(cond)) error(msg);}
+# define Trace(x) fprintf x
+# define Tracev(x) {if (verbose) fprintf x ;}
+# define Tracevv(x) {if (verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+#define WARN(msg) {if (!quiet) fprintf msg ; \
+ if (exit_code == OK) exit_code = WARNING;}
+
+ /* in zip.c: */
+extern int zip OF((int in, int out));
+extern int file_read OF((char *buf, unsigned size));
+
+ /* in unzip.c */
+extern int unzip OF((int in, int out));
+extern int check_zipfile OF((int in));
+
+ /* in unpack.c */
+extern int unpack OF((int in, int out));
+
+ /* in unlzh.c */
+extern int unlzh OF((int in, int out));
+
+ /* in gzip.c */
+RETSIGTYPE abort_gzip OF((void));
+
+ /* in deflate.c */
+void lm_init OF((int pack_level, ush *flags));
+ulg deflate OF((void));
+
+ /* in trees.c */
+void ct_init OF((ush *attr, int *method));
+int ct_tally OF((int dist, int lc));
+ulg flush_block OF((char *buf, ulg stored_len, int eof));
+
+ /* in bits.c */
+void bi_init OF((file_t zipfile));
+void send_bits OF((int value, int length));
+unsigned bi_reverse OF((unsigned value, int length));
+void bi_windup OF((void));
+void copy_block OF((char *buf, unsigned len, int header));
+extern int (*read_buf) OF((char *buf, unsigned size));
+
+ /* in util.c: */
+extern int copy OF((int in, int out));
+extern ulg updcrc OF((uch *s, unsigned n));
+extern void clear_bufs OF((void));
+extern int fill_inbuf OF((int eof_ok));
+extern void flush_outbuf OF((void));
+extern void flush_window OF((void));
+extern void write_buf OF((int fd, voidp buf, unsigned cnt));
+extern char *strlwr OF((char *s));
+/* extern char *basename OF((char *fname));*/
+extern void make_simple_name OF((char *name));
+extern char *add_envopt OF((int *argcp, char ***argvp, char *env));
+extern void error OF((char *m));
+extern void warn OF((char *a, char *b));
+extern void read_error OF((void));
+extern void write_error OF((void));
+extern void display_ratio OF((long num, long den, FILE *file));
+extern voidp xmalloc OF((unsigned int size));
+
+ /* in inflate.c */
+extern int inflate OF((void));
diff --git a/libstore/inflate.c b/libstore/inflate.c
new file mode 100644
index 0000000..c3be438
--- /dev/null
+++ b/libstore/inflate.c
@@ -0,0 +1,954 @@
+/* inflate.c -- Not copyrighted 1992 by Mark Adler
+ version c10p1, 10 January 1993 */
+
+/* You can do whatever you like with this source file, though I would
+ prefer that if you modify it and redistribute it that you include
+ comments to that effect with your name and the date. Thank you.
+ [The history has been moved to the file ChangeLog.]
+ */
+
+/*
+ Inflate deflated (PKZIP's method 8 compressed) data. The compression
+ method searches for as much of the current string of bytes (up to a
+ length of 258) in the previous 32K bytes. If it doesn't find any
+ matches (of at least length 3), it codes the next byte. Otherwise, it
+ codes the length of the matched string and its distance backwards from
+ the current position. There is a single Huffman code that codes both
+ single bytes (called "literals") and match lengths. A second Huffman
+ code codes the distance information, which follows a length code. Each
+ length or distance code actually represents a base value and a number
+ of "extra" (sometimes zero) bits to get to add to the base value. At
+ the end of each deflated block is a special end-of-block (EOB) literal/
+ length code. The decoding process is basically: get a literal/length
+ code; if EOB then done; if a literal, emit the decoded byte; if a
+ length then get the distance and emit the referred-to bytes from the
+ sliding window of previously emitted data.
+
+ There are (currently) three kinds of inflate blocks: stored, fixed, and
+ dynamic. The compressor deals with some chunk of data at a time, and
+ decides which method to use on a chunk-by-chunk basis. A chunk might
+ typically be 32K or 64K. If the chunk is uncompressible, then the
+ "stored" method is used. In this case, the bytes are simply stored as
+ is, eight bits per byte, with none of the above coding. The bytes are
+ preceded by a count, since there is no longer an EOB code.
+
+ If the data is compressible, then either the fixed or dynamic methods
+ are used. In the dynamic method, the compressed data is preceded by
+ an encoding of the literal/length and distance Huffman codes that are
+ to be used to decode this block. The representation is itself Huffman
+ coded, and so is preceded by a description of that code. These code
+ descriptions take up a little space, and so for small blocks, there is
+ a predefined set of codes, called the fixed codes. The fixed method is
+ used if the block codes up smaller that way (usually for quite small
+ chunks), otherwise the dynamic method is used. In the latter case, the
+ codes are customized to the probabilities in the current block, and so
+ can code it much better than the pre-determined fixed codes.
+
+ The Huffman codes themselves are decoded using a mutli-level table
+ lookup, in order to maximize the speed of decoding plus the speed of
+ building the decoding tables. See the comments below that precede the
+ lbits and dbits tuning parameters.
+ */
+
+
+/*
+ Notes beyond the 1.93a appnote.txt:
+
+ 1. Distance pointers never point before the beginning of the output
+ stream.
+ 2. Distance pointers can point back across blocks, up to 32k away.
+ 3. There is an implied maximum of 7 bits for the bit length table and
+ 15 bits for the actual data.
+ 4. If only one code exists, then it is encoded using one bit. (Zero
+ would be more efficient, but perhaps a little confusing.) If two
+ codes exist, they are coded using one bit each (0 and 1).
+ 5. There is no way of sending zero distance codes--a dummy must be
+ sent if there are none. (History: a pre 2.0 version of PKZIP would
+ store blocks with no distance codes, but this was discovered to be
+ too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
+ zero distance codes, which is sent as one code of zero bits in
+ length.
+ 6. There are up to 286 literal/length codes. Code 256 represents the
+ end-of-block. Note however that the static length tree defines
+ 288 codes just to fill out the Huffman codes. Codes 286 and 287
+ cannot be used though, since there is no length base or extra bits
+ defined for them. Similarly, there are up to 30 distance codes.
+ However, static trees define 32 codes (all 5 bits) to fill out the
+ Huffman codes, but the last two had better not show up in the data.
+ 7. Unzip can check dynamic Huffman blocks for complete code sets.
+ The exception is that a single code would not be complete (see #4).
+ 8. The five bits following the block type is really the number of
+ literal codes sent minus 257.
+ 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+ (1+6+6). Therefore, to output three times the length, you output
+ three codes (1+1+1), whereas to output four times the same length,
+ you only need two codes (1+3). Hmm.
+ 10. In the tree reconstruction algorithm, Code = Code + Increment
+ only if BitLength(i) is not zero. (Pretty obvious.)
+ 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
+ 12. Note: length code 284 can represent 227-258, but length code 285
+ really is 258. The last length deserves its own, short code
+ since it gets used a lot in very redundant files. The length
+ 258 is special since 258 - 3 (the min match length) is 255.
+ 13. The literal/length and distance code bit lengths are read as a
+ single stream of lengths. It is possible (and advantageous) for
+ a repeat code (16, 17, or 18) to go across the boundary between
+ the two sets of lengths.
+ */
+
+#ifdef RCSID
+static char rcsid[] = "$Id: inflate.c,v 1.1 1994/12/14 04:31:21 roland Exp $";
+#endif
+
+#include <sys/types.h>
+
+#include "tailor.h"
+
+#if defined(STDC_HEADERS) || !defined(NO_STDLIB_H)
+# include <stdlib.h>
+#endif
+
+#include "gzip.h"
+#define slide window
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+ that have 16-bit pointers (e.g. PC's in the small or medium model).
+ Valid extra bits are 0..13. e == 15 is EOB (end of block), e == 16
+ means that v is a literal, 16 < e < 32 means that v is a pointer to
+ the next table, which codes e - 16 bits, and lastly e == 99 indicates
+ an unused code. If a code with e == 99 is looked up, this implies an
+ error in the data. */
+struct huft {
+ uch e; /* number of extra bits or operation */
+ uch b; /* number of bits in this code or subcode */
+ union {
+ ush n; /* literal, length base, or distance base */
+ struct huft *t; /* pointer to next level of table */
+ } v;
+};
+
+
+/* Function prototypes */
+int huft_build OF((unsigned *, unsigned, unsigned, ush *, ush *,
+ struct huft **, int *));
+int huft_free OF((struct huft *));
+int inflate_codes OF((struct huft *, struct huft *, int, int));
+int inflate_stored OF((void));
+int inflate_fixed OF((void));
+int inflate_dynamic OF((void));
+int inflate_block OF((int *));
+int inflate OF((void));
+
+
+/* The inflate algorithm uses a sliding 32K byte window on the uncompressed
+ stream to find repeated byte strings. This is implemented here as a
+ circular buffer. The index is updated simply by incrementing and then
+ and'ing with 0x7fff (32K-1). */
+/* It is left to other modules to supply the 32K area. It is assumed
+ to be usable as if it were declared "uch slide[32768];" or as just
+ "uch *slide;" and then malloc'ed in the latter case. The definition
+ must be in unzip.h, included above. */
+/* unsigned wp; current position in slide */
+#define wp outcnt
+#define flush_output(w) (wp=(w),flush_window())
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+static unsigned border[] = { /* Order of the bit length code lengths */
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+static ush cplens[] = { /* Copy lengths for literal codes 257..285 */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ /* note: see note #13 above about the 258 in this list. */
+static ush cplext[] = { /* Extra bits for literal codes 257..285 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */
+static ush cpdist[] = { /* Copy offsets for distance codes 0..29 */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577};
+static ush cpdext[] = { /* Extra bits for distance codes */
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13};
+
+
+
+/* Macros for inflate() bit peeking and grabbing.
+ The usage is:
+
+ NEEDBITS(j)
+ x = b & mask_bits[j];
+ DUMPBITS(j)
+
+ where NEEDBITS makes sure that b has at least j bits in it, and
+ DUMPBITS removes the bits from b. The macros use the variable k
+ for the number of bits in b. Normally, b and k are register
+ variables for speed, and are initialized at the beginning of a
+ routine that uses these macros from a global bit buffer and count.
+
+ If we assume that EOB will be the longest code, then we will never
+ ask for bits with NEEDBITS that are beyond the end of the stream.
+ So, NEEDBITS should not read any more bytes than are needed to
+ meet the request. Then no bytes need to be "returned" to the buffer
+ at the end of the last block.
+
+ However, this assumption is not true for fixed blocks--the EOB code
+ is 7 bits, but the other literal/length codes can be 8 or 9 bits.
+ (The EOB code is shorter than other codes because fixed blocks are
+ generally short. So, while a block always has an EOB, many other
+ literal/length codes have a significantly lower probability of
+ showing up at all.) However, by making the first table have a
+ lookup of seven bits, the EOB code will be found in that first
+ lookup, and so will not require that too many bits be pulled from
+ the stream.
+ */
+
+ulg bb; /* bit buffer */
+unsigned bk; /* bits in bit buffer */
+
+ush mask_bits[] = {
+ 0x0000,
+ 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+#ifdef CRYPT
+ uch cc;
+# define NEXTBYTE() \
+ (decrypt ? (cc = get_byte(), zdecode(cc), cc) : get_byte())
+#else
+# define NEXTBYTE() (uch)get_byte()
+#endif
+#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<<k;k+=8;}}
+#define DUMPBITS(n) {b>>=(n);k-=(n);}
+
+
+/*
+ Huffman code decoding is performed using a multi-level table lookup.
+ The fastest way to decode is to simply build a lookup table whose
+ size is determined by the longest code. However, the time it takes
+ to build this table can also be a factor if the data being decoded
+ is not very long. The most common codes are necessarily the
+ shortest codes, so those codes dominate the decoding time, and hence
+ the speed. The idea is you can have a shorter table that decodes the
+ shorter, more probable codes, and then point to subsidiary tables for
+ the longer codes. The time it costs to decode the longer codes is
+ then traded against the time it takes to make longer tables.
+
+ This results of this trade are in the variables lbits and dbits
+ below. lbits is the number of bits the first level table for literal/
+ length codes can decode in one step, and dbits is the same thing for
+ the distance codes. Subsequent tables are also less than or equal to
+ those sizes. These values may be adjusted either when all of the
+ codes are shorter than that, in which case the longest code length in
+ bits is used, or when the shortest code is *longer* than the requested
+ table size, in which case the length of the shortest code in bits is
+ used.
+
+ There are two different values for the two tables, since they code a
+ different number of possibilities each. The literal/length table
+ codes 286 possible values, or in a flat code, a little over eight
+ bits. The distance table codes 30 possible values, or a little less
+ than five bits, flat. The optimum values for speed end up being
+ about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+ The optimum values may differ though from machine to machine, and
+ possibly even between compilers. Your mileage may vary.
+ */
+
+
+int lbits = 9; /* bits in base literal/length lookup table */
+int dbits = 6; /* bits in base distance lookup table */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
+#define BMAX 16 /* maximum bit length of any code (16 for explode) */
+#define N_MAX 288 /* maximum number of codes in any set */
+
+
+unsigned hufts; /* track memory usage */
+
+
+int huft_build(b, n, s, d, e, t, m)
+unsigned *b; /* code lengths in bits (all assumed <= BMAX) */
+unsigned n; /* number of codes (assumed <= N_MAX) */
+unsigned s; /* number of simple-valued codes (0..s-1) */
+ush *d; /* list of base values for non-simple codes */
+ush *e; /* list of extra bits for non-simple codes */
+struct huft **t; /* result: starting table */
+int *m; /* maximum lookup bits, returns actual */
+/* Given a list of code lengths and a maximum table size, make a set of
+ tables to decode that set of codes. Return zero on success, one if
+ the given code set is incomplete (the tables are still built in this
+ case), two if the input is invalid (all zero length codes or an
+ oversubscribed set of lengths), and three if not enough memory. */
+{
+ unsigned a; /* counter for codes of length k */
+ unsigned c[BMAX+1]; /* bit length count table */
+ unsigned f; /* i repeats in table every f entries */
+ int g; /* maximum code length */
+ int h; /* table level */
+ register unsigned i; /* counter, current code */
+ register unsigned j; /* counter */
+ register int k; /* number of bits in current code */
+ int l; /* bits per table (returned in m) */
+ register unsigned *p; /* pointer into c[], b[], or v[] */
+ register struct huft *q; /* points to current table */
+ struct huft r; /* table entry for structure assignment */
+ struct huft *u[BMAX]; /* table stack */
+ unsigned v[N_MAX]; /* values in order of bit length */
+ register int w; /* bits before this table == (l * h) */
+ unsigned x[BMAX+1]; /* bit offsets, then code stack */
+ unsigned *xp; /* pointer into x */
+ int y; /* number of dummy codes added */
+ unsigned z; /* number of entries in current table */
+
+
+ /* Generate counts for each bit length */
+ memzero(c, sizeof(c));
+ p = b; i = n;
+ do {
+ Tracecv(*p, (stderr, (n-i >= ' ' && n-i <= '~' ? "%c %d\n" : "0x%x %d\n"),
+ n-i, *p));
+ c[*p]++; /* assume all entries <= BMAX */
+ p++; /* Can't combine with above line (Solaris bug) */
+ } while (--i);
+ if (c[0] == n) /* null input--all zero length codes */
+ {
+ *t = (struct huft *)NULL;
+ *m = 0;
+ return 0;
+ }
+
+
+ /* Find minimum and maximum length, bound *m by those */
+ l = *m;
+ for (j = 1; j <= BMAX; j++)
+ if (c[j])
+ break;
+ k = j; /* minimum code length */
+ if ((unsigned)l < j)
+ l = j;
+ for (i = BMAX; i; i--)
+ if (c[i])
+ break;
+ g = i; /* maximum code length */
+ if ((unsigned)l > i)
+ l = i;
+ *m = l;
+
+
+ /* Adjust last length count to fill out codes, if needed */
+ for (y = 1 << j; j < i; j++, y <<= 1)
+ if ((y -= c[j]) < 0)
+ return 2; /* bad input: more codes than bits */
+ if ((y -= c[i]) < 0)
+ return 2;
+ c[i] += y;
+
+
+ /* Generate starting offsets into the value table for each length */
+ x[1] = j = 0;
+ p = c + 1; xp = x + 2;
+ while (--i) { /* note that i == g from above */
+ *xp++ = (j += *p++);
+ }
+
+
+ /* Make a table of values in order of bit lengths */
+ p = b; i = 0;
+ do {
+ if ((j = *p++) != 0)
+ v[x[j]++] = i;
+ } while (++i < n);
+
+
+ /* Generate the Huffman codes and for each, make the table entries */
+ x[0] = i = 0; /* first Huffman code is zero */
+ p = v; /* grab values in bit order */
+ h = -1; /* no tables yet--level -1 */
+ w = -l; /* bits decoded == (l * h) */
+ u[0] = (struct huft *)NULL; /* just to keep compilers happy */
+ q = (struct huft *)NULL; /* ditto */
+ z = 0; /* ditto */
+
+ /* go through the bit lengths (k already is bits in shortest code) */
+ for (; k <= g; k++)
+ {
+ a = c[k];
+ while (a--)
+ {
+ /* here i is the Huffman code of length k bits for value *p */
+ /* make tables up to required level */
+ while (k > w + l)
+ {
+ h++;
+ w += l; /* previous table always l bits */
+
+ /* compute minimum size table less than or equal to l bits */
+ z = (z = g - w) > (unsigned)l ? l : z; /* upper limit on table size */
+ if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
+ { /* too few codes for k-w bit table */
+ f -= a + 1; /* deduct codes from patterns left */
+ xp = c + k;
+ while (++j < z) /* try smaller tables up to z bits */
+ {
+ if ((f <<= 1) <= *++xp)
+ break; /* enough codes to use up j bits */
+ f -= *xp; /* else deduct codes from patterns */
+ }
+ }
+ z = 1 << j; /* table entries for j-bit table */
+
+ /* allocate and link in new table */
+ if ((q = (struct huft *)malloc((z + 1)*sizeof(struct huft))) ==
+ (struct huft *)NULL)
+ {
+ if (h)
+ huft_free(u[0]);
+ return 3; /* not enough memory */
+ }
+ hufts += z + 1; /* track memory usage */
+ *t = q + 1; /* link to list for huft_free() */
+ *(t = &(q->v.t)) = (struct huft *)NULL;
+ u[h] = ++q; /* table starts after link */
+
+ /* connect to last table, if there is one */
+ if (h)
+ {
+ x[h] = i; /* save pattern for backing up */
+ r.b = (uch)l; /* bits to dump before this table */
+ r.e = (uch)(16 + j); /* bits in this table */
+ r.v.t = q; /* pointer to this table */
+ j = i >> (w - l); /* (get around Turbo C bug) */
+ u[h-1][j] = r; /* connect to last table */
+ }
+ }
+
+ /* set up table entry in r */
+ r.b = (uch)(k - w);
+ if (p >= v + n)
+ r.e = 99; /* out of values--invalid code */
+ else if (*p < s)
+ {
+ r.e = (uch)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */
+ r.v.n = (ush)(*p); /* simple code is just the value */
+ p++; /* one compiler does not like *p++ */
+ }
+ else
+ {
+ r.e = (uch)e[*p - s]; /* non-simple--look up in lists */
+ r.v.n = d[*p++ - s];
+ }
+
+ /* fill code-like entries with r */
+ f = 1 << (k - w);
+ for (j = i >> w; j < z; j += f)
+ q[j] = r;
+
+ /* backwards increment the k-bit code i */
+ for (j = 1 << (k - 1); i & j; j >>= 1)
+ i ^= j;
+ i ^= j;
+
+ /* backup over finished tables */
+ while ((i & ((1 << w) - 1)) != x[h])
+ {
+ h--; /* don't need to update q */
+ w -= l;
+ }
+ }
+ }
+
+
+ /* Return true (1) if we were given an incomplete table */
+ return y != 0 && g != 1;
+}
+
+
+
+int huft_free(t)
+struct huft *t; /* table to free */
+/* Free the malloc'ed tables built by huft_build(), which makes a linked
+ list of the tables it made, with the links in a dummy first entry of
+ each table. */
+{
+ register struct huft *p, *q;
+
+
+ /* Go through linked list, freeing from the malloced (t[-1]) address. */
+ p = t;
+ while (p != (struct huft *)NULL)
+ {
+ q = (--p)->v.t;
+ free((char*)p);
+ p = q;
+ }
+ return 0;
+}
+
+
+int inflate_codes(tl, td, bl, bd)
+struct huft *tl, *td; /* literal/length and distance decoder tables */
+int bl, bd; /* number of bits decoded by tl[] and td[] */
+/* inflate (decompress) the codes in a deflated (compressed) block.
+ Return an error code or zero if it all goes ok. */
+{
+ register unsigned e; /* table entry flag/number of extra bits */
+ unsigned n, d; /* length and index for copy */
+ unsigned w; /* current window position */
+ struct huft *t; /* pointer to table entry */
+ unsigned ml, md; /* masks for bl and bd bits */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+
+ /* make local copies of globals */
+ b = bb; /* initialize bit buffer */
+ k = bk;
+ w = wp; /* initialize window position */
+
+ /* inflate the coded data */
+ ml = mask_bits[bl]; /* precompute masks for speed */
+ md = mask_bits[bd];
+ for (;;) /* do until end of block */
+ {
+ NEEDBITS((unsigned)bl)
+ if ((e = (t = tl + ((unsigned)b & ml))->e) > 16)
+ do {
+ if (e == 99)
+ return 1;
+ DUMPBITS(t->b)
+ e -= 16;
+ NEEDBITS(e)
+ } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
+ DUMPBITS(t->b)
+ if (e == 16) /* then it's a literal */
+ {
+ slide[w++] = (uch)t->v.n;
+ Tracevv((stderr, "%c", slide[w-1]));
+ if (w == WSIZE)
+ {
+ flush_output(w);
+ w = 0;
+ }
+ }
+ else /* it's an EOB or a length */
+ {
+ /* exit if end of block */
+ if (e == 15)
+ break;
+
+ /* get length of block to copy */
+ NEEDBITS(e)
+ n = t->v.n + ((unsigned)b & mask_bits[e]);
+ DUMPBITS(e);
+
+ /* decode distance of block to copy */
+ NEEDBITS((unsigned)bd)
+ if ((e = (t = td + ((unsigned)b & md))->e) > 16)
+ do {
+ if (e == 99)
+ return 1;
+ DUMPBITS(t->b)
+ e -= 16;
+ NEEDBITS(e)
+ } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
+ DUMPBITS(t->b)
+ NEEDBITS(e)
+ d = w - t->v.n - ((unsigned)b & mask_bits[e]);
+ DUMPBITS(e)
+ Tracevv((stderr,"\\[%d,%d]", w-d, n));
+
+ /* do the copy */
+ do {
+ n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e);
+#if !defined(NOMEMCPY) && !defined(DEBUG)
+ if (w - d >= e) /* (this test assumes unsigned comparison) */
+ {
+ memcpy(slide + w, slide + d, e);
+ w += e;
+ d += e;
+ }
+ else /* do it slow to avoid memcpy() overlap */
+#endif /* !NOMEMCPY */
+ do {
+ slide[w++] = slide[d++];
+ Tracevv((stderr, "%c", slide[w-1]));
+ } while (--e);
+ if (w == WSIZE)
+ {
+ flush_output(w);
+ w = 0;
+ }
+ } while (n);
+ }
+ }
+
+
+ /* restore the globals from the locals */
+ wp = w; /* restore global window pointer */
+ bb = b; /* restore global bit buffer */
+ bk = k;
+
+ /* done */
+ return 0;
+}
+
+
+
+int inflate_stored()
+/* "decompress" an inflated type 0 (stored) block. */
+{
+ unsigned n; /* number of bytes in block */
+ unsigned w; /* current window position */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+
+ /* make local copies of globals */
+ b = bb; /* initialize bit buffer */
+ k = bk;
+ w = wp; /* initialize window position */
+
+
+ /* go to byte boundary */
+ n = k & 7;
+ DUMPBITS(n);
+
+
+ /* get the length and its complement */
+ NEEDBITS(16)
+ n = ((unsigned)b & 0xffff);
+ DUMPBITS(16)
+ NEEDBITS(16)
+ if (n != (unsigned)((~b) & 0xffff))
+ return 1; /* error in compressed data */
+ DUMPBITS(16)
+
+
+ /* read and output the compressed data */
+ while (n--)
+ {
+ NEEDBITS(8)
+ slide[w++] = (uch)b;
+ if (w == WSIZE)
+ {
+ flush_output(w);
+ w = 0;
+ }
+ DUMPBITS(8)
+ }
+
+
+ /* restore the globals from the locals */
+ wp = w; /* restore global window pointer */
+ bb = b; /* restore global bit buffer */
+ bk = k;
+ return 0;
+}
+
+
+
+int inflate_fixed()
+/* decompress an inflated type 1 (fixed Huffman codes) block. We should
+ either replace this with a custom decoder, or at least precompute the
+ Huffman tables. */
+{
+ int i; /* temporary variable */
+ struct huft *tl; /* literal/length code table */
+ struct huft *td; /* distance code table */
+ int bl; /* lookup bits for tl */
+ int bd; /* lookup bits for td */
+ unsigned l[288]; /* length list for huft_build */
+
+
+ /* set up literal table */
+ for (i = 0; i < 144; i++)
+ l[i] = 8;
+ for (; i < 256; i++)
+ l[i] = 9;
+ for (; i < 280; i++)
+ l[i] = 7;
+ for (; i < 288; i++) /* make a complete, but wrong code set */
+ l[i] = 8;
+ bl = 7;
+ if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0)
+ return i;
+
+
+ /* set up distance table */
+ for (i = 0; i < 30; i++) /* make an incomplete code set */
+ l[i] = 5;
+ bd = 5;
+ if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1)
+ {
+ huft_free(tl);
+ return i;
+ }
+
+
+ /* decompress until an end-of-block code */
+ if (inflate_codes(tl, td, bl, bd))
+ return 1;
+
+
+ /* free the decoding tables, return */
+ huft_free(tl);
+ huft_free(td);
+ return 0;
+}
+
+
+
+int inflate_dynamic()
+/* decompress an inflated type 2 (dynamic Huffman codes) block. */
+{
+ int i; /* temporary variables */
+ unsigned j;
+ unsigned l; /* last length */
+ unsigned m; /* mask for bit lengths table */
+ unsigned n; /* number of lengths to get */
+ struct huft *tl; /* literal/length code table */
+ struct huft *td; /* distance code table */
+ int bl; /* lookup bits for tl */
+ int bd; /* lookup bits for td */
+ unsigned nb; /* number of bit length codes */
+ unsigned nl; /* number of literal/length codes */
+ unsigned nd; /* number of distance codes */
+#ifdef PKZIP_BUG_WORKAROUND
+ unsigned ll[288+32]; /* literal/length and distance code lengths */
+#else
+ unsigned ll[286+30]; /* literal/length and distance code lengths */
+#endif
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+
+ /* make local bit buffer */
+ b = bb;
+ k = bk;
+
+
+ /* read in table lengths */
+ NEEDBITS(5)
+ nl = 257 + ((unsigned)b & 0x1f); /* number of literal/length codes */
+ DUMPBITS(5)
+ NEEDBITS(5)
+ nd = 1 + ((unsigned)b & 0x1f); /* number of distance codes */
+ DUMPBITS(5)
+ NEEDBITS(4)
+ nb = 4 + ((unsigned)b & 0xf); /* number of bit length codes */
+ DUMPBITS(4)
+#ifdef PKZIP_BUG_WORKAROUND
+ if (nl > 288 || nd > 32)
+#else
+ if (nl > 286 || nd > 30)
+#endif
+ return 1; /* bad lengths */
+
+
+ /* read in bit-length-code lengths */
+ for (j = 0; j < nb; j++)
+ {
+ NEEDBITS(3)
+ ll[border[j]] = (unsigned)b & 7;
+ DUMPBITS(3)
+ }
+ for (; j < 19; j++)
+ ll[border[j]] = 0;
+
+
+ /* build decoding table for trees--single level, 7 bit lookup */
+ bl = 7;
+ if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0)
+ {
+ if (i == 1)
+ huft_free(tl);
+ return i; /* incomplete code set */
+ }
+
+
+ /* read in literal and distance code lengths */
+ n = nl + nd;
+ m = mask_bits[bl];
+ i = l = 0;
+ while ((unsigned)i < n)
+ {
+ NEEDBITS((unsigned)bl)
+ j = (td = tl + ((unsigned)b & m))->b;
+ DUMPBITS(j)
+ j = td->v.n;
+ if (j < 16) /* length of code in bits (0..15) */
+ ll[i++] = l = j; /* save last length in l */
+ else if (j == 16) /* repeat last length 3 to 6 times */
+ {
+ NEEDBITS(2)
+ j = 3 + ((unsigned)b & 3);
+ DUMPBITS(2)
+ if ((unsigned)i + j > n)
+ return 1;
+ while (j--)
+ ll[i++] = l;
+ }
+ else if (j == 17) /* 3 to 10 zero length codes */
+ {
+ NEEDBITS(3)
+ j = 3 + ((unsigned)b & 7);
+ DUMPBITS(3)
+ if ((unsigned)i + j > n)
+ return 1;
+ while (j--)
+ ll[i++] = 0;
+ l = 0;
+ }
+ else /* j == 18: 11 to 138 zero length codes */
+ {
+ NEEDBITS(7)
+ j = 11 + ((unsigned)b & 0x7f);
+ DUMPBITS(7)
+ if ((unsigned)i + j > n)
+ return 1;
+ while (j--)
+ ll[i++] = 0;
+ l = 0;
+ }
+ }
+
+
+ /* free decoding table for trees */
+ huft_free(tl);
+
+
+ /* restore the global bit buffer */
+ bb = b;
+ bk = k;
+
+
+ /* build the decoding tables for literal/length and distance codes */
+ bl = lbits;
+ if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0)
+ {
+ if (i == 1) {
+ fprintf(stderr, " incomplete literal tree\n");
+ huft_free(tl);
+ }
+ return i; /* incomplete code set */
+ }
+ bd = dbits;
+ if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0)
+ {
+ if (i == 1) {
+ fprintf(stderr, " incomplete distance tree\n");
+#ifdef PKZIP_BUG_WORKAROUND
+ i = 0;
+ }
+#else
+ huft_free(td);
+ }
+ huft_free(tl);
+ return i; /* incomplete code set */
+#endif
+ }
+
+
+ /* decompress until an end-of-block code */
+ if (inflate_codes(tl, td, bl, bd))
+ return 1;
+
+
+ /* free the decoding tables, return */
+ huft_free(tl);
+ huft_free(td);
+ return 0;
+}
+
+
+
+int inflate_block(e)
+int *e; /* last block flag */
+/* decompress an inflated block */
+{
+ unsigned t; /* block type */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+
+ /* make local bit buffer */
+ b = bb;
+ k = bk;
+
+
+ /* read in last block bit */
+ NEEDBITS(1)
+ *e = (int)b & 1;
+ DUMPBITS(1)
+
+
+ /* read in block type */
+ NEEDBITS(2)
+ t = (unsigned)b & 3;
+ DUMPBITS(2)
+
+
+ /* restore the global bit buffer */
+ bb = b;
+ bk = k;
+
+
+ /* inflate that block type */
+ if (t == 2)
+ return inflate_dynamic();
+ if (t == 0)
+ return inflate_stored();
+ if (t == 1)
+ return inflate_fixed();
+
+
+ /* bad block type */
+ return 2;
+}
+
+
+
+int inflate()
+/* decompress an inflated entry */
+{
+ int e; /* last block flag */
+ int r; /* result code */
+ unsigned h; /* maximum struct huft's malloc'ed */
+
+
+ /* initialize window, bit buffer */
+ wp = 0;
+ bk = 0;
+ bb = 0;
+
+
+ /* decompress until the last block */
+ h = 0;
+ do {
+ hufts = 0;
+ if ((r = inflate_block(&e)) != 0)
+ return r;
+ if (hufts > h)
+ h = hufts;
+ } while (!e);
+
+ /* Undo too much lookahead. The next read will be byte aligned so we
+ * can discard unused bits in the last meaningful byte.
+ */
+ while (bk >= 8) {
+ bk -= 8;
+ inptr--;
+ }
+
+ /* flush out slide */
+ flush_output(wp);
+
+
+ /* return success */
+#ifdef DEBUG
+ fprintf(stderr, "<%u> ", h);
+#endif /* DEBUG */
+ return 0;
+}
diff --git a/libstore/tailor.h b/libstore/tailor.h
new file mode 100644
index 0000000..d207af5
--- /dev/null
+++ b/libstore/tailor.h
@@ -0,0 +1,14 @@
+
+#ifndef get_char
+# define get_char() get_byte()
+#endif
+
+#ifndef put_char
+# define put_char(c) put_byte(c)
+#endif
+
+#include <stdio.h>
+#define fprintf(stream, fmt...) /* ignore useless error msgs */ ((void)0)
+
+void (*unzip_error) (const char *msg);
+#define error(msg) (*unzip_error) (msg)
diff --git a/libstore/unzip.c b/libstore/unzip.c
new file mode 100644
index 0000000..d0f5bf1
--- /dev/null
+++ b/libstore/unzip.c
@@ -0,0 +1,199 @@
+/* unzip.c -- decompress files in gzip or pkzip format.
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ *
+ * The code in this file is derived from the file funzip.c written
+ * and put in the public domain by Mark Adler.
+ */
+
+/*
+ This version can extract files in gzip or pkzip format.
+ For the latter, only the first entry is extracted, and it has to be
+ either deflated or stored.
+ */
+
+#ifdef RCSID
+static char rcsid[] = "$Id: unzip.c,v 1.1 1994/12/14 04:30:25 roland Exp $";
+#endif
+
+#include "tailor.h"
+#include "gzip.h"
+#include "crypt.h"
+
+/* PKZIP header definitions */
+#define LOCSIG 0x04034b50L /* four-byte lead-in (lsb first) */
+#define LOCFLG 6 /* offset of bit flag */
+#define CRPFLG 1 /* bit for encrypted entry */
+#define EXTFLG 8 /* bit for extended local header */
+#define LOCHOW 8 /* offset of compression method */
+#define LOCTIM 10 /* file mod time (for decryption) */
+#define LOCCRC 14 /* offset of crc */
+#define LOCSIZ 18 /* offset of compressed size */
+#define LOCLEN 22 /* offset of uncompressed length */
+#define LOCFIL 26 /* offset of file name field length */
+#define LOCEXT 28 /* offset of extra field length */
+#define LOCHDR 30 /* size of local header, including sig */
+#define EXTHDR 16 /* size of extended local header, inc sig */
+
+
+/* Globals */
+
+int decrypt; /* flag to turn on decryption */
+char *key; /* not used--needed to link crypt.c */
+int pkzip = 0; /* set for a pkzip file */
+int ext_header = 0; /* set if extended local header */
+
+/* ===========================================================================
+ * Check zip file and advance inptr to the start of the compressed data.
+ * Get ofname from the local header if necessary.
+ */
+int check_zipfile(in)
+ int in; /* input file descriptors */
+{
+ uch *h = inbuf + inptr; /* first local header */
+
+ ifd = in;
+
+ /* Check validity of local header, and skip name and extra fields */
+ inptr += LOCHDR + SH(h + LOCFIL) + SH(h + LOCEXT);
+
+ if (inptr > insize || LG(h) != LOCSIG) {
+ fprintf(stderr, "\n%s: %s: not a valid zip file\n",
+ progname, ifname);
+ exit_code = ERROR;
+ return ERROR;
+ }
+ method = h[LOCHOW];
+ if (method != STORED && method != DEFLATED) {
+ fprintf(stderr,
+ "\n%s: %s: first entry not deflated or stored -- use unzip\n",
+ progname, ifname);
+ exit_code = ERROR;
+ return ERROR;
+ }
+
+ /* If entry encrypted, decrypt and validate encryption header */
+ if ((decrypt = h[LOCFLG] & CRPFLG) != 0) {
+ fprintf(stderr, "\n%s: %s: encrypted file -- use unzip\n",
+ progname, ifname);
+ exit_code = ERROR;
+ return ERROR;
+ }
+
+ /* Save flags for unzip() */
+ ext_header = (h[LOCFLG] & EXTFLG) != 0;
+ pkzip = 1;
+
+ /* Get ofname and time stamp from local header (to be done) */
+ return OK;
+}
+
+/* ===========================================================================
+ * Unzip in to out. This routine works on both gzip and pkzip files.
+ *
+ * IN assertions: the buffer inbuf contains already the beginning of
+ * the compressed data, from offsets inptr to insize-1 included.
+ * The magic header has already been checked. The output buffer is cleared.
+ */
+int unzip(in, out)
+ int in, out; /* input and output file descriptors */
+{
+ ulg orig_crc = 0; /* original crc */
+ ulg orig_len = 0; /* original uncompressed length */
+ int n;
+ uch buf[EXTHDR]; /* extended local header */
+
+ ifd = in;
+ ofd = out;
+
+ updcrc(NULL, 0); /* initialize crc */
+
+ if (pkzip && !ext_header) { /* crc and length at the end otherwise */
+ orig_crc = LG(inbuf + LOCCRC);
+ orig_len = LG(inbuf + LOCLEN);
+ }
+
+ /* Decompress */
+ if (method == DEFLATED) {
+
+ int res = inflate();
+
+ if (res == 3) {
+ error("out of memory");
+ } else if (res != 0) {
+ error("invalid compressed data--format violated");
+ }
+
+ } else if (pkzip && method == STORED) {
+
+ register ulg n = LG(inbuf + LOCLEN);
+
+ if (n != LG(inbuf + LOCSIZ) - (decrypt ? RAND_HEAD_LEN : 0)) {
+
+ fprintf(stderr, "len %ld, siz %ld\n", n, LG(inbuf + LOCSIZ));
+ error("invalid compressed data--length mismatch");
+ }
+ while (n--) {
+ uch c = (uch)get_byte();
+#ifdef CRYPT
+ if (decrypt) zdecode(c);
+#endif
+ put_ubyte(c);
+ }
+ flush_window();
+ } else {
+ error("internal error, invalid method");
+ }
+
+ /* Get the crc and original length */
+ if (!pkzip) {
+ /* crc32 (see algorithm.doc)
+ * uncompressed input size modulo 2^32
+ */
+ for (n = 0; n < 8; n++) {
+ buf[n] = (uch)get_byte(); /* may cause an error if EOF */
+ }
+ orig_crc = LG(buf);
+ orig_len = LG(buf+4);
+
+ } else if (ext_header) { /* If extended header, check it */
+ /* signature - 4bytes: 0x50 0x4b 0x07 0x08
+ * CRC-32 value
+ * compressed size 4-bytes
+ * uncompressed size 4-bytes
+ */
+ for (n = 0; n < EXTHDR; n++) {
+ buf[n] = (uch)get_byte(); /* may cause an error if EOF */
+ }
+ orig_crc = LG(buf+4);
+ orig_len = LG(buf+12);
+ }
+
+ /* Validate decompression */
+ if (orig_crc != updcrc(outbuf, 0)) {
+ error("invalid compressed data--crc error");
+ }
+ if (orig_len != (ulg)bytes_out) {
+ error("invalid compressed data--length error");
+ }
+
+ /* Check if there are more entries in a pkzip file */
+ if (pkzip && inptr + 4 < insize && LG(inbuf+inptr) == LOCSIG) {
+ if (to_stdout) {
+ WARN((stderr,
+ "%s: %s has more than one entry--rest ignored\n",
+ progname, ifname));
+ } else {
+ /* Don't destroy the input zip file */
+ fprintf(stderr,
+ "%s: %s has more than one entry -- unchanged\n",
+ progname, ifname);
+ exit_code = ERROR;
+ ext_header = pkzip = 0;
+ return ERROR;
+ }
+ }
+ ext_header = pkzip = 0; /* for next file */
+ return OK;
+}
diff --git a/libstore/util.c b/libstore/util.c
new file mode 100644
index 0000000..598586f
--- /dev/null
+++ b/libstore/util.c
@@ -0,0 +1,272 @@
+/* Hacked and slashed by address@hidden for use in Hurd exec server. */
+
+/* util.c -- utility functions for gzip support
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+#ifdef RCSID
+static char rcsid[] = "$Id: util.c,v 1.1 1994/12/14 04:29:37 roland Exp $";
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include "tailor.h"
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#ifndef NO_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#if defined(STDC_HEADERS) || !defined(NO_STDLIB_H)
+# include <stdlib.h>
+#else
+ extern int errno;
+#endif
+
+#include "gzip.h"
+#include "crypt.h"
+
+/* cruft */
+int ifd, ofd;
+int to_stdout=1,quiet=1;
+
+/* I/O interface */
+int (*unzip_read) (char *buf, size_t maxread);
+void (*unzip_write) (const char *buf, size_t nwrite);
+#define read_error() (*unzip_read_error) ()
+void (*unzip_read_error) (void);
+
+
+extern ulg crc_32_tab[]; /* crc table, defined below */
+
+int exit_code = OK; /* program exit code */
+int method = DEFLATED;/* compression method */
+unsigned insize; /* valid bytes in inbuf */
+unsigned inptr; /* index of next byte to be processed in inbuf */
+unsigned outcnt; /* bytes in output buffer */
+DECLARE(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
+DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
+DECLARE(uch, window, 2L*WSIZE);
+
+
+/* This function stolen from gzip.c. */
+/* ========================================================================
+ * Check the magic number of the input file and update ofname if an
+ * original name was given and to_stdout is not set.
+ * Return the compression method, -1 for error, -2 for warning.
+ * Set inptr to the offset of the next byte to be processed.
+ * Updates time_stamp if there is one and --no-time is not used.
+ * This function may be called repeatedly for an input file consisting
+ * of several contiguous gzip'ed members.
+ * IN assertions: there is at least one remaining compressed member.
+ * If the member is a zip file, it must be the only one.
+ */
+int get_method(in)
+ int in; /* input file descriptor */
+{
+ uch flags; /* compression flags */
+ char magic[2]; /* magic header */
+ ulg stamp; /* time stamp */
+
+ /* Prime the input buffer. */
+ fill_inbuf(0);
+ inptr = 0;
+
+ magic[0] = (char)get_byte();
+ magic[1] = (char)get_byte();
+
+ method = -1; /* unknown yet */
+
+ if (memcmp(magic, GZIP_MAGIC, 2) == 0
+ || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
+
+ method = (int)get_byte();
+ if (method != DEFLATED)
+ return -1;
+
+ flags = (uch)get_byte();
+ if ((flags & ENCRYPTED) != 0) return -1;
+ if ((flags & CONTINUATION) != 0) return -1;
+ if ((flags & RESERVED) != 0) return -1;
+
+ stamp = (ulg)get_byte();
+ stamp |= ((ulg)get_byte()) << 8;
+ stamp |= ((ulg)get_byte()) << 16;
+ stamp |= ((ulg)get_byte()) << 24;
+
+ (void)get_byte(); /* Ignore extra flags for the moment */
+ (void)get_byte(); /* Ignore OS type for the moment */
+
+ if ((flags & CONTINUATION) != 0) {
+ unsigned part = (unsigned)get_byte();
+ part |= ((unsigned)get_byte())<<8;
+ }
+ if ((flags & EXTRA_FIELD) != 0) {
+ unsigned len = (unsigned)get_byte();
+ len |= ((unsigned)get_byte())<<8;
+ while (len--) (void)get_byte();
+ }
+
+ /* Get original file name if it was truncated */
+ if ((flags & ORIG_NAME) != 0) {
+ /* Discard the old name */
+ char c; /* dummy used for NeXTstep 3.0 cc optimizer bug */
+ do {c=get_byte();} while (c != 0);
+ }
+
+ /* Discard file comment if any */
+ if ((flags & COMMENT) != 0) {
+ while (get_char() != 0) /* null */ ;
+ }
+ } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
+ && memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0) {
+ /* To simplify the code, we support a zip file when alone only.
+ * We are thus guaranteed that the entire local header fits in inbuf.
+ */
+ inptr = 0;
+ if (check_zipfile(in) == OK) return 0;
+ }
+
+ return method != DEFLATED;
+}
+
+
+/* ===========================================================================
+ * Run a set of bytes through the crc shift register. If s is a NULL
+ * pointer, then initialize the crc shift register contents instead.
+ * Return the current crc in either case.
+ */
+ulg updcrc(s, n)
+ uch *s; /* pointer to bytes to pump through */
+ unsigned n; /* number of bytes in s[] */
+{
+ register ulg c; /* temporary variable */
+
+ static ulg crc = (ulg)0xffffffffL; /* shift register contents */
+
+ if (s == NULL) {
+ c = 0xffffffffL;
+ } else {
+ c = crc;
+ if (n) do {
+ c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
+ } while (--n);
+ }
+ crc = c;
+ return c ^ 0xffffffffL; /* (instead of ~c for 64-bit machines) */
+}
+
+/* ===========================================================================
+ * Clear input and output buffers
+ */
+void clear_bufs()
+{
+ outcnt = 0;
+ insize = inptr = 0;
+}
+
+/* ===========================================================================
+ * Fill the input buffer. This is called only when the buffer is empty.
+ */
+int fill_inbuf(eof_ok)
+ int eof_ok; /* set if EOF acceptable as a result */
+{
+ int len;
+
+ /* Read as much as possible */
+ insize = 0;
+ do {
+ len = (*unzip_read)((char*)inbuf+insize, INBUFSIZ-insize);
+ if (len == 0 || len == EOF) break;
+ insize += len;
+ } while (insize < INBUFSIZ);
+
+ if (insize == 0) {
+ if (eof_ok) return EOF;
+ read_error();
+ }
+
+ inptr = 1;
+ return inbuf[0];
+}
+
+long int bytes_out;
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+void flush_window()
+{
+ if (outcnt == 0) return;
+ updcrc(window, outcnt);
+
+ (*unzip_write) ((char *) window, outcnt);
+ bytes_out += outcnt;
+
+ outcnt = 0;
+}
+
+/* ========================================================================
+ * Table of CRC-32's of all single-byte values (made by makecrc.c)
+ */
+ulg crc_32_tab[] = {
+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL
+};
diff --git a/libtrivfs/Makefile b/libtrivfs/Makefile
index 1c6fd5e..241b76d 100644
--- a/libtrivfs/Makefile
+++ b/libtrivfs/Makefile
@@ -25,7 +25,7 @@ FSSRCS= dir-link.c dir-mkdir.c dir-mkfile.c dir-lookup.c
dir-readdir.c \
file-getlinknode.c file-lock.c file-set-trans.c file-statfs.c \
file-sync.c file-syncfs.c file-set-size.c file-utimes.c file-exec.c \
file-access.c dir-chg.c file-chg.c file-get-storage-info.c \
- file-get-fs-options.c file-reparent.c
+ file-get-fs-options.c file-reparent.c get-source.c
IOSRCS=io-async-icky.c io-async.c io-duplicate.c io-map.c io-modes-get.c \
io-modes-off.c io-modes-on.c io-modes-set.c io-owner-get.c \
@@ -34,7 +34,8 @@ IOSRCS=io-async-icky.c io-async.c io-duplicate.c io-map.c
io-modes-get.c \
io-stat.c io-stubs.c io-write.c io-version.c io-identity.c
FSYSSRCS=fsys-getroot.c fsys-goaway.c fsys-stubs.c fsys-syncfs.c \
- fsys-forward.c fsys-set-options.c fsys-get-options.c
+ fsys-forward.c fsys-set-options.c fsys-get-options.c \
+ fsys-get-children.c fsys-get-source.c
OTHERSRCS=demuxer.c protid-clean.c protid-dup.c cntl-create.c \
cntl-clean.c migsupport.c times.c startup.c open.c \
diff --git a/libtrivfs/fsys-get-children.c b/libtrivfs/fsys-get-children.c
new file mode 100644
index 0000000..4697cc5
--- /dev/null
+++ b/libtrivfs/fsys-get-children.c
@@ -0,0 +1,35 @@
+/* fsys_get_children
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ Written by Justus Winter <address@hidden>
+
+ 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "priv.h"
+
+/* Return any active translators bound to nodes of the receiving
+ filesystem. CHILDREN is an argz vector containing file names
+ relative to the root of the receiving translator. */
+error_t
+trivfs_S_fsys_get_children (trivfs_control_t server,
+ mach_port_t reply,
+ mach_msg_type_name_t replyPoly,
+ char **children,
+ mach_msg_type_number_t *children_len)
+{
+ return EOPNOTSUPP;
+}
diff --git a/libtrivfs/fsys-get-source.c b/libtrivfs/fsys-get-source.c
new file mode 100644
index 0000000..64aec2f
--- /dev/null
+++ b/libtrivfs/fsys-get-source.c
@@ -0,0 +1,33 @@
+/* fsys_get_source
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ Written by Justus Winter <address@hidden>
+
+ 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "priv.h"
+
+/* Return information about the source of the receiving
+ filesystem. */
+error_t
+trivfs_S_fsys_get_source (trivfs_control_t server,
+ mach_port_t reply,
+ mach_msg_type_name_t replyPoly,
+ char *source)
+{
+ return trivfs_get_source (source);
+}
diff --git a/libtrivfs/get-source.c b/libtrivfs/get-source.c
new file mode 100644
index 0000000..9ea5693
--- /dev/null
+++ b/libtrivfs/get-source.c
@@ -0,0 +1,28 @@
+/* Default version of trivfs_get_source
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ Written by Justus Winter <address@hidden>
+
+ 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "priv.h"
+
+error_t
+trivfs_get_source (char *source)
+{
+ return EOPNOTSUPP;
+}
diff --git a/libtrivfs/startup.c b/libtrivfs/startup.c
index 86b0f82..4d76d47 100644
--- a/libtrivfs/startup.c
+++ b/libtrivfs/startup.c
@@ -65,5 +65,24 @@ trivfs_startup(mach_port_t bootstrap, int flags,
if (!err && control)
*control = fsys;
+ /* Mark us as important. */
+ if (! err)
+ {
+ mach_port_t proc = getproc ();
+ if (proc == MACH_PORT_NULL)
+ /* /hurd/exec uses libtrivfs. We have no handle to the proc
+ server in /hurd/exec when it does its handshake with the
+ root filesystem, so fail graciously here. */
+ return 0;
+
+ err = proc_mark_important (proc);
+ /* This might fail due to permissions or because the old proc
+ server is still running, ignore any such errors. */
+ if (err == EPERM || err == EMIG_BAD_ID)
+ err = 0;
+
+ mach_port_deallocate (mach_task_self (), proc);
+ }
+
return err;
}
diff --git a/libtrivfs/trivfs.h b/libtrivfs/trivfs.h
index 33b0436..cf817b5 100644
--- a/libtrivfs/trivfs.h
+++ b/libtrivfs/trivfs.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994,95,96,97,99,2002 Free Software Foundation, Inc.
+ Copyright (C) 1994,95,96,97,99,2002,13 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
@@ -233,6 +233,12 @@ error_t trivfs_set_options (struct trivfs_control *fsys,
routine simply calls diskfs_append_std_options. */
error_t trivfs_append_args (struct trivfs_control *fsys,
char **argz, size_t *argz_len);
+
+/* The user may define this function. The function must set source to
+ the source device of the filesystem. The function may return an
+ EOPNOTSUPP to indicate that the concept of a source device is not
+ applicable. The default function always returns EOPNOTSUPP. */
+error_t trivfs_get_source (char *source);
/* Add the port class *CLASS to the list of control port classes recognized
by trivfs; if *CLASS is 0, an attempt is made to allocate a new port
diff --git a/mach-defpager/main.c b/mach-defpager/main.c
index 3134d6f..fe6f735 100644
--- a/mach-defpager/main.c
+++ b/mach-defpager/main.c
@@ -125,6 +125,19 @@ main (int argc, char **argv)
}
}
+ /* Mark us as important. */
+ mach_port_t proc = getproc ();
+ if (proc == MACH_PORT_NULL)
+ error (3, err, "cannot get a handle to our process");
+
+ err = proc_mark_important (proc);
+ /* This might fail due to permissions or because the old proc server
+ is still running, ignore any such errors. */
+ if (err && err != EPERM && err != EMIG_BAD_ID)
+ error (3, err, "cannot mark us as important");
+
+ mach_port_deallocate (mach_task_self (), proc);
+
printf_init(bootstrap_master_device_port);
/*
diff --git a/pfinet/main.c b/pfinet/main.c
index 01b324d..c952719 100644
--- a/pfinet/main.c
+++ b/pfinet/main.c
@@ -28,6 +28,7 @@
#include <string.h>
#include <fcntl.h>
#include <version.h>
+#include <pids.h>
/* Include Hurd's errno.h file, but don't include glue-include/hurd/errno.h,
since it #undef's the errno macro. */
@@ -153,7 +154,7 @@ arrange_shutdown_notification ()
if (!procserver)
return;
- err = proc_getmsgport (procserver, 1, &initport);
+ err = proc_getmsgport (procserver, HURD_PID_STARTUP, &initport);
mach_port_deallocate (mach_task_self (), procserver);
if (err)
return;
diff --git a/pfinet/tunnel.c b/pfinet/tunnel.c
index 4a6f616..495356c 100644
--- a/pfinet/tunnel.c
+++ b/pfinet/tunnel.c
@@ -479,14 +479,23 @@ io_select_common (struct trivfs_protid *cred,
tdev = (struct tunnel_device *) cred->po->cntl->hook;
- /* We only deal with SELECT_READ here. */
- *type &= SELECT_READ;
+ /* We only deal with SELECT_READ and SELECT_WRITE here. */
+ *type &= SELECT_READ | SELECT_WRITE;
if (*type == 0)
return 0;
pthread_mutex_lock (&tdev->lock);
+ if (*type & SELECT_WRITE)
+ {
+ /* We are always writable. */
+ if (skb_queue_len (&tdev->xq) == 0)
+ *type &= ~SELECT_READ;
+ pthread_mutex_unlock (&tdev->lock);
+ return 0;
+ }
+
while (1)
{
if (skb_queue_len (&tdev->xq) != 0)
diff --git a/proc/info.c b/proc/info.c
index 40f9d21..0d502c6 100644
--- a/proc/info.c
+++ b/proc/info.c
@@ -37,7 +37,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA
02139, USA. */
/* Returns true if PROC1 has `owner' privileges over PROC2 (and can thus get
its task port &c). If PROC2 has an owner, then PROC1 must have that uid;
otherwise, both must be in the same login collection. */
-static inline int
+int
check_owner (struct proc *proc1, struct proc *proc2)
{
return
diff --git a/proc/main.c b/proc/main.c
index 494169e..73abbc0 100644
--- a/proc/main.c
+++ b/proc/main.c
@@ -28,6 +28,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA
02139, USA. */
#include <argp.h>
#include <error.h>
#include <version.h>
+#include <pids.h>
#include "proc.h"
@@ -87,7 +88,7 @@ main (int argc, char **argv, char **envp)
self_proc = allocate_proc (mach_task_self ());
assert (self_proc);
- complete_proc (self_proc, 0);
+ complete_proc (self_proc, HURD_PID_PROC);
startup_port = ports_get_send_right (startup_proc);
err = startup_procinit (boot, startup_port, &startup_proc->p_task,
diff --git a/proc/mgt.c b/proc/mgt.c
index 7af9c1a..c093b8f 100644
--- a/proc/mgt.c
+++ b/proc/mgt.c
@@ -32,6 +32,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA
02139, USA. */
#include <sys/resource.h>
#include <hurd/auth.h>
#include <assert.h>
+#include <pids.h>
#include "proc.h"
#include "process_S.h"
@@ -209,6 +210,15 @@ S_proc_child (struct proc *parentp,
childp->p_parent->p_pid, childp->p_pgrp->pg_pgid,
!childp->p_pgrp->pg_orphcnt);
childp->p_parentset = 1;
+
+ /* If these are not set in the child, it was probably fork(2)ed. If
+ so, it inherits the values of its parent. */
+ if (! childp->start_code && ! childp->end_code)
+ {
+ childp->start_code = parentp->start_code;
+ childp->end_code = parentp->end_code;
+ }
+
return 0;
}
@@ -582,7 +592,7 @@ create_startup_proc (void)
p = allocate_proc (MACH_PORT_NULL);
assert (p);
- p->p_pid = 1;
+ p->p_pid = HURD_PID_STARTUP;
p->p_parent = p;
p->p_sib = 0;
@@ -592,6 +602,8 @@ create_startup_proc (void)
p->p_deadmsg = 1; /* Force initial "re-"fetch of msgport. */
+ p->p_important = 1;
+
p->p_noowner = 0;
p->p_id = make_ids (&zero, 1);
assert (p->p_id);
@@ -867,3 +879,66 @@ genpid ()
return nextpid++;
}
+
+/* Implement proc_mark_important as described in <hurd/process.defs>. */
+kern_return_t
+S_proc_mark_important (struct proc *p)
+{
+ if (!p)
+ return EOPNOTSUPP;
+
+ /* Only root may use this interface. Any children of startup_proc
+ exempt from this restriction, as startup_proc calls this on their
+ behalf. The kernel process is a notable example of an process
+ that needs this exemption. That is not an problem however, since
+ all children of /hurd/init are important and we mark them as such
+ anyway. */
+ if (! check_uid (p, 0) && ! check_owner (startup_proc, p))
+ return EPERM;
+
+ p->p_important = 1;
+ return 0;
+}
+
+/* Implement proc_is_important as described in <hurd/process.defs>. */
+error_t
+S_proc_is_important (struct proc *callerp,
+ boolean_t *essential)
+{
+ if (!callerp)
+ return EOPNOTSUPP;
+
+ *essential = callerp->p_important;
+
+ return 0;
+}
+
+/* Implement proc_set_code as described in <hurd/process.defs>. */
+error_t
+S_proc_set_code (struct proc *callerp,
+ vm_address_t start_code,
+ vm_address_t end_code)
+{
+ if (!callerp)
+ return EOPNOTSUPP;
+
+ callerp->start_code = start_code;
+ callerp->end_code = end_code;
+
+ return 0;
+}
+
+/* Implement proc_get_code as described in <hurd/process.defs>. */
+error_t
+S_proc_get_code (struct proc *callerp,
+ vm_address_t *start_code,
+ vm_address_t *end_code)
+{
+ if (!callerp)
+ return EOPNOTSUPP;
+
+ *start_code = callerp->start_code;
+ *end_code = callerp->end_code;
+
+ return 0;
+}
diff --git a/proc/pgrp.c b/proc/pgrp.c
index 2d6ca93..d4ea9ee 100644
--- a/proc/pgrp.c
+++ b/proc/pgrp.c
@@ -1,5 +1,5 @@
/* Session and process group manipulation
- Copyright (C) 1992,93,94,95,96,99,2001,02 Free Software Foundation, Inc.
+ Copyright (C) 1992,93,94,95,96,99,2001,02,13 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -265,7 +265,7 @@ S_proc_getpgrppids (struct proc *callerp,
count = 0;
for (p = pg->pg_plist; p; p = p->p_gnext)
- if (++count <= npids)
+ if (!p->p_important && ++count <= npids)
*pp++ = p->p_pid;
if (count > npids)
@@ -278,7 +278,8 @@ S_proc_getpgrppids (struct proc *callerp,
pp = *pids;
for (p = pg->pg_plist; p; p = p->p_gnext)
- *pp++ = p->p_pid;
+ if (!p->p_important)
+ *pp++ = p->p_pid;
/* Dealloc ? XXX */
}
*npidsp = count;
diff --git a/proc/proc.h b/proc/proc.h
index 247795d..80f8397 100644
--- a/proc/proc.h
+++ b/proc/proc.h
@@ -64,6 +64,8 @@ struct proc
/* Miscellaneous information */
vm_address_t p_argv, p_envp;
+ vm_address_t start_code; /* all executable segments are in this range */
+ vm_address_t end_code;
int p_status; /* to return via wait */
int p_sigcode;
struct rusage p_rusage; /* my usage if I'm dead, to return via wait */
@@ -84,6 +86,7 @@ struct proc
unsigned int p_noowner:1; /* has no owner known */
unsigned int p_loginleader:1; /* leader of login collection */
unsigned int p_dead:1; /* process is dead */
+ unsigned int p_important:1; /* has called proc_mark_important */
};
typedef struct proc *pstruct_t;
@@ -129,8 +132,6 @@ struct exc
natural_t thread_state[0];
};
-struct zombie *zombie_list;
-
mach_port_t authserver;
struct proc *self_proc; /* process 0 (us) */
struct proc *startup_proc; /* process 1 (init) */
@@ -157,6 +158,7 @@ process_drop (struct proc *p)
/* Forward declarations */
void complete_wait (struct proc *, int);
int check_uid (struct proc *, uid_t);
+int check_owner (struct proc *, struct proc *);
void addalltasks (void);
void prociterate (void (*)(struct proc *, void *), void *);
void count_up (void *);
diff --git a/procfs/ChangeLog b/procfs/ChangeLog
new file mode 100644
index 0000000..0cd74d0
--- /dev/null
+++ b/procfs/ChangeLog
@@ -0,0 +1,6 @@
+edb4593c38d421b5d538b221a991b50c36fdba15 is the last commit imported from CVS.
+All commits after that one have valid author and committer information.
+
+Use this to examine the change log for earlier changes:
+
+ $ git show edb4593c38d421b5d538b221a991b50c36fdba15:ChangeLog
diff --git a/procfs/main.c b/procfs/main.c
index 90b3e92..54e9682 100644
--- a/procfs/main.c
+++ b/procfs/main.c
@@ -22,6 +22,7 @@
#include <unistd.h>
#include <error.h>
#include <argp.h>
+#include <argz.h>
#include <hurd/netfs.h>
#include <ps.h>
#include "procfs.h"
@@ -37,6 +38,13 @@ pid_t opt_fake_self;
pid_t opt_kernel_pid;
uid_t opt_anon_owner;
+/* Default values */
+#define OPT_CLK_TCK sysconf(_SC_CLK_TCK)
+#define OPT_STAT_MODE 0400
+#define OPT_FAKE_SELF -1
+#define OPT_KERNEL_PID 2
+#define OPT_ANON_OWNER 0
+
#define NODEV_KEY -1 /* <= 0, so no short option. */
#define NOEXEC_KEY -2 /* Likewise. */
#define NOSUID_KEY -3 /* Likewise. */
@@ -120,50 +128,90 @@ argp_parser (int key, char *arg, struct argp_state *state)
case NOSUID_KEY:
/* Ignored for compatibility with Linux' procfs. */
;;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
}
return 0;
}
+struct argp_option common_options[] = {
+ { "clk-tck", 'h', "HZ", 0,
+ "Unit used for the values expressed in system clock ticks "
+ "(default: sysconf(_SC_CLK_TCK))" },
+ { "stat-mode", 's', "MODE", 0,
+ "The [pid]/stat file publishes information which on Hurd is only "
+ "available to the process owner. "
+ "You can use this option to override its mode to be more permissive "
+ "for compatibility purposes. "
+ "(default: 0400)" },
+ { "fake-self", 'S', "PID", OPTION_ARG_OPTIONAL,
+ "Provide a fake \"self\" symlink to the given PID, for compatibility "
+ "purposes. If PID is omitted, \"self\" will point to init. "
+ "(default: no self link)" },
+ { "kernel-process", 'k', "PID", 0,
+ "Process identifier for the kernel, used to retreive its command "
+ "line, as well as the global up and idle times. "
+ "(default: 2)" },
+ { "compatible", 'c', NULL, 0,
+ "Try to be compatible with the Linux procps utilities. "
+ "Currently equivalent to -h 100 -s 0444 -S 1." },
+ { "anonymous-owner", 'a', "USER", 0,
+ "Make USER the owner of files related to processes without one. "
+ "Be aware that USER will be granted access to the environment and "
+ "other sensitive information about the processes in question. "
+ "(default: use uid 0)" },
+ { "nodev", NODEV_KEY, NULL, 0,
+ "Ignored for compatibility with Linux' procfs." },
+ { "noexec", NOEXEC_KEY, NULL, 0,
+ "Ignored for compatibility with Linux' procfs." },
+ { "nosuid", NOSUID_KEY, NULL, 0,
+ "Ignored for compatibility with Linux' procfs." },
+ {}
+};
+
struct argp argp = {
- .options = (struct argp_option []) {
- { "clk-tck", 'h', "HZ", 0,
- "Unit used for the values expressed in system clock ticks "
- "(default: sysconf(_SC_CLK_TCK))" },
- { "stat-mode", 's', "MODE", 0,
- "The [pid]/stat file publishes information which on Hurd is only "
- "available to the process owner. "
- "You can use this option to override its mode to be more permissive "
- "for compatibility purposes. "
- "(default: 0400)" },
- { "fake-self", 'S', "PID", OPTION_ARG_OPTIONAL,
- "Provide a fake \"self\" symlink to the given PID, for compatibility "
- "purposes. If PID is omitted, \"self\" will point to init. "
- "(default: no self link)" },
- { "kernel-process", 'k', "PID", 0,
- "Process identifier for the kernel, used to retreive its command "
- "line, as well as the global up and idle times. "
- "(default: 2)" },
- { "compatible", 'c', NULL, 0,
- "Try to be compatible with the Linux procps utilities. "
- "Currently equivalent to -h 100 -s 0444 -S 1." },
- { "anonymous-owner", 'a', "USER", 0,
- "Make USER the owner of files related to processes without one. "
- "Be aware that USER will be granted access to the environment and "
- "other sensitive information about the processes in question. "
- "(default: use uid 0)" },
- { "nodev", NODEV_KEY, NULL, 0,
- "Ignored for compatibility with Linux' procfs." },
- { "noexec", NOEXEC_KEY, NULL, 0,
- "Ignored for compatibility with Linux' procfs." },
- { "nosuid", NOSUID_KEY, NULL, 0,
- "Ignored for compatibility with Linux' procfs." },
+ .options = common_options,
+ .parser = argp_parser,
+ .doc = "A virtual filesystem emulating the Linux procfs.",
+ .children = (struct argp_child []) {
+ { &netfs_std_startup_argp, },
{}
},
+};
+
+static error_t
+runtime_argp_parser (int key, char *arg, struct argp_state *state)
+{
+ switch (key)
+ {
+ case 'u':
+ /* do nothing */
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ return 0;
+}
+
+struct argp runtime_argp = {
+ .options = (struct argp_option []) {
+ { "update", 'u', NULL, 0, "remount; for procfs this does nothing" },
+ {},
+ },
+ .parser = runtime_argp_parser,
+};
+
+struct argp netfs_runtime_argp_ = {
+ .options = common_options,
.parser = argp_parser,
.doc = "A virtual filesystem emulating the Linux procfs.",
.children = (struct argp_child []) {
- { &netfs_std_startup_argp, },
+ { &runtime_argp, },
+ { &netfs_std_runtime_argp, },
{}
},
};
@@ -171,6 +219,47 @@ struct argp argp = {
/* Used by netfs_set_options to handle runtime option parsing. */
struct argp *netfs_runtime_argp = &argp;
+/* Return an argz string describing the current options. Fill *ARGZ
+ with a pointer to newly malloced storage holding the list and *LEN
+ to the length of that storage. */
+error_t
+netfs_append_args (char **argz, size_t *argz_len)
+{
+ char buf[80];
+ error_t err = 0;
+
+#define FOPT(opt, default, fmt, args...) \
+ do { \
+ if (! err && opt != default) \
+ { \
+ snprintf (buf, sizeof buf, fmt, ## args); \
+ err = argz_add (argz, argz_len, buf); \
+ } \
+ } while (0)
+
+ FOPT (opt_clk_tck, OPT_CLK_TCK,
+ "--clk-tck=%d", opt_clk_tck);
+
+ FOPT (opt_stat_mode, OPT_STAT_MODE,
+ "--stat-mode=%o", opt_stat_mode);
+
+ FOPT (opt_fake_self, OPT_FAKE_SELF,
+ "--fake-self=%d", opt_fake_self);
+
+ FOPT (opt_anon_owner, OPT_ANON_OWNER,
+ "--anonymous-owner=%d", opt_anon_owner);
+
+ FOPT (opt_kernel_pid, OPT_KERNEL_PID,
+ "--kernel-process=%d", opt_kernel_pid);
+
+#undef FOPT
+
+ if (! err)
+ err = netfs_append_std_options (argz, argz_len);
+
+ return err;
+}
+
error_t
root_make_node (struct ps_context *pc, struct node **np)
{
@@ -196,11 +285,11 @@ int main (int argc, char **argv)
mach_port_t bootstrap;
error_t err;
- opt_clk_tck = sysconf(_SC_CLK_TCK);
- opt_stat_mode = 0400;
- opt_fake_self = -1;
- opt_kernel_pid = 2;
- opt_anon_owner = 0;
+ opt_clk_tck = OPT_CLK_TCK;
+ opt_stat_mode = OPT_STAT_MODE;
+ opt_fake_self = OPT_FAKE_SELF;
+ opt_kernel_pid = OPT_KERNEL_PID;
+ opt_anon_owner = OPT_ANON_OWNER;
err = argp_parse (&argp, argc, argv, 0, 0, 0);
if (err)
error (1, err, "Could not parse command line");
diff --git a/procfs/process.c b/procfs/process.c
index c5ef7d8..269a18b 100644
--- a/procfs/process.c
+++ b/procfs/process.c
@@ -116,6 +116,26 @@ process_file_gc_stat (struct proc_stat *ps, char
**contents)
thread_basic_info_t thbi = proc_stat_thread_basic_info (ps);
const char *fn = args_filename (proc_stat_args (ps));
+ vm_address_t start_code = 1; /* 0 would make killall5.c consider it
+ a kernel process, thus use 1 as
+ default. */
+ vm_address_t end_code = 1;
+ process_t p;
+ error_t err = proc_pid2proc (ps->context->server, ps->pid, &p);
+ if (! err)
+ {
+ boolean_t essential = 0;
+ proc_is_important (p, &essential);
+ if (essential)
+ start_code = end_code = 0; /* To make killall5.c consider it a
+ kernel process that is to be
+ left alone. */
+ else
+ proc_get_code (p, &start_code, &end_code);
+
+ mach_port_deallocate (mach_task_self (), p);
+ }
+
/* See proc(5) for more information about the contents of each field for the
Linux procfs. */
return asprintf (contents,
@@ -152,7 +172,9 @@ process_file_gc_stat (struct proc_stat *ps, char **contents)
timeval_jiffies (thbi->creation_time), /* FIXME: ... since boot */
(long unsigned) tbi->virtual_size,
(long unsigned) tbi->resident_size / PAGE_SIZE, 0L,
- 0L, 0L, 0L, 0L, 0L,
+ start_code,
+ end_code,
+ 0L, 0L, 0L,
0L, 0L, 0L, 0L,
(long unsigned) proc_stat_thread_rpc (ps), /* close enough */
0L, 0L,
diff --git a/procfs/rootdir.c b/procfs/rootdir.c
index f234dd0..34bf91c 100644
--- a/procfs/rootdir.c
+++ b/procfs/rootdir.c
@@ -1,5 +1,5 @@
/* Hurd /proc filesystem, permanent files of the root directory.
- Copyright (C) 2010 Free Software Foundation, Inc.
+ Copyright (C) 2010,13 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -404,6 +404,31 @@ rootdir_gc_fakeself (void *hook, char **contents, ssize_t
*contents_len)
return 0;
}
+/* The mtab translator to use by default for the "mounts" node. */
+#define MTAB_TRANSLATOR "/hurd/mtab"
+
+static error_t
+rootdir_mounts_get_translator (void *hook, char **argz, size_t *argz_len)
+{
+ static const char const mtab_argz[] = MTAB_TRANSLATOR "\0/";
+
+ *argz = malloc (sizeof mtab_argz);
+ if (! *argz)
+ return ENOMEM;
+
+ memcpy (*argz, mtab_argz, sizeof mtab_argz);
+ *argz_len = sizeof mtab_argz;
+ return 0;
+}
+
+static int
+rootdir_mounts_exists (void *dir_hook, const void *entry_hook)
+{
+ static int translator_exists = -1;
+ if (translator_exists == -1)
+ translator_exists = access (MTAB_TRANSLATOR, F_OK|X_OK) == 0;
+ return translator_exists;
+}
/* Glue logic and entries table */
@@ -426,6 +451,18 @@ rootdir_symlink_make_node (void *dir_hook, const void
*entry_hook)
return np;
}
+static struct node *
+rootdir_translator_make_node (void *dir_hook, const void *entry_hook)
+{
+ struct node *np = procfs_make_node (entry_hook, dir_hook);
+ if (np)
+ {
+ procfs_node_chtype (np, S_IFREG | S_IPTRANS);
+ procfs_node_chmod (np, 0444);
+ }
+ return np;
+}
+
static const struct procfs_dir_entry rootdir_entries[] = {
{
.name = "self",
@@ -487,6 +524,16 @@ static const struct procfs_dir_entry rootdir_entries[] = {
.cleanup_contents = procfs_cleanup_contents_with_free,
},
},
+ {
+ .name = "mounts",
+ .hook = & (struct procfs_node_ops) {
+ .get_translator = rootdir_mounts_get_translator,
+ },
+ .ops = {
+ .make_node = rootdir_translator_make_node,
+ .exists = rootdir_mounts_exists,
+ }
+ },
#ifdef PROFILE
/* In order to get a usable gmon.out file, we must apparently use exit(). */
{
diff --git a/storeio/pager.c b/storeio/pager.c
index cbae7eb..7d78711 100644
--- a/storeio/pager.c
+++ b/storeio/pager.c
@@ -110,6 +110,13 @@ pager_unlock_page (struct user_pager_info *upi,
vm_offset_t address)
return 0;
}
+void
+pager_notify_evict (struct user_pager_info *pager,
+ vm_offset_t page)
+{
+ assert (!"unrequested notification on eviction");
+}
+
/* The user must define this function. It should report back (in
*OFFSET and *SIZE the minimum valid address the pager will accept
and the size of the object. */
@@ -246,7 +253,7 @@ dev_get_memory_object (struct dev *dev, vm_prot_t prot,
memory_object_t *memobj)
{
dev->pager =
pager_create ((struct user_pager_info *)dev, pager_port_bucket,
- 1, MEMORY_OBJECT_COPY_DELAY);
+ 1, MEMORY_OBJECT_COPY_DELAY, 0);
if (dev->pager == NULL)
{
pthread_mutex_unlock (&dev->pager_lock);
diff --git a/sutils/fstab.c b/sutils/fstab.c
index 1492ccd..ed59151 100644
--- a/sutils/fstab.c
+++ b/sutils/fstab.c
@@ -457,11 +457,19 @@ fs_remount (struct fs *fs)
return err;
}
-/* Returns the FS entry in FSTAB with the device field NAME (there can only
- be one such entry). */
+/* Returns the FS entry in FSTAB with the device field NAME.
+
+ In general there can only be one such entry. This holds not true
+ for virtual file systems that use "none" as device name.
+
+ If name is "none", NULL is returned. This also makes it possible to
+ add more than one entry for the device "none". */
inline struct fs *
fstab_find_device (const struct fstab *fstab, const char *name)
{
+ if (strcmp (name, "none") == 0)
+ return NULL;
+
struct fs *fs;
for (fs = fstab->entries; fs; fs = fs->next)
if (strcmp (fs->mntent.mnt_fsname, name) == 0)
@@ -880,90 +888,41 @@ fstab_argp_create (struct fstab_argp_params *params,
check = fstab;
else
{
- struct fs *fs;
- const char *tn;
- unsigned int nonexclude_types;
-
err = fstab_create (types, &check);
if (err)
error (105, err, "fstab_create");
- /* For each excluded type (i.e. `-t notype'), clobber the
- fstype entry's program with an empty string to mark it. */
- nonexclude_types = 0;
- for (tn = params->types; tn;
- tn = argz_next (params->types, params->types_len, tn))
- {
- if (!strncasecmp (tn, "no", 2))
- {
- struct fstype *type;
- err = fstypes_get (types, &tn[2], &type);
- if (err)
- error (106, err, "fstypes_get");
- free (type->program);
- type->program = strdup ("");
- }
- else
- ++nonexclude_types;
- }
-
- if (nonexclude_types != 0)
- {
- const char *tn;
- struct fstypes *wanttypes;
-
- /* We will copy the types we want to include into a fresh
- list in WANTTYPES. Since we specify no search formats,
- `fstypes_get' applied to WANTTYPES can only create
- elements with a null `program' field. */
- err = fstypes_create (0, 0, &wanttypes);
- if (err)
- error (102, err, "fstypes_create");
-
- for (tn = params->types; tn;
- tn = argz_next (params->types, params->types_len, tn))
- if (strncasecmp (tn, "no", 2))
- {
- struct fstype *type;
- err = fstypes_get (types, tn, &type);
- if (err)
- error (106, err, "fstypes_get");
- if (type->program == 0)
- error (0, 0,
- "requested filesystem type `%s' unknown", tn);
- else
- {
- struct fstype *newtype = malloc (sizeof *newtype);
- newtype->name = strdup (type->name);
- newtype->program = strdup (type->program);
- newtype->next = wanttypes->entries;
- wanttypes->entries = newtype;
- }
- }
-
- /* fstypes_free (types); */
- types = wanttypes;
- }
+ int blacklist = strncasecmp (params->types, "no", 2) == 0;
+ if (blacklist)
+ params->types += 2; /* Skip no. */
+ struct fs *fs;
for (fs = fstab->entries; fs; fs = fs->next)
{
- const char *ptn;
- struct fstype *type;
-
- err = fs_type (fs, &type);
- if (err || nonexclude_types)
- {
- err = fstypes_get (types, fs->mntent.mnt_type, &type);
- if (err)
- error (106, err, "fstypes_get");
- if (params->types != 0)
- continue;
- }
- if (nonexclude_types && type->program == 0)
- continue; /* Freshly created, was not in WANTTYPES. */
- if (type->program != 0 && type->program[0] == '\0')
- continue; /* This type is marked as excluded. */
+ if (strcmp (fs->mntent.mnt_type, MNTTYPE_SWAP) == 0)
+ continue; /* Ignore swap entries. */
+
+ const char *tn;
+ int matched = 0;
+ for (tn = params->types; tn;
+ tn = argz_next (params->types, params->types_len, tn))
+ {
+ const char *type = fs->mntent.mnt_type;
+ if (strcmp (type, tn) == 0
+ /* Skip no for compatibility. */
+ || ((strncasecmp (type, "no", 2) == 0)
+ && strcmp (type, tn) == 0))
+ {
+ matched = 1;
+ break;
+ }
+ }
+
+ if (matched == blacklist)
+ continue; /* Either matched and types is a blacklist
+ or not matched and types is a whitelist */
+ const char *ptn;
for (ptn = params->exclude; ptn;
ptn = argz_next (params->exclude, params->exclude_len, ptn))
if (fnmatch (ptn, fs->mntent.mnt_dir, 0) == 0)
diff --git a/tmpfs/pager-stubs.c b/tmpfs/pager-stubs.c
index 25d70fe..3cb264b 100644
--- a/tmpfs/pager-stubs.c
+++ b/tmpfs/pager-stubs.c
@@ -57,6 +57,14 @@ pager_unlock_page (struct user_pager_info *pager,
return EIEIO;
}
+void
+pager_notify_evict (struct user_pager_info *pager,
+ vm_offset_t page)
+{
+ abort();
+}
+
+
/* The user must define this function. It should report back (in
*OFFSET and *SIZE the minimum valid address the pager will accept
and the size of the object. */
diff --git a/tmpfs/tmpfs.c b/tmpfs/tmpfs.c
index 7da3dd5..1872a7d 100644
--- a/tmpfs/tmpfs.c
+++ b/tmpfs/tmpfs.c
@@ -29,6 +29,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA
02139, USA. */
#include <fcntl.h>
#include <hurd.h>
#include <hurd/paths.h>
+#include <nullauth.h>
char *diskfs_server_name = "tmpfs";
char *diskfs_server_version = HURD_VERSION;
@@ -437,6 +438,11 @@ main (int argc, char **argv)
/* We must keep the REALNODE send right to remain the active
translator for the underlying node. */
+ /* Drop all privileges. */
+ err = setnullauth();
+ if (err)
+ error (1, err, "Could not drop privileges");
+
pthread_mutex_unlock (&diskfs_root_node->lock);
/* and so we die, leaving others to do the real work. */
diff --git a/trans/Makefile b/trans/Makefile
index b3210b6..6eb51d0 100644
--- a/trans/Makefile
+++ b/trans/Makefile
@@ -20,14 +20,15 @@ dir := trans
makemode := servers
targets = symlink firmlink ifsock magic null fifo new-fifo fwd crash \
- password hello hello-mt streamio fakeroot proxy-defpager remap
+ password hello hello-mt streamio fakeroot proxy-defpager remap \
+ mtab
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
+ fakeroot.c proxy-defpager.c remap.c mtab.c
OBJS = $(SRCS:.c=.o) fsysServer.o ifsockServer.o passwordServer.o \
crashServer.o crash_replyUser.o msgServer.o \
default_pagerServer.o default_pagerUser.o \
- device_replyServer.o elfcore.o
+ device_replyServer.o elfcore.o fsysUser.o
HURDLIBS = ports netfs trivfs iohelp fshelp pipe ihash shouldbeinlibc
LDLIBS += -lpthread
password-LDLIBS = $(LIBCRYPT)
@@ -51,6 +52,7 @@ magic: ../libiohelp/libiohelp.a
hello: ../libtrivfs/libtrivfs.a ../libfshelp/libfshelp.a
../libports/libports.a ../libihash/libihash.a
fakeroot: ../libnetfs/libnetfs.a ../libfshelp/libfshelp.a
../libiohelp/libiohelp.a ../libports/libports.a ../libihash/libihash.a
remap: ../libtrivfs/libtrivfs.a ../libfshelp/libfshelp.a
../libports/libports.a ../libihash/libihash.a
+mtab: ../libtrivfs/libtrivfs.a ../libfshelp/libfshelp.a ../libports/libports.a
../libihash/libihash.a fsysUser.o
$(targets): ../libshouldbeinlibc/libshouldbeinlibc.a
$(targets): %: %.o
diff --git a/trans/mtab.c b/trans/mtab.c
new file mode 100644
index 0000000..2973a0b
--- /dev/null
+++ b/trans/mtab.c
@@ -0,0 +1,800 @@
+/* This is an mtab translator.
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ Written by Justus Winter <address@hidden>
+
+ 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 the GNU Hurd. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <argp.h>
+#include <argz.h>
+#include <error.h>
+#include <fcntl.h>
+#include <hurd.h>
+#include <hurd/trivfs.h>
+#include <inttypes.h>
+#include <mntent.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <version.h>
+
+#include "fsys_U.h"
+
+static char *path = NULL;
+static int insecure = 0;
+
+/* Our control port. */
+struct trivfs_control *control;
+
+/* These kind of objects are created and populated in the open_hook.
+ They keep track of the content and file position of the client. */
+struct mtab
+{
+ char *contents;
+ size_t contents_len;
+ off_t offs;
+};
+
+const char *argp_program_version = STANDARD_HURD_VERSION (mtab);
+
+static const struct argp_option options[] =
+{
+ {"insecure", 'I', 0, 0,
+ "Follow translators not bound to nodes owned by you or root"},
+ {}
+};
+
+/* Parse a command line option. */
+error_t parse_opt (int key, char *arg, struct argp_state *state)
+{
+ switch (key)
+ {
+ case 'I':
+ insecure = 1;
+ break;
+
+ case ARGP_KEY_ARG:
+ path = realpath (arg, NULL);
+ if (! path)
+ argp_error (state, "Error while canonicalizing path");
+ break;
+
+ case ARGP_KEY_NO_ARGS:
+ argp_usage (state);
+ return EINVAL;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static struct argp argp =
+ {
+ options,
+ parse_opt,
+ "TARGET\tFile name of a node with an active translator",
+ "A translator providing mtab compatible information about active "
+ "and passive translators below TARGET.",
+ };
+
+/* This will be called from libtrivfs to help construct the answer
+ to an fsys_get_options RPC. */
+error_t
+trivfs_append_args (struct trivfs_control *fsys,
+ char **argz, size_t *argz_len)
+{
+ error_t err;
+
+ if (insecure)
+ {
+ err = argz_add (argz, argz_len, path);
+ if (err)
+ return err;
+ }
+
+ err = argz_add (argz, argz_len, path);
+ return err;
+}
+
+/* Setting this variable makes libtrivfs use our argp to
+ parse options passed in an fsys_set_options RPC. */
+struct argp *trivfs_runtime_argp = &argp;
+
+/* Authentication of the current process. */
+uid_t *uids;
+gid_t *gids;
+size_t uids_len, gids_len;
+
+/* Initialize and populate the uids and gids vectors. */
+error_t
+get_credentials (void)
+{
+ /* Fetch uids... */
+ uids_len = geteuids (0, 0);
+ if (uids_len < 0)
+ return errno;
+
+ uids = malloc (uids_len * sizeof (uid_t));
+ if (! uids)
+ return ENOMEM;
+
+ uids_len = geteuids (uids_len, uids);
+ if (uids_len < 0)
+ return errno;
+
+ /* ... and gids. */
+ gids_len = getgroups (0, 0);
+ if (gids_len < 0)
+ return errno;
+
+ gids = malloc (gids_len * sizeof (gid_t));
+ if (! uids)
+ return ENOMEM;
+
+ gids_len = getgroups (gids_len, gids);
+ if (gids_len < 0)
+ return errno;
+
+ return 0;
+}
+
+/* Check if the given struct stat describes a node owned by the
+ current user. */
+int
+is_owner (io_statbuf_t *st)
+{
+ int found = 0;
+ for (size_t i = 0; i < uids_len; i++)
+ if (uids[i] == st->st_uid)
+ {
+ found = 1;
+ break;
+ }
+
+ if (! found)
+ return 0;
+
+ found = 0;
+ for (size_t i = 0; i < gids_len; i++)
+ if (gids[i] == st->st_gid)
+ {
+ found = 1;
+ break;
+ }
+
+ return found;
+}
+
+error_t
+mtab_populate (struct mtab *mtab, const char *path, int insecure);
+
+error_t
+argz_add_device (char **options, size_t *options_len, const char *device);
+
+error_t
+map_device_to_path (const char *device, char **path);
+
+int
+main (int argc, char *argv[])
+{
+ error_t err;
+
+ err = argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, 0);
+ if (err)
+ error (1, err, "argument parsing");
+
+ err = get_credentials ();
+ if (err)
+ error (2, err, "getting credentials");
+
+ mach_port_t bootstrap;
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap != MACH_PORT_NULL)
+ {
+ /* Started as a translator. */
+
+ auth_t nullauth;
+ err = auth_makeauth (getauth (),
+ NULL, MACH_MSG_TYPE_COPY_SEND, 0,
+ NULL, 0,
+ NULL, 0,
+ NULL, 0,
+ NULL, 0,
+ &nullauth);
+ if (err)
+ error (3, err, "dropping credentials");
+
+ err = setauth (nullauth);
+ if (err)
+ error (3, err, "dropping credentials");
+
+ /* Reply to our parent. */
+ err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &control);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ if (err)
+ error (4, err, "trivfs_startup");
+
+ /* Launch. */
+ ports_manage_port_operations_one_thread (control->pi.bucket,
+ trivfs_demuxer,
+ 0);
+ }
+ else
+ {
+ /* One-shot mode. */
+ struct mtab mtab = { NULL, 0, 0 };
+ err = mtab_populate (&mtab, path, insecure);
+ if (err)
+ error (5, err, "%s", path);
+
+ if (mtab.contents)
+ printf ("%s", mtab.contents);
+ }
+
+ return 0;
+}
+
+error_t
+mtab_add_entry (struct mtab *mtab, const char *entry, size_t length)
+{
+ char *p = realloc (mtab->contents, mtab->contents_len + length + 1);
+ if (! p)
+ return ENOMEM;
+
+ memcpy (&p[mtab->contents_len], entry, length);
+
+ mtab->contents = p;
+ mtab->contents_len += length;
+
+ /* Zero-terminate contents so that we can also interpret it as
+ string. */
+ mtab->contents[mtab->contents_len] = '\0';
+
+ return 0;
+}
+
+/* Populates the given MTAB object with the information for PATH. If
+ INSECURE is given, also follow translators bound to nodes not owned
+ by root or the current user. */
+/* XXX split up */
+error_t
+mtab_populate (struct mtab *mtab, const char *path, int insecure)
+{
+ error_t err = 0;
+
+ /* These resources are freed in the epilogue. */
+ file_t node = MACH_PORT_NULL;
+ fsys_t fsys = MACH_PORT_NULL;
+ char *argz = NULL;
+ size_t argz_len = 0;
+ char **argv = NULL;
+ char *type = NULL;
+ char *options = NULL;
+ size_t options_len = 0;
+ char *src = NULL;
+ char *entry = NULL;
+ size_t entry_len = 0;
+ char *children = NULL;
+ size_t children_len = 0;
+
+ /* Get the underlying node. */
+ node = file_name_lookup (path, O_NOTRANS, 0666);
+ if (node == MACH_PORT_NULL)
+ {
+ err = errno;
+ goto errout;
+ }
+
+ if (! insecure)
+ {
+ /* Check who owns the node the translator is bound to. */
+ io_statbuf_t st;
+ err = io_stat (node, &st);
+ if (err)
+ goto errout;
+
+ if (st.st_uid != 0 && st.st_gid != 0 && ! is_owner (&st))
+ {
+ err = EPERM;
+ goto errout;
+ }
+ }
+
+ err = file_get_translator_cntl (node, &fsys);
+ if (err == EPERM)
+ /* If we do not have permission to do that, it cannot be a node
+ bound to our control port, so ignore this error. */
+ err = 0;
+
+ if (err == ENXIO && strcmp (path, "/") == 0)
+ /* The root translator fails differently, but this can't be bound
+ to our control port either, so ignore this error. */
+ err = 0;
+
+ if (err)
+ return err;
+
+ if (control && control->pi.port_right == fsys)
+ /* This node is bound to our control port, ignore it. */
+ goto errout;
+
+ /* Re-do the lookup without O_NOTRANS to get the root node. */
+ mach_port_deallocate (mach_task_self (), node);
+ node = file_name_lookup (path, 0, 0666);
+ if (node == MACH_PORT_NULL)
+ {
+ err = errno;
+ goto errout;
+ }
+
+ /* Query its options. */
+ err = file_get_fs_options (node, &argz, &argz_len);
+ if (err)
+ {
+ if (err == EOPNOTSUPP)
+ err = 0; /* There's not much we could do then. */
+
+ goto errout;
+ }
+
+ size_t count = argz_count (argz, argz_len);
+ argv = malloc ((count + 1) * sizeof (char *));
+ if (! argv)
+ {
+ err = ENOMEM;
+ goto errout;
+ }
+
+ argz_extract (argz, argz_len, argv);
+
+ type = strdup (argv[0]);
+ if (! type)
+ {
+ err = ENOMEM;
+ goto errout;
+ }
+
+ for (int i = 1; i < count - 1; i++)
+ {
+ char *v = argv[i];
+
+ if (*v == '-')
+ v++;
+ if (*v == '-')
+ v++;
+
+ err = argz_add (&options, &options_len, v);
+ if (err)
+ goto errout;
+ }
+
+ err = argz_add_device (&options, &options_len, argv[count - 1]);
+ if (err)
+ goto errout;
+
+ argz_stringify (options, options_len, ',');
+
+ string_t source;
+ err = fsys_get_source (node, source);
+ if (err)
+ {
+ if (err == EOPNOTSUPP)
+ {
+ /* Guess based on the last argument. */
+ err = map_device_to_path (argv[count - 1], &src);
+ if (err)
+ goto errout;
+ }
+ else
+ goto errout;
+ }
+ else
+ src = source;
+
+ entry_len = asprintf (&entry, "%s %s %s %s 0 0\n", src, path, type,
+ options? options: MNTOPT_DEFAULTS);
+ if (! entry)
+ {
+ err = ENOMEM;
+ goto errout;
+ }
+
+ err = mtab_add_entry (mtab, entry, entry_len);
+ if (err)
+ goto errout;
+
+ /* path has an active translator, query its children. */
+ err = fsys_get_children (node, &children, &children_len);
+ if (err == EOPNOTSUPP)
+ {
+ err = 0;
+ children_len = 0;
+ }
+
+ if (err)
+ goto errout;
+
+ if (children_len)
+ for (char *c = children; c; c = argz_next (children, children_len, c))
+ {
+ char *p = NULL;
+ asprintf (&p, "%s%s%s",
+ path,
+ path[strlen (path) - 1] == '/'? "": "/",
+ c);
+ if (! p)
+ {
+ err = ENOMEM;
+ goto errout;
+ }
+
+ err = mtab_populate (mtab, p, insecure);
+ if (err)
+ {
+ /* There is really not much we can do about errors here. */
+ error (0, err, "%s", p);
+ err = 0;
+ }
+
+ free (p);
+ }
+
+ errout:
+ if (node != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), node);
+
+ if (fsys != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), fsys);
+
+ if (argz)
+ vm_deallocate (mach_task_self (), (vm_address_t) argz, argz_len);
+
+ free (argv);
+ free (type);
+ free (options);
+
+ if (src != source)
+ free (src);
+
+ free (entry);
+
+ if (children)
+ vm_deallocate (mach_task_self (), (vm_address_t) children, children_len);
+
+ return err;
+}
+
+/* Decodes the DEVICE string into appropriate OPTIONS. Currently only
+ tmpfs-style size declarations are supported. */
+error_t
+argz_add_device (char **options, size_t *options_len, const char *device)
+{
+ error_t err;
+ char *end = NULL;
+ intmax_t size = strtoimax (device, &end, 0);
+ if (end == NULL || end == device)
+ return 0;
+
+ if (size < 0)
+ return 0;
+
+ switch (*end)
+ {
+ case 'g':
+ case 'G':
+ case 'm':
+ case 'M':
+ case 'k':
+ case 'K':
+ break;
+ default:
+ return 0;
+ }
+
+ /* device specifies a size. */
+ char *arg = NULL;
+ asprintf (&arg, "size=%s", device);
+ if (! arg)
+ return ENOMEM;
+
+ err = argz_add (options, options_len, arg);
+
+ free (arg);
+ return err;
+}
+
+/* Matches [hs]d\ds\d\d?. */
+int
+looks_like_block_device (const char *s)
+{
+ size_t len = strlen (s);
+ if (len != 3 && len != 5 && len != 6)
+ return 0;
+
+ return ((s[0] == 'h' || s[0] == 's') && s[1] == 'd' && isdigit (s[2]) &&
+ (len == 3 || (s[3] == 's' && isdigit (s[4]) &&
+ (len == 5 || isdigit (s[5])))));
+}
+
+/* Map a device string to a file name referencing the appropriate
+ device file. */
+error_t
+map_device_to_path (const char *device, char **path)
+{
+ if (strncmp (device, "device:", 7) == 0)
+ asprintf (path, "/dev/%s", &device[7]);
+ else if (strncmp (device, "/dev/", 5) == 0)
+ *path = strdup (device);
+ else if (looks_like_block_device (device))
+ asprintf (path, "/dev/%s", device);
+ else
+ *path = strdup ("none");
+
+ if (! *path)
+ return ENOMEM;
+
+ return 0;
+}
+
+/* Trivfs hooks. */
+int trivfs_fstype = FSTYPE_MISC;
+int trivfs_fsid = 0;
+
+int trivfs_allow_open = O_READ;
+
+int trivfs_support_read = 1;
+int trivfs_support_write = 0;
+int trivfs_support_exec = 0;
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
+{
+ /* Mark the node as a read-only plain file. */
+ st->st_mode &= ~(S_IFMT | ALLPERMS);
+ st->st_mode |= (S_IFREG | S_IRUSR | S_IRGRP | S_IROTH);
+ st->st_size = ((struct mtab *) cred->po->hook)->contents_len;
+}
+
+error_t
+trivfs_goaway (struct trivfs_control *cntl, int flags)
+{
+ exit (EXIT_SUCCESS);
+}
+
+static error_t
+open_hook (struct trivfs_peropen *peropen)
+{
+ struct mtab *mtab = malloc (sizeof (struct mtab));
+ if (mtab == NULL)
+ return ENOMEM;
+
+ /* Hook! */
+ peropen->hook = mtab;
+
+ /* Initialize the fields. */
+ mtab->offs = 0;
+ mtab->contents = NULL;
+ mtab->contents_len = 0;
+
+ return mtab_populate (mtab, path, insecure);
+}
+
+static void
+close_hook (struct trivfs_peropen *peropen)
+{
+ free (((struct mtab *) peropen->hook)->contents);
+ free (peropen->hook);
+}
+
+/* Read data from an IO object. If offset is -1, read from the object
+ maintained file pointer. If the object is not seekable, offset is
+ ignored. The amount desired to be read is in AMOUNT. */
+error_t
+trivfs_S_io_read (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ char **data, mach_msg_type_number_t *data_len,
+ loff_t offs, mach_msg_type_number_t amount)
+{
+ struct mtab *op;
+
+ /* Deny access if they have bad credentials. */
+ if (! cred)
+ return EOPNOTSUPP;
+
+ if (! (cred->po->openmodes & O_READ))
+ return EBADF;
+
+ /* Get the offset. */
+ op = cred->po->hook;
+ if (offs == -1)
+ offs = op->offs;
+
+ /* Prune the amount they want to read. */
+ if (offs > op->contents_len)
+ offs = op->contents_len;
+ if (offs + amount > op->contents_len)
+ amount = op->contents_len - offs;
+
+ if (amount > 0)
+ {
+ /* Possibly allocate a new buffer. */
+ if (*data_len < amount)
+ {
+ *data = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (*data == MAP_FAILED)
+ return ENOMEM;
+ }
+
+ /* Copy the constant data into the buffer. */
+ memcpy ((char *) *data, op->contents + offs, amount);
+
+ /* Update the saved offset. */
+ op->offs += amount;
+ }
+
+ *data_len = amount;
+ return 0;
+}
+
+
+/* Change current read/write offset */
+error_t
+trivfs_S_io_seek (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ off_t offs, int whence, off_t *new_offs)
+{
+ if (! cred)
+ return EOPNOTSUPP;
+
+ struct mtab *op = cred->po->hook;
+
+ switch (whence)
+ {
+ case SEEK_CUR:
+ offs += op->offs;
+ goto check;
+ case SEEK_END:
+ offs += op->contents_len;
+ case SEEK_SET:
+ check:
+ if (offs >= 0)
+ {
+ *new_offs = op->offs = offs;
+ break;
+ }
+ default:
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+/* If this variable is set, it is called every time a new peropen
+ structure is created and initialized. */
+error_t (*trivfs_peropen_create_hook)(struct trivfs_peropen *) = open_hook;
+
+/* If this variable is set, it is called every time a peropen structure
+ is about to be destroyed. */
+void (*trivfs_peropen_destroy_hook) (struct trivfs_peropen *) = close_hook;
+
+/* Tell how much data can be read from the object without blocking for
+ a "long time" (this should be the same meaning of "long time" used
+ by the nonblocking flag. */
+kern_return_t
+trivfs_S_io_readable (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t replytype,
+ mach_msg_type_number_t *amount)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (!(cred->po->openmodes & O_READ))
+ return EINVAL;
+
+ struct mtab *op = cred->po->hook;
+
+ *amount = op->contents_len - op->offs;
+ return 0;
+}
+
+/* SELECT_TYPE is the bitwise OR of SELECT_READ, SELECT_WRITE, and SELECT_URG.
+ Block until one of the indicated types of i/o can be done "quickly", and
+ return the types that are then available. ID_TAG is returned as passed; it
+ is just for the convenience of the user in matching up reply messages with
+ specific requests sent. */
+kern_return_t
+trivfs_S_io_select (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t replytype,
+ int *type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (((*type & SELECT_READ) && !(cred->po->openmodes & O_READ))
+ || ((*type & SELECT_WRITE) && !(cred->po->openmodes & O_WRITE)))
+ return EBADF;
+
+ *type &= ~SELECT_URG;
+ return 0;
+}
+
+kern_return_t
+trivfs_S_io_select_timeout (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t replytype,
+ struct timespec ts,
+ int *type)
+{
+ return trivfs_S_io_select (cred, reply, replytype, type);
+}
+
+/* These four routines modify the O_APPEND, O_ASYNC, O_FSYNC, and
+ O_NONBLOCK bits for the IO object. In addition, io_get_openmodes
+ will tell you which of O_READ, O_WRITE, and O_EXEC the object can
+ be used for. The O_ASYNC bit affects icky async I/O; good async
+ I/O is done through io_async which is orthogonal to these calls. */
+
+kern_return_t
+trivfs_S_io_get_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t replytype,
+ int *bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ *bits = cred->po->openmodes;
+ return 0;
+}
+
+error_t
+trivfs_S_io_set_all_openmodes(struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t replytype,
+ int mode)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ return 0;
+}
+
+kern_return_t
+trivfs_S_io_set_some_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t replytype,
+ int bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ return 0;
+}
+
+kern_return_t
+trivfs_S_io_clear_some_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t replytype,
+ int bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ return 0;
+}
diff --git a/trans/null.c b/trans/null.c
index 1f985b3..8b3b4e0 100644
--- a/trans/null.c
+++ b/trans/null.c
@@ -31,6 +31,7 @@
#include <fcntl.h>
#include <limits.h>
#include <argp.h>
+#include <nullauth.h>
const char *argp_program_version = STANDARD_HURD_VERSION (null);
@@ -78,6 +79,10 @@ main (int argc, char **argv)
if (err)
error(3, err, "Contacting parent");
+ err = setnullauth ();
+ if (err)
+ error(4, err, "Dropping privileges");
+
/* Launch. */
ports_manage_port_operations_multithread (fsys->pi.bucket, trivfs_demuxer,
2 * 60 * 1000, 0, 0);
diff --git a/trans/symlink.c b/trans/symlink.c
index 03b5100..8562662 100644
--- a/trans/symlink.c
+++ b/trans/symlink.c
@@ -98,6 +98,19 @@ main (int argc, char **argv)
io_restrict_auth (realnode, &realnodenoauth, 0, 0, 0, 0);
mach_port_deallocate (mach_task_self (), realnode);
+ /* Mark us as important. */
+ mach_port_t proc = getproc ();
+ if (proc == MACH_PORT_NULL)
+ error (2, err, "cannot get a handle to our process");
+
+ err = proc_mark_important (proc);
+ /* This might fail due to permissions or because the old proc server
+ is still running, ignore any such errors. */
+ if (err && err != EPERM && err != EMIG_BAD_ID)
+ error (2, err, "Cannot mark us as important");
+
+ mach_port_deallocate (mach_task_self (), proc);
+
/* Launch */
while (1)
{
@@ -221,3 +234,18 @@ S_fsys_forward (mach_port_t server, mach_port_t requestor,
{
return EOPNOTSUPP;
}
+
+error_t
+S_fsys_get_children (mach_port_t server,
+ char **children,
+ mach_msg_type_number_t *children_len)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+S_fsys_get_source (mach_port_t server,
+ char *source)
+{
+ return EOPNOTSUPP;
+}
diff --git a/ufs/pager.c b/ufs/pager.c
index 1e3d140..5d3e44a 100644
--- a/ufs/pager.c
+++ b/ufs/pager.c
@@ -450,6 +450,13 @@ pager_unlock_page (struct user_pager_info *pager,
return err;
}
+void
+pager_notify_evict (struct user_pager_info *pager,
+ vm_offset_t page)
+{
+ assert (!"unrequested notification on eviction");
+}
+
/* Implement the pager_report_extent callback from the pager library. See
<hurd/pager.h> for the interface description. */
inline error_t
@@ -502,7 +509,7 @@ create_disk_pager (void)
upi->type = DISK;
upi->np = 0;
pager_bucket = ports_create_bucket ();
- diskfs_start_disk_pager (upi, pager_bucket, MAY_CACHE, store->size,
+ diskfs_start_disk_pager (upi, pager_bucket, MAY_CACHE, 0, store->size,
&disk_image);
upi->p = diskfs_disk_pager;
}
@@ -595,7 +602,7 @@ diskfs_get_filemap (struct node *np, vm_prot_t prot)
upi->unlocked_pagein_length = 0;
diskfs_nref_light (np);
upi->p = pager_create (upi, pager_bucket,
- MAY_CACHE, MEMORY_OBJECT_COPY_DELAY);
+ MAY_CACHE, MEMORY_OBJECT_COPY_DELAY, 0);
if (upi->p == 0)
{
diskfs_nrele_light (np);
diff --git a/utils/Makefile b/utils/Makefile
index e3bed0b..c079016 100644
--- a/utils/Makefile
+++ b/utils/Makefile
@@ -21,14 +21,17 @@ makemode := utilities
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
+ storeread msgport rpctrace mount gcore fakeauth fakeroot remap \
+ umount nullauth
+
special-targets = loginpr sush uptime fakeroot remap
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
+ rpctrace.c mount.c gcore.c fakeauth.c fakeroot.sh remap.sh \
+ nullauth.c
OBJS = $(filter-out %.sh,$(SRCS:.c=.o))
HURDLIBS = ps ihash store fshelp ports ftpconn shouldbeinlibc
@@ -36,6 +39,8 @@ LDLIBS += -lpthread
login-LDLIBS = -lutil $(LIBCRYPT)
addauth-LDLIBS = $(LIBCRYPT)
setauth-LDLIBS = $(LIBCRYPT)
+mount-LDLIBS = $(libblkid_LIBS)
+mount-CPPFLAGS = $(libblkid_CFLAGS)
INSTALL-login-ops = -o root -m 4755
INSTALL-ids-ops = -o root -m 4755
@@ -56,7 +61,7 @@ ftpcp ftpdir: ../libftpconn/libftpconn.a
settrans: ../libfshelp/libfshelp.a ../libports/libports.a
ps w ids settrans syncfs showtrans fsysopts storeinfo login vmstat portinfo \
devprobe vminfo addauth rmauth setauth unsu ftpcp ftpdir storeread \
- storecat msgport mount: \
+ storecat msgport mount umount nullauth: \
../libshouldbeinlibc/libshouldbeinlibc.a
$(filter-out $(special-targets), $(targets)): %: %.o
@@ -72,7 +77,7 @@ fakeauth-CPPFLAGS = -I$(srcdir)/../auth
authServer-CPPFLAGS = -I$(srcdir)/../auth
auth_requestUser-CPPFLAGS = -I$(srcdir)/../auth
-mount: ../sutils/fstab.o ../sutils/clookup.o \
+mount umount: ../sutils/fstab.o ../sutils/clookup.o match-options.o \
$(foreach L,fshelp ports,../lib$L/lib$L.a)
../sutils/fstab.o ../sutils/clookup.o: FORCE
$(MAKE) -C $(@D) $(@F)
diff --git a/utils/fakeroot.sh b/utils/fakeroot.sh
index 1ace1cf..a64e963 100644
--- a/utils/fakeroot.sh
+++ b/utils/fakeroot.sh
@@ -1,7 +1,7 @@
#!/bin/sh
# Execute a command in an environment where it appears to be root.
#
-# Copyright (C) 2002 Free Software Foundation, Inc.
+# Copyright (C) 2002, 2013 Free Software Foundation, Inc.
#
# This file is part of the GNU Hurd.
#
@@ -54,10 +54,16 @@ if [ $# -eq 0 ]; then
set -- ${SHELL:-/bin/sh}
fi
+TARGET=
+until [ $# -eq 0 ]; do
+ TARGET="${TARGET} '$(echo "$1" | sed -e "s/'/'\\\\''/g")'"
+ shift
+done
+
# We exec settrans, which execs the "fakeauth" command in the chroot context.
# The `pwd` is evaluated here and now, and that result interpreted inside
# the shell running under fakeauth to chdir there inside the chroot world.
# That shell then execs our arguments as a command line.
exec /bin/settrans --chroot \
- /bin/fakeauth /bin/sh -c "cd `pwd`; $*" \
+ /bin/fakeauth /bin/sh -c "cd `pwd`; exec ${TARGET}" \
-- / /hurd/fakeroot
diff --git a/utils/match-options.c b/utils/match-options.c
new file mode 100644
index 0000000..11fc9dc
--- /dev/null
+++ b/utils/match-options.c
@@ -0,0 +1,68 @@
+/* Common functionality for the --test-opts flag of mount and umount.
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+ Written by Justus Winter <address@hidden>
+
+ 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. */
+
+#include <argz.h>
+#include <error.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "match-options.h"
+
+char *test_opts;
+size_t test_opts_len;
+
+int
+match_options (struct mntent *mntent)
+{
+ char *opts;
+ size_t opts_len;
+
+ error_t err = argz_create_sep (mntent->mnt_opts, ',', &opts, &opts_len);
+ if (err)
+ error (3, err, "parsing mount options failed");
+
+ for (char *test = test_opts;
+ test; test = argz_next (test_opts, test_opts_len, test))
+ {
+ char *needle = test;
+ int inverse = strncmp("no", needle, 2) == 0;
+ if (inverse)
+ needle += 2;
+
+ int match = 0;
+ for (char *opt = opts; opt; opt = argz_next (opts, opts_len, opt))
+ {
+ if (strcmp (opt, needle) == 0) {
+ if (inverse)
+ return 0; /* foo in opts, nofoo in test_opts. */
+
+ /* foo in opts, foo in test_opts, record match. */
+ match = 1;
+ }
+ }
+
+ if (! inverse && ! match)
+ return 0; /* No foo in opts, but foo in test_opts. */
+ }
+
+ /* If no conflicting test_opt was encountered, return success. */
+ return 1;
+}
diff --git a/utils/match-options.h b/utils/match-options.h
new file mode 100644
index 0000000..ea7ae70
--- /dev/null
+++ b/utils/match-options.h
@@ -0,0 +1,33 @@
+/* Common functionality for the --test-opts flag of mount and umount.
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+ Written by Justus Winter <address@hidden>
+
+ 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. */
+
+#include <mntent.h>
+
+extern char *test_opts;
+extern size_t test_opts_len;
+
+/* Check whether the given mount entry matches the given set of
+ options.
+
+ Returns 0 if foo is in the options vector but nofoo is in test_opts.
+ Returns 0 if foo is in test_opts but foo is not in the options vector. */
+int
+match_options (struct mntent *mntent);
diff --git a/utils/mount.c b/utils/mount.c
index 8b059c2..04519da 100644
--- a/utils/mount.c
+++ b/utils/mount.c
@@ -24,16 +24,23 @@
#include <error.h>
#include <stdlib.h>
#include <fcntl.h>
+#include <unistd.h>
#include <hurd/fsys.h>
#include <hurd/fshelp.h>
#include <hurd/paths.h>
+#ifdef HAVE_BLKID
+#include <blkid/blkid.h>
+#endif
+
+#include "match-options.h"
#define SEARCH_FMTS _HURD "%sfs\0" _HURD "%s"
-#define DEFAULT_FSTYPE "ext2"
+#define DEFAULT_FSTYPE "auto"
static char *fstype = DEFAULT_FSTYPE;
static char *device, *mountpoint;
static int verbose;
+static int fake;
static char *options;
static size_t options_len;
static mach_msg_timeout_t timeout;
@@ -54,6 +61,10 @@ static const struct argp_option argp_opts[] =
{"update", 'u', 0, 0, "Flush any meta-data cached in core"},
{"remount", 0, 0, OPTION_ALIAS},
{"verbose", 'v', 0, 0, "Give more detailed information"},
+ {"no-mtab", 'n', 0, 0, "Do not update /etc/mtab"},
+ {"test-opts", 'O', "OPTIONS", 0,
+ "Only mount fstab entries matching the given set of options"},
+ {"fake", 'f', 0, 0, "Do not actually mount, just pretend"},
{0, 0}
};
@@ -110,6 +121,20 @@ parse_opt (int key, char *arg, struct argp_state *state)
}
break;
+ case 'n':
+ /* do nothing */
+ break;
+
+ case 'f':
+ fake = 1;
+ break;
+
+ case 'O':
+ err = argz_create_sep (arg, ',', &test_opts, &test_opts_len);
+ if (err)
+ argp_failure (state, 100, ENOMEM, "%s", arg);
+ break;
+
case ARGP_KEY_ARG:
if (mountpoint == 0) /* One arg: mountpoint */
mountpoint = arg;
@@ -307,12 +332,38 @@ do_mount (struct fs *fs, int remount)
return 0;
}
- if (mounted != MACH_PORT_NULL)
+ /* Do not fail if there is an active translator if --fake is
+ given. This mimics Linux mount utility more closely which
+ just looks into the mtab file. */
+ if (mounted != MACH_PORT_NULL && !fake)
{
error (0, 0, "%s already mounted", fs->mntent.mnt_fsname);
return EBUSY;
}
+ if (strcmp (fs->mntent.mnt_type, "auto") == 0)
+ {
+#if HAVE_BLKID
+ char *type =
+ blkid_get_tag_value (NULL, "TYPE", fs->mntent.mnt_fsname);
+ if (! type)
+ {
+ error (0, 0, "failed to detect file system type");
+ return EFTYPE;
+ }
+ else
+ {
+ fs->mntent.mnt_type = strdup (type);
+ if (! fs->mntent.mnt_type)
+ error (3, ENOMEM, "failed to allocate memory");
+ }
+#else
+ fs->mntent.mnt_type = strdup ("ext2");
+ if (! fs->mntent.mnt_type)
+ error (3, ENOMEM, "failed to allocate memory");
+#endif
+ }
+
err = fs_type (fs, &type);
if (err)
{
@@ -337,6 +388,23 @@ do_mount (struct fs *fs, int remount)
/* Now we have a translator command line argz in FSOPTS. */
+ if (fake) {
+ /* Fake the translator startup. */
+ mach_port_t underlying;
+ mach_msg_type_name_t underlying_type;
+ err = open_node (O_READ, &underlying, &underlying_type, 0, NULL);
+ if (err)
+ error (1, errno, "cannot mount on %s", fs->mntent.mnt_dir);
+
+ mach_port_deallocate (mach_task_self (), underlying);
+
+ /* See if the translator is at least executable. */
+ if (access(type->program, X_OK) == -1)
+ error (1, errno, "can not execute %s", type->program);
+
+ return 0;
+ }
+
explain ("settrans -a");
err = fshelp_start_translator (open_node, NULL, fsopts,
fsopts, fsopts_len, timeout,
@@ -521,6 +589,12 @@ main (int argc, char **argv)
fstab = fstab_argp_create (&fstab_params, SEARCH_FMTS, sizeof SEARCH_FMTS);
+ /* This is a convenient way of checking for any `remount' options. */
+ remount = 0;
+ err = argz_replace (&options, &options_len, "remount", "update", &remount);
+ if (err)
+ error (3, ENOMEM, "collecting mount options");
+
if (device) /* two-argument form */
{
struct mntent m =
@@ -531,13 +605,23 @@ main (int argc, char **argv)
mnt_opts: 0,
mnt_freq: 0, mnt_passno: 0
};
- struct fstype *fst;
- err = fstypes_get (fstab->types, fstype, &fst);
+ err = fstab_add_mntent (fstab, &m, &fs);
if (err)
- error (106, err, "cannot initialize type %s", fstype);
- if (fst->program == 0)
- error (2, 0, "filesystem type %s not recognized", fstype);
+ error (2, err, "%s", mountpoint);
+ }
+ else if (mountpoint && remount) /* one-argument remount */
+ {
+ struct mntent m =
+ {
+ mnt_fsname: mountpoint, /* since we cannot know the device,
+ using mountpoint here leads to more
+ helpful error messages */
+ mnt_dir: mountpoint,
+ mnt_type: fstype,
+ mnt_opts: 0,
+ mnt_freq: 0, mnt_passno: 0
+ };
err = fstab_add_mntent (fstab, &m, &fs);
if (err)
@@ -552,12 +636,6 @@ main (int argc, char **argv)
else
fs = 0;
- /* This is a convenient way of checking for any `remount' options. */
- remount = 0;
- err = argz_replace (&options, &options_len, "remount", "update", &remount);
- if (err)
- error (3, ENOMEM, "collecting mount options");
-
if (fs != 0)
err = do_mount (fs, remount);
else
@@ -566,8 +644,22 @@ main (int argc, char **argv)
case mount:
for (fs = fstab->entries; fs; fs = fs->next)
{
- if (fstab_params.do_all && hasmntopt (&fs->mntent, MNTOPT_NOAUTO))
- continue;
+ if (fstab_params.do_all) {
+ if (hasmntopt (&fs->mntent, MNTOPT_NOAUTO))
+ continue;
+
+ if (! match_options (&fs->mntent))
+ continue;
+
+ fsys_t mounted;
+ err = fs_fsys (fs, &mounted);
+ if (err)
+ error (0, err, "cannot determine if %s is already mounted",
+ fs->mntent.mnt_fsname);
+
+ if (mounted != MACH_PORT_NULL)
+ continue;
+ }
err |= do_mount (fs, remount);
}
break;
diff --git a/utils/nullauth.c b/utils/nullauth.c
new file mode 100644
index 0000000..a0d5d1b
--- /dev/null
+++ b/utils/nullauth.c
@@ -0,0 +1,90 @@
+/* Utility to drop all authentication credentials.
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ Written by Justus Winter <address@hidden>
+
+ This file is part of the GNU Hurd.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#include <argp.h>
+#include <error.h>
+#include <nullauth.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <version.h>
+
+static char **args;
+
+const char const *argp_program_version = STANDARD_HURD_VERSION (nullauth);
+
+static const struct argp_option const options[] =
+{
+ { 0 }
+};
+
+static const char const doc[] =
+ "Drop all authentication credentials and run the given program.";
+static const char const args_doc[] =
+ "PROGRAM [ARGUMENTS...]\tThe program to run";
+
+error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ switch (key)
+ {
+ case ARGP_KEY_ARGS:
+ args = state->argv + state->next;
+ break;
+
+ case ARGP_KEY_NO_ARGS:
+ argp_error (state, "expected program to run");
+ return EINVAL;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ return 0;
+}
+
+static struct argp argp = {
+ options,
+ parse_opt,
+ args_doc,
+ doc,
+ NULL,
+};
+
+int
+main (int argc, char *argv[])
+{
+ error_t err;
+
+ /* Parse our command line. This shouldn't ever return an error. */
+ argp_parse (&argp, argc, argv, 0, 0, NULL);
+
+ /* Drop all privileges. */
+ err = setnullauth();
+ if (err)
+ error (1, err, "Could not drop privileges");
+
+ execv (args[0], args);
+ error (1, errno, "execv");
+
+ /* Not reached. */
+ return EXIT_FAILURE;
+}
diff --git a/utils/remap.sh b/utils/remap.sh
index d799759..064f0f5 100644
--- a/utils/remap.sh
+++ b/utils/remap.sh
@@ -57,10 +57,16 @@ if [ $# -eq 0 ]; then
set -- ${SHELL:-/bin/sh}
fi
+TARGET=
+until [ $# -eq 0 ]; do
+ TARGET="${TARGET} '$(echo "$1" | sed -e "s/'/'\\\\''/g")'"
+ shift
+done
+
# We exec settrans, which execs the "fakeauth" command in the chroot context.
# The `pwd` is evaluated here and now, and that result interpreted inside
# the shell running under fakeauth to chdir there inside the chroot world.
# That shell then execs our arguments as a command line.
exec /bin/settrans --chroot \
- /bin/sh -c "cd `pwd`; $*" \
+ /bin/sh -c "cd `pwd`; exec ${TARGET}" \
-- / /hurd/remap $MAPPED
diff --git a/utils/umount.c b/utils/umount.c
new file mode 100644
index 0000000..26d2b56
--- /dev/null
+++ b/utils/umount.c
@@ -0,0 +1,357 @@
+/* Roughly Unix/Linux-compatible `umount' frontend for Hurd translators.
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+ Written by Justus Winter <address@hidden>
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#include <argp.h>
+#include <argz.h>
+#include <error.h>
+#include <fcntl.h>
+#include <hurd/fshelp.h>
+#include <hurd/fsys.h>
+#include <hurd/paths.h>
+#include <hurd/process.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "match-options.h"
+#include "../sutils/fstab.h"
+
+/* XXX fix libc */
+#undef _PATH_MOUNTED
+#define _PATH_MOUNTED "/etc/mtab"
+
+static char *targets;
+static size_t targets_len;
+static int readonly;
+static int verbose;
+static int passive_flags = FS_TRANS_SET;
+static int active_flags = FS_TRANS_SET;
+static int goaway_flags;
+static int source_goaway;
+static int fake;
+
+static struct fstab_argp_params fstab_params;
+
+#define FAKE_KEY 0x80 /* !isascii (FAKE_KEY), so no short option. */
+
+static const struct argp_option argp_opts[] =
+{
+ {NULL, 'd', 0, 0, "Also ask the source translator to go away"},
+ {"fake", FAKE_KEY, 0, 0, "Do not actually umount, just pretend"},
+ {"force", 'f', 0, 0, "Force umount by killing the translator"},
+ {"no-mtab", 'n', 0, 0, "Do not update /etc/mtab"},
+ {"read-only", 'r', 0, 0, "If unmounting fails, try to remount read-only"},
+ {"nosync", 'S', 0, 0, "Don't sync a translator before killing it"},
+ {"test-opts", 'O', "OPTIONS", 0,
+ "Only mount fstab entries matching the given set of options"},
+ {"verbose", 'v', 0, 0, "Give more detailed information"},
+ {},
+};
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ struct fstab_argp_params *params = state->input;
+ error_t err;
+ switch (key)
+ {
+ case ARGP_KEY_INIT:
+ state->child_inputs[0] = params; /* pass down to fstab_argp parser */
+ break;
+
+ case 'd':
+ source_goaway = 1;
+ break;
+
+ case FAKE_KEY:
+ fake = 1;
+ break;
+
+ case 'f':
+ goaway_flags |= FSYS_GOAWAY_FORCE;
+ break;
+
+ case 'n':
+ /* do nothing */
+ break;
+
+ case 'r':
+ readonly = 1;
+ break;
+
+ case 'S':
+ goaway_flags |= FSYS_GOAWAY_NOSYNC;
+ break;
+
+ case 'O':
+ err = argz_create_sep (arg, ',', &test_opts, &test_opts_len);
+ if (err)
+ argp_failure (state, 100, ENOMEM, "%s", arg);
+ break;
+
+ case 'v':
+ verbose += 1;
+ break;
+
+ case ARGP_KEY_ARG:
+ err = argz_add (&targets, &targets_len, arg);
+ if (err)
+ argp_failure (state, 100, ENOMEM, "%s", arg);
+ break;
+
+ case ARGP_KEY_NO_ARGS:
+ if (! params->do_all)
+ {
+ argp_error (state,
+ "filesystem argument required if --all is not given");
+ return EINVAL;
+ }
+ break;
+
+ case ARGP_KEY_END:
+ if (params->do_all && targets)
+ {
+ argp_error (state, "filesystem argument not allowed with --all");
+ return EINVAL;
+ }
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ return 0;
+}
+
+static const char doc[] = "Stop active and remove passive translators";
+static const char args_doc[] = "DEVICE|DIRECTORY [DEVICE|DIRECTORY ...]";
+
+static struct argp fstab_argp_mtab; /* Slightly modified version. */
+
+static const struct argp_child argp_kids[] =
+{
+ {&fstab_argp_mtab, 0,
+ "Filesystem selection (if no explicit filesystem arguments given):", 2},
+ {},
+};
+static struct argp argp =
+{
+ options: argp_opts,
+ parser: parse_opt,
+ args_doc: args_doc,
+ doc: doc,
+ children: argp_kids,
+};
+
+/* This is a trimmed and slightly modified version of
+ fstab_argp.options which uses _PATH_MOUNTED instead of _PATH_MNTTAB
+ in the doc strings. */
+static const struct argp_option fstab_argp_mtab_opts[] =
+{
+ {"all", 'a', 0, 0, "Do all filesystems in " _PATH_MOUNTED},
+ {0, 'A', 0, OPTION_ALIAS },
+ {"fstab", 'F', "FILE", 0, "File to use instead of " _PATH_MOUNTED},
+ {"fstype", 't', "TYPE", 0, "Do only filesystems of given type(s)"},
+ {"exclude-root",'R',0, 0,
+ "Exclude root (/) filesystem from " _PATH_MOUNTED " list"},
+ {"exclude", 'X', "PATTERN", 0, "Exclude directories matching PATTERN"},
+ {}
+};
+
+static error_t
+fstab_argp_mtab_parse_opt (int key, char *arg, struct argp_state *state)
+{
+ return fstab_argp.parser (key, arg, state);
+}
+
+static struct argp fstab_argp_mtab =
+{
+ options: fstab_argp_mtab_opts,
+ parser: fstab_argp_mtab_parse_opt,
+};
+
+/* Unmount one filesystem. */
+static error_t
+do_umount (struct fs *fs)
+{
+ error_t err = 0;
+
+ file_t node = file_name_lookup (fs->mntent.mnt_dir, O_NOTRANS, 0666);
+ if (node == MACH_PORT_NULL)
+ {
+ error (0, errno, "%s", fs->mntent.mnt_dir);
+ return errno;
+ }
+
+ if (verbose)
+ printf ("settrans -apg%s%s %s\n",
+ goaway_flags & FSYS_GOAWAY_NOSYNC? "S": "",
+ goaway_flags & FSYS_GOAWAY_FORCE? "f": "",
+ fs->mntent.mnt_dir);
+
+ if (! fake)
+ {
+ err = file_set_translator (node,
+ passive_flags, active_flags, goaway_flags,
+ NULL, 0,
+ MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND);
+ if (! err)
+ {
+ if (strcmp (fs->mntent.mnt_fsname, "") != 0 &&
+ strcmp (fs->mntent.mnt_fsname, "none") != 0)
+ {
+ if (verbose)
+ printf ("settrans -ag%s%s %s\n",
+ goaway_flags & FSYS_GOAWAY_NOSYNC? "S": "",
+ goaway_flags & FSYS_GOAWAY_FORCE? "f": "",
+ fs->mntent.mnt_fsname);
+
+ file_t source = file_name_lookup (fs->mntent.mnt_fsname,
+ O_NOTRANS,
+ 0666);
+ if (source == MACH_PORT_NULL)
+ {
+ error (0, errno, "%s", fs->mntent.mnt_fsname);
+ return errno;
+ }
+
+ err = file_set_translator (source,
+ 0, active_flags, goaway_flags,
+ NULL, 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TYPE_COPY_SEND);
+ if (err)
+ error (0, err, "%s", fs->mntent.mnt_fsname);
+
+ mach_port_deallocate (mach_task_self (), source);
+
+ }
+ }
+ else
+ {
+ error (0, err, "%s", fs->mntent.mnt_dir);
+
+ /* Try remounting readonly instead if requested. */
+ if (readonly)
+ {
+ if (verbose)
+ printf ("fsysopts %s --readonly\n", fs->mntent.mnt_dir);
+
+ error_t e = fs_set_readonly (fs, TRUE);
+ if (e)
+ error (0, e, "%s", fs->mntent.mnt_dir);
+ }
+ }
+ }
+
+ /* Deallocate the reference so that unmounting nested translators
+ works properly. */
+ mach_port_deallocate (mach_task_self (), node);
+ return err;
+}
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+
+ err = argp_parse (&argp, argc, argv, 0, 0, &fstab_params);
+ if (err)
+ error (3, err, "parsing arguments");
+
+ /* Read the mtab file by default. */
+ if (! fstab_params.fstab_path)
+ fstab_params.fstab_path = _PATH_MOUNTED;
+
+ struct fstab *fstab = fstab_argp_create (&fstab_params, NULL, 0);
+ if (! fstab)
+ error (3, ENOMEM, "fstab creation");
+
+ if (targets)
+ for (char *t = targets; t; t = argz_next (targets, targets_len, t))
+ {
+ /* Figure out if t is the device or the mountpoint. */
+ struct fs *fs = fstab_find_mount (fstab, t);
+ if (! fs)
+ {
+ fs = fstab_find_device (fstab, t);
+ if (! fs)
+ {
+ error (0, 0, "could not find entry for: %s", t);
+
+ /* As last resort, just assume it is the mountpoint. */
+ struct mntent m =
+ {
+ mnt_fsname: "",
+ mnt_dir: t,
+ mnt_type: "",
+ mnt_opts: 0,
+ mnt_freq: 0,
+ mnt_passno: 0,
+ };
+
+ err = fstab_add_mntent (fstab, &m, &fs);
+ if (err)
+ error (2, err, "%s", t);
+ }
+ }
+
+ if (fs)
+ err |= do_umount (fs);
+ }
+ else
+ {
+ /* Sort entries in reverse lexicographical order so that the
+ longest mount points are unmounted first. This makes sure
+ that nested mounts are handled properly. */
+ size_t count = 0;
+ for (struct fs *fs = fstab->entries; fs; fs = fs->next)
+ count += 1;
+
+ char **entries = malloc (count * sizeof (char *));
+ if (! entries)
+ error (3, ENOMEM, "allocating entries array");
+
+ char **p = entries;
+ for (struct fs *fs = fstab->entries; fs; fs = fs->next)
+ *p++ = fs->mntent.mnt_dir;
+
+ /* Reverse lexicographical order. */
+ int compare_entries (const void *a, const void *b)
+ {
+ return -strcmp ((char *) a, (char *) b);
+ }
+
+ qsort (entries, count, sizeof (char *), compare_entries);
+
+ for (int i = 0; i < count; i++)
+ {
+ struct fs *fs = fstab_find_mount (fstab, entries[i]);
+ if (! fs)
+ error (4, 0, "could not find entry for: %s", entries[i]);
+
+ if (! match_options (&fs->mntent))
+ continue;
+
+ err |= do_umount (fs);
+ }
+ }
+
+ return err? EXIT_FAILURE: EXIT_SUCCESS;
+}
--
Alioth's /usr/local/bin/git-commit-notice on
/srv/git.debian.org/git/pkg-hurd/hurd.git
- [hurd] branch master updated (020d5e0 -> 1dee421), Samuel Thibault, 2013/09/16
- [hurd] 03/07: control: Add build dependency on libdaemon, Samuel Thibault, 2013/09/16
- [hurd] 04/07: Add an initscript for hurd-console, Samuel Thibault, 2013/09/16
- [hurd] 05/07: Fix link until libc gets rebuilt against new .defs, Samuel Thibault, 2013/09/16
- [hurd] 07/07: Merge branch 'upstream-merged', Samuel Thibault, 2013/09/16
- [hurd] 06/07: Drop removed files, Samuel Thibault, 2013/09/16
- [hurd] 02/07: Merge branch 'upstream-merged', Samuel Thibault, 2013/09/16
- [hurd] 01/07: New upstream snapshot,
Samuel Thibault <=