From 44a7a5ab64e9df65e241260d76d3dac1160b3360 Mon Sep 17 00:00:00 2001
From: Apple <opensource@apple.com>
Date: Tue, 10 Apr 2001 06:35:09 +0000
Subject: [PATCH] file_cmds-45.tar.gz

---
 Makefile                    |   49 ++
 Makefile.postamble          |    1 +
 Makefile.preamble           |    1 +
 PB.project                  |   49 ++
 PROJECT                     |   10 +
 chflags/Makefile            |   48 ++
 chflags/Makefile.postamble  |    1 +
 chflags/Makefile.preamble   |    5 +
 chflags/PB.project          |   25 +
 chflags/chflags.1           |  126 +++
 chflags/chflags.c           |  187 +++++
 chmod/Makefile              |   48 ++
 chmod/Makefile.postamble    |    1 +
 chmod/Makefile.preamble     |    1 +
 chmod/PB.project            |   25 +
 chmod/chmod.1               |  306 +++++++
 chmod/chmod.c               |  242 ++++++
 chown/Makefile              |   50 ++
 chown/Makefile.postamble    |    4 +
 chown/Makefile.preamble     |    1 +
 chown/PB.project            |   26 +
 chown/chgrp.1               |  146 ++++
 chown/chown.8               |  154 ++++
 chown/chown.c               |  266 ++++++
 cksum/crc.c                 |  149 ++++
 compress/Makefile           |   49 ++
 compress/Makefile.postamble |    5 +
 compress/Makefile.preamble  |    1 +
 compress/PB.project         |   32 +
 compress/compress.1         |  176 ++++
 compress/compress.c         |  491 ++++++++++++
 compress/uncompress.1       |    1 +
 compress/zopen.3            |  142 ++++
 compress/zopen.c            |  748 +++++++++++++++++
 cp/Makefile                 |   51 ++
 cp/Makefile.postamble       |    1 +
 cp/Makefile.preamble        |    1 +
 cp/PB.project               |   27 +
 cp/cp.1                     |  215 +++++
 cp/cp.c                     |  484 +++++++++++
 cp/extern.h                 |   59 ++
 cp/utils.c                  |  356 ++++++++
 csh/strpct.c                |   99 +++
 dd/Makefile                 |   50 ++
 dd/Makefile.postamble       |    1 +
 dd/Makefile.preamble        |    1 +
 dd/PB.project               |   26 +
 dd/args.c                   |  412 ++++++++++
 dd/conv.c                   |  283 +++++++
 dd/conv_tab.c               |  291 +++++++
 dd/dd.1                     |  355 ++++++++
 dd/dd.c                     |  412 ++++++++++
 dd/dd.h                     |   98 +++
 dd/extern.h                 |   69 ++
 dd/misc.c                   |  108 +++
 dd/position.c               |  174 ++++
 df/Makefile                 |   48 ++
 df/Makefile.postamble       |    4 +
 df/Makefile.preamble        |    5 +
 df/PB.project               |   25 +
 df/df.1                     |  122 +++
 df/df.c                     |  455 +++++++++++
 du/Makefile                 |   48 ++
 du/Makefile.postamble       |    1 +
 du/Makefile.preamble        |    1 +
 du/PB.project               |   25 +
 du/du.1                     |  134 ++++
 du/du.c                     |  255 ++++++
 install/Makefile            |   50 ++
 install/Makefile.postamble  |    1 +
 install/Makefile.preamble   |    5 +
 install/PB.project          |   26 +
 install/install.1           |  183 +++++
 install/pathnames.h         |   38 +
 install/xinstall.c          |  563 +++++++++++++
 ln/Makefile                 |   49 ++
 ln/Makefile.postamble       |    1 +
 ln/Makefile.preamble        |    1 +
 ln/PB.project               |   25 +
 ln/ln.1                     |  147 ++++
 ln/ln.c                     |  182 +++++
 ln/symlink.7                |  427 ++++++++++
 ls/Makefile                 |   50 ++
 ls/Makefile.postamble       |    1 +
 ls/Makefile.preamble        |    1 +
 ls/PB.project               |   26 +
 ls/cmp.c                    |  203 +++++
 ls/extern.h                 |   56 ++
 ls/ls.1                     |  367 +++++++++
 ls/ls.c                     |  616 ++++++++++++++
 ls/ls.h                     |   76 ++
 ls/print.c                  |  363 +++++++++
 ls/stat_flags.c             |  164 ++++
 ls/util.c                   |   80 ++
 mkdir/Makefile              |   48 ++
 mkdir/Makefile.postamble    |    1 +
 mkdir/Makefile.preamble     |    1 +
 mkdir/PB.project            |   25 +
 mkdir/mkdir.1               |   97 +++
 mkdir/mkdir.c               |  195 +++++
 mkfifo/Makefile             |   48 ++
 mkfifo/Makefile.postamble   |    1 +
 mkfifo/Makefile.preamble    |    1 +
 mkfifo/PB.project           |   25 +
 mkfifo/mkfifo.1             |   91 +++
 mkfifo/mkfifo.c             |  113 +++
 mknod/Makefile              |   48 ++
 mknod/Makefile.postamble    |    1 +
 mknod/Makefile.preamble     |    1 +
 mknod/PB.project            |   25 +
 mknod/mknod.8               |  149 ++++
 mknod/mknod.c               |  396 +++++++++
 mtree/Makefile              |   50 ++
 mtree/Makefile.postamble    |    1 +
 mtree/Makefile.preamble     |    5 +
 mtree/PB.project            |   26 +
 mtree/compare.c             |  298 +++++++
 mtree/create.c              |  306 +++++++
 mtree/extern.h              |   52 ++
 mtree/misc.c                |  134 ++++
 mtree/mtree.8               |  261 ++++++
 mtree/mtree.c               |  162 ++++
 mtree/mtree.h               |   97 +++
 mtree/spec.c                |  293 +++++++
 mtree/verify.c              |  211 +++++
 mv/Makefile                 |   50 ++
 mv/Makefile.postamble       |    1 +
 mv/Makefile.preamble        |    1 +
 mv/PB.project               |   26 +
 mv/mv.1                     |  133 +++
 mv/mv.c                     |  361 +++++++++
 mv/pathnames.h              |   39 +
 pax/Makefile                |   54 ++
 pax/Makefile.postamble      |    5 +
 pax/Makefile.preamble       |    1 +
 pax/PB.project              |   54 ++
 pax/ar_io.c                 | 1372 +++++++++++++++++++++++++++++++
 pax/ar_subs.c               | 1288 +++++++++++++++++++++++++++++
 pax/buf_subs.c              | 1094 +++++++++++++++++++++++++
 pax/cache.c                 |  500 ++++++++++++
 pax/cache.h                 |   77 ++
 pax/cpio.1                  |  270 +++++++
 pax/cpio.c                  | 1284 +++++++++++++++++++++++++++++
 pax/cpio.h                  |  154 ++++
 pax/extern.h                |  299 +++++++
 pax/file_subs.c             | 1112 +++++++++++++++++++++++++
 pax/ftree.c                 |  565 +++++++++++++
 pax/ftree.h                 |   54 ++
 pax/gen_subs.c              |  467 +++++++++++
 pax/getoldopt.c             |   73 ++
 pax/options.c               | 1515 +++++++++++++++++++++++++++++++++++
 pax/options.h               |  116 +++
 pax/pat_rep.c               | 1240 ++++++++++++++++++++++++++++
 pax/pat_rep.h               |   57 ++
 pax/pax.1                   | 1178 +++++++++++++++++++++++++++
 pax/pax.c                   |  426 ++++++++++
 pax/pax.h                   |  243 ++++++
 pax/sel_subs.c              |  662 +++++++++++++++
 pax/sel_subs.h              |   76 ++
 pax/tables.c                | 1434 +++++++++++++++++++++++++++++++++
 pax/tables.h                |  175 ++++
 pax/tar.1                   |  239 ++++++
 pax/tar.c                   | 1213 ++++++++++++++++++++++++++++
 pax/tar.h                   |  151 ++++
 pax/tty_subs.c              |  251 ++++++
 rm/Makefile                 |   48 ++
 rm/Makefile.postamble       |    1 +
 rm/Makefile.preamble        |    1 +
 rm/PB.project               |   25 +
 rm/rm.1                     |  157 ++++
 rm/rm.c                     |  448 +++++++++++
 rmdir/Makefile              |   48 ++
 rmdir/Makefile.postamble    |    1 +
 rmdir/Makefile.preamble     |    1 +
 rmdir/PB.project            |   25 +
 rmdir/rmdir.1               |   94 +++
 rmdir/rmdir.c               |  136 ++++
 rmt/Makefile                |   48 ++
 rmt/Makefile.postamble      |    1 +
 rmt/Makefile.preamble       |    1 +
 rmt/PB.project              |   25 +
 rmt/rmt.8                   |  220 +++++
 rmt/rmt.c                   |  259 ++++++
 shar/Makefile               |   49 ++
 shar/Makefile.postamble     |    1 +
 shar/Makefile.preamble      |    3 +
 shar/PB.project             |   25 +
 shar/shar.1                 |  105 +++
 shar/shar.sh                |   76 ++
 tcopy/Makefile              |   48 ++
 tcopy/Makefile.postamble    |    1 +
 tcopy/Makefile.preamble     |    1 +
 tcopy/PB.project            |   25 +
 tcopy/tcopy.1               |   91 +++
 tcopy/tcopy.c               |  339 ++++++++
 touch/Makefile              |   48 ++
 touch/Makefile.postamble    |    1 +
 touch/Makefile.preamble     |    1 +
 touch/PB.project            |   25 +
 touch/touch.1               |  177 ++++
 touch/touch.c               |  389 +++++++++
 201 files changed, 36379 insertions(+)
 create mode 100644 Makefile
 create mode 100644 Makefile.postamble
 create mode 100644 Makefile.preamble
 create mode 100644 PB.project
 create mode 100644 PROJECT
 create mode 100644 chflags/Makefile
 create mode 100644 chflags/Makefile.postamble
 create mode 100644 chflags/Makefile.preamble
 create mode 100644 chflags/PB.project
 create mode 100644 chflags/chflags.1
 create mode 100644 chflags/chflags.c
 create mode 100644 chmod/Makefile
 create mode 100644 chmod/Makefile.postamble
 create mode 100644 chmod/Makefile.preamble
 create mode 100644 chmod/PB.project
 create mode 100644 chmod/chmod.1
 create mode 100644 chmod/chmod.c
 create mode 100644 chown/Makefile
 create mode 100644 chown/Makefile.postamble
 create mode 100644 chown/Makefile.preamble
 create mode 100644 chown/PB.project
 create mode 100644 chown/chgrp.1
 create mode 100644 chown/chown.8
 create mode 100644 chown/chown.c
 create mode 100644 cksum/crc.c
 create mode 100644 compress/Makefile
 create mode 100644 compress/Makefile.postamble
 create mode 100644 compress/Makefile.preamble
 create mode 100644 compress/PB.project
 create mode 100644 compress/compress.1
 create mode 100644 compress/compress.c
 create mode 100644 compress/uncompress.1
 create mode 100644 compress/zopen.3
 create mode 100644 compress/zopen.c
 create mode 100644 cp/Makefile
 create mode 100644 cp/Makefile.postamble
 create mode 100644 cp/Makefile.preamble
 create mode 100644 cp/PB.project
 create mode 100644 cp/cp.1
 create mode 100644 cp/cp.c
 create mode 100644 cp/extern.h
 create mode 100644 cp/utils.c
 create mode 100644 csh/strpct.c
 create mode 100644 dd/Makefile
 create mode 100644 dd/Makefile.postamble
 create mode 100644 dd/Makefile.preamble
 create mode 100644 dd/PB.project
 create mode 100644 dd/args.c
 create mode 100644 dd/conv.c
 create mode 100644 dd/conv_tab.c
 create mode 100644 dd/dd.1
 create mode 100644 dd/dd.c
 create mode 100644 dd/dd.h
 create mode 100644 dd/extern.h
 create mode 100644 dd/misc.c
 create mode 100644 dd/position.c
 create mode 100644 df/Makefile
 create mode 100644 df/Makefile.postamble
 create mode 100644 df/Makefile.preamble
 create mode 100644 df/PB.project
 create mode 100644 df/df.1
 create mode 100644 df/df.c
 create mode 100644 du/Makefile
 create mode 100644 du/Makefile.postamble
 create mode 100644 du/Makefile.preamble
 create mode 100644 du/PB.project
 create mode 100644 du/du.1
 create mode 100644 du/du.c
 create mode 100644 install/Makefile
 create mode 100644 install/Makefile.postamble
 create mode 100644 install/Makefile.preamble
 create mode 100644 install/PB.project
 create mode 100644 install/install.1
 create mode 100644 install/pathnames.h
 create mode 100644 install/xinstall.c
 create mode 100644 ln/Makefile
 create mode 100644 ln/Makefile.postamble
 create mode 100644 ln/Makefile.preamble
 create mode 100644 ln/PB.project
 create mode 100644 ln/ln.1
 create mode 100644 ln/ln.c
 create mode 100644 ln/symlink.7
 create mode 100644 ls/Makefile
 create mode 100644 ls/Makefile.postamble
 create mode 100644 ls/Makefile.preamble
 create mode 100644 ls/PB.project
 create mode 100644 ls/cmp.c
 create mode 100644 ls/extern.h
 create mode 100644 ls/ls.1
 create mode 100644 ls/ls.c
 create mode 100644 ls/ls.h
 create mode 100644 ls/print.c
 create mode 100644 ls/stat_flags.c
 create mode 100644 ls/util.c
 create mode 100644 mkdir/Makefile
 create mode 100644 mkdir/Makefile.postamble
 create mode 100644 mkdir/Makefile.preamble
 create mode 100644 mkdir/PB.project
 create mode 100644 mkdir/mkdir.1
 create mode 100644 mkdir/mkdir.c
 create mode 100644 mkfifo/Makefile
 create mode 100644 mkfifo/Makefile.postamble
 create mode 100644 mkfifo/Makefile.preamble
 create mode 100644 mkfifo/PB.project
 create mode 100644 mkfifo/mkfifo.1
 create mode 100644 mkfifo/mkfifo.c
 create mode 100644 mknod/Makefile
 create mode 100644 mknod/Makefile.postamble
 create mode 100644 mknod/Makefile.preamble
 create mode 100644 mknod/PB.project
 create mode 100644 mknod/mknod.8
 create mode 100644 mknod/mknod.c
 create mode 100644 mtree/Makefile
 create mode 100644 mtree/Makefile.postamble
 create mode 100644 mtree/Makefile.preamble
 create mode 100644 mtree/PB.project
 create mode 100644 mtree/compare.c
 create mode 100644 mtree/create.c
 create mode 100644 mtree/extern.h
 create mode 100644 mtree/misc.c
 create mode 100644 mtree/mtree.8
 create mode 100644 mtree/mtree.c
 create mode 100644 mtree/mtree.h
 create mode 100644 mtree/spec.c
 create mode 100644 mtree/verify.c
 create mode 100644 mv/Makefile
 create mode 100644 mv/Makefile.postamble
 create mode 100644 mv/Makefile.preamble
 create mode 100644 mv/PB.project
 create mode 100644 mv/mv.1
 create mode 100644 mv/mv.c
 create mode 100644 mv/pathnames.h
 create mode 100644 pax/Makefile
 create mode 100644 pax/Makefile.postamble
 create mode 100644 pax/Makefile.preamble
 create mode 100644 pax/PB.project
 create mode 100644 pax/ar_io.c
 create mode 100644 pax/ar_subs.c
 create mode 100644 pax/buf_subs.c
 create mode 100644 pax/cache.c
 create mode 100644 pax/cache.h
 create mode 100644 pax/cpio.1
 create mode 100644 pax/cpio.c
 create mode 100644 pax/cpio.h
 create mode 100644 pax/extern.h
 create mode 100644 pax/file_subs.c
 create mode 100644 pax/ftree.c
 create mode 100644 pax/ftree.h
 create mode 100644 pax/gen_subs.c
 create mode 100644 pax/getoldopt.c
 create mode 100644 pax/options.c
 create mode 100644 pax/options.h
 create mode 100644 pax/pat_rep.c
 create mode 100644 pax/pat_rep.h
 create mode 100644 pax/pax.1
 create mode 100644 pax/pax.c
 create mode 100644 pax/pax.h
 create mode 100644 pax/sel_subs.c
 create mode 100644 pax/sel_subs.h
 create mode 100644 pax/tables.c
 create mode 100644 pax/tables.h
 create mode 100644 pax/tar.1
 create mode 100644 pax/tar.c
 create mode 100644 pax/tar.h
 create mode 100644 pax/tty_subs.c
 create mode 100644 rm/Makefile
 create mode 100644 rm/Makefile.postamble
 create mode 100644 rm/Makefile.preamble
 create mode 100644 rm/PB.project
 create mode 100644 rm/rm.1
 create mode 100644 rm/rm.c
 create mode 100644 rmdir/Makefile
 create mode 100644 rmdir/Makefile.postamble
 create mode 100644 rmdir/Makefile.preamble
 create mode 100644 rmdir/PB.project
 create mode 100644 rmdir/rmdir.1
 create mode 100644 rmdir/rmdir.c
 create mode 100644 rmt/Makefile
 create mode 100644 rmt/Makefile.postamble
 create mode 100644 rmt/Makefile.preamble
 create mode 100644 rmt/PB.project
 create mode 100644 rmt/rmt.8
 create mode 100644 rmt/rmt.c
 create mode 100644 shar/Makefile
 create mode 100644 shar/Makefile.postamble
 create mode 100644 shar/Makefile.preamble
 create mode 100644 shar/PB.project
 create mode 100644 shar/shar.1
 create mode 100644 shar/shar.sh
 create mode 100644 tcopy/Makefile
 create mode 100644 tcopy/Makefile.postamble
 create mode 100644 tcopy/Makefile.preamble
 create mode 100644 tcopy/PB.project
 create mode 100644 tcopy/tcopy.1
 create mode 100644 tcopy/tcopy.c
 create mode 100644 touch/Makefile
 create mode 100644 touch/Makefile.postamble
 create mode 100644 touch/Makefile.preamble
 create mode 100644 touch/PB.project
 create mode 100644 touch/touch.1
 create mode 100644 touch/touch.c

diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..97ed83a
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,49 @@
+#
+# Generated by the NeXT Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = file_cmds
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Aggregate
+
+TOOLS = chflags chmod chown compress cp dd df du install ln ls\
+        mkdir mkfifo mknod mtree mv pax rm rmdir rmt shar tcopy\
+        touch
+
+OTHERSRCS = PROJECT Makefile.preamble Makefile Makefile.postamble
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = aggregate.make
+LIBS = 
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+NEXTSTEP_PB_CFLAGS = -Wall -Werror
+
+
+NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/$(NAME)/Build
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
diff --git a/Makefile.postamble b/Makefile.postamble
new file mode 100644
index 0000000..013b558
--- /dev/null
+++ b/Makefile.postamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
diff --git a/Makefile.preamble b/Makefile.preamble
new file mode 100644
index 0000000..8f8a3bd
--- /dev/null
+++ b/Makefile.preamble
@@ -0,0 +1 @@
+include $(MAKEFILEPATH)/CoreOS/ProjectBuilder/Makefile.Preamble.Common
diff --git a/PB.project b/PB.project
new file mode 100644
index 0000000..09da8c8
--- /dev/null
+++ b/PB.project
@@ -0,0 +1,49 @@
+{
+    DYNAMIC_CODE_GEN = YES; 
+    FILESTABLE = {
+        OTHER_SOURCES = (PROJECT, Makefile.preamble, Makefile, Makefile.postamble); 
+        SUBPROJECTS = (
+            chflags, 
+            chmod, 
+            chown, 
+            compress, 
+            cp, 
+            dd, 
+            df, 
+            du, 
+            install, 
+            ln, 
+            ls, 
+            mkdir, 
+            mkfifo, 
+            mknod, 
+            mtree, 
+            mv, 
+            pax, 
+            rm, 
+            rmdir, 
+            rmt, 
+            shar, 
+            tcopy, 
+            touch
+        ); 
+    }; 
+    LANGUAGE = English; 
+    LOCALIZABLE_FILES = {}; 
+    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
+    NEXTSTEP_BUILDDIR = "/tmp/$(NAME)/Build"; 
+    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
+    NEXTSTEP_COMPILEROPTIONS = "-Wall -Werror"; 
+    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
+    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
+    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
+    PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; 
+    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
+    PROJECTNAME = file_cmds; 
+    PROJECTTYPE = Aggregate; 
+    PROJECTVERSION = 2.8; 
+    TARGETS = (); 
+    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
+    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
+    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
+}
diff --git a/PROJECT b/PROJECT
new file mode 100644
index 0000000..6c7fd2c
--- /dev/null
+++ b/PROJECT
@@ -0,0 +1,10 @@
+Project		: file_cmds
+Description	: File Commands
+Distribution	: NetBSD Tue Oct  6 14:50:43 PDT 1998
+Source		: NetBSD Foundation, Inc.
+Location	: cvs.netbsd.org:/cvsroot
+Owner		: wsanchez
+Releases	: Titan
+Dependancies	: 
+
+Some file commands in NetBSD implement the -h flag and can otherwise charge permissions on symlinks. But this requires lchmod(2) from NetBSD and we don't currently have that, so it is disabled with -D__APPLE__. 
diff --git a/chflags/Makefile b/chflags/Makefile
new file mode 100644
index 0000000..4f99118
--- /dev/null
+++ b/chflags/Makefile
@@ -0,0 +1,48 @@
+#
+# Generated by the NeXT Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = chflags
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+CFILES = chflags.c
+
+OTHERSRCS = Makefile Makefile.preamble Makefile.postamble chflags.1
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /usr/bin
+LIBS = 
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+
+
+NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/developer_cmds/Build
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
diff --git a/chflags/Makefile.postamble b/chflags/Makefile.postamble
new file mode 100644
index 0000000..013b558
--- /dev/null
+++ b/chflags/Makefile.postamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
diff --git a/chflags/Makefile.preamble b/chflags/Makefile.preamble
new file mode 100644
index 0000000..7a86fc2
--- /dev/null
+++ b/chflags/Makefile.preamble
@@ -0,0 +1,5 @@
+vpath stat_flags.c ../ls
+
+CFILES += stat_flags.c
+
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
diff --git a/chflags/PB.project b/chflags/PB.project
new file mode 100644
index 0000000..bf7e967
--- /dev/null
+++ b/chflags/PB.project
@@ -0,0 +1,25 @@
+{
+    DYNAMIC_CODE_GEN = YES; 
+    FILESTABLE = {
+        FRAMEWORKS = (); 
+        OTHER_LINKED = (chflags.c); 
+        OTHER_SOURCES = (Makefile, Makefile.preamble, Makefile.postamble, chflags.1); 
+    }; 
+    LANGUAGE = English; 
+    LOCALIZABLE_FILES = {}; 
+    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
+    NEXTSTEP_BUILDDIR = /tmp/developer_cmds/Build; 
+    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
+    NEXTSTEP_INSTALLDIR = /usr/bin; 
+    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
+    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
+    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
+    PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; 
+    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
+    PROJECTNAME = chflags; 
+    PROJECTTYPE = Tool; 
+    PROJECTVERSION = 2.8; 
+    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
+    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
+    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
+}
diff --git a/chflags/chflags.1 b/chflags/chflags.1
new file mode 100644
index 0000000..c7ab4bc
--- /dev/null
+++ b/chflags/chflags.1
@@ -0,0 +1,126 @@
+.\"	$NetBSD: chflags.1,v 1.6 1997/10/18 12:39:50 lukem Exp $
+.\"
+.\" Copyright (c) 1989, 1990, 1993, 1994
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)chflags.1	8.4 (Berkeley) 5/2/95
+.\"
+.Dd May 2, 1995
+.Dt CHFLAGS 1
+.Os
+.Sh NAME
+.Nm chflags
+.Nd change file flags
+.Sh SYNOPSIS
+.Nm
+.Oo
+.Fl R
+.Op Fl H | Fl L | Fl P
+.Oc
+.Ar flags
+.Ar file ...
+.Sh DESCRIPTION
+The
+.Nm
+utility modifies the file flags of the listed files
+as specified by the
+.Ar flags
+operand.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl H
+If the
+.Fl R
+option is specified, symbolic links on the command line are followed.
+(Symbolic links encountered in the tree traversal are not followed.)
+.It Fl L
+If the
+.Fl R
+option is specified, all symbolic links are followed.
+.It Fl P
+If the
+.Fl R
+option is specified, no symbolic links are followed.
+.It Fl R
+Change the file flags for the file hierarchies rooted
+in the files instead of just the files themselves.
+.El
+.Pp
+Flags are a comma separated list of keywords.
+The following keywords are currently defined:
+.Bd -literal -offset indent compact
+arch	set the archived flag (super-user only)
+opaque	set the opaque flag (owner or super-user only)
+nodump	set the nodump flag (owner or super-user only)
+sappnd	set the system append-only flag (super-user only)
+schg	set the system immutable flag (super-user only)
+uappnd	set the user append-only flag (owner or super-user only)
+uchg	set the user immutable flag (owner or super-user only)
+.Ed
+.Pp
+Putting the letters
+.Dq no
+before an option causes the flag to be turned off.
+For example:
+.Bd -literal -offset indent compact
+nouchg	the immutable bit should be cleared
+.Ed
+.Pp
+Symbolic links do not have flags, so unless the
+.Fl H
+or
+.Fl L
+option is set,
+.Nm
+on a symbolic link always succeeds and has no effect.
+The
+.Fl H ,
+.Fl L
+and
+.Fl P
+options are ignored unless the
+.Fl R
+option is specified.
+In addition, these options override each other and the
+command's actions are determined by the last one specified.
+.Pp
+The
+.Nm
+utility exits 0 on success, and >0 if an error occurs.
+.Sh SEE ALSO
+.Xr chflags 2 ,
+.Xr stat 2 ,
+.Xr fts 3 ,
+.Xr symlink 7
diff --git a/chflags/chflags.c b/chflags/chflags.c
new file mode 100644
index 0000000..54d1bc3
--- /dev/null
+++ b/chflags/chflags.c
@@ -0,0 +1,187 @@
+/*	$NetBSD: chflags.c,v 1.5 1997/10/18 12:39:54 lukem Exp $	*/
+
+/*
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1992, 1993, 1994\n\
+	The Regents of the University of California.  All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "from: @(#)chflags.c	8.5 (Berkeley) 4/1/94";
+#else
+__RCSID("$NetBSD: chflags.c,v 1.5 1997/10/18 12:39:54 lukem Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int	main __P((int, char **));
+u_long	string_to_flags __P((char **, u_long *, u_long *));
+void	usage __P((void));
+
+int
+main(argc, argv)
+	int argc;
+	char *argv[];
+{
+	FTS *ftsp;
+	FTSENT *p;
+	u_long clear, set;
+	long val;
+	int Hflag, Lflag, Pflag, Rflag, ch, fts_options, oct, rval;
+	char *flags, *ep;
+
+	Hflag = Lflag = Pflag = Rflag = 0;
+	while ((ch = getopt(argc, argv, "HLPR")) != -1)
+		switch (ch) {
+		case 'H':
+			Hflag = 1;
+			Lflag = Pflag = 0;
+			break;
+		case 'L':
+			Lflag = 1;
+			Hflag = Pflag = 0;
+			break;
+		case 'P':
+			Pflag = 1;
+			Hflag = Lflag = 0;
+			break;
+		case 'R':
+			Rflag = 1;
+			break;
+		case '?':
+		default:
+			usage();
+		}
+	argv += optind;
+	argc -= optind;
+
+	if (argc < 2)
+		usage();
+
+	fts_options = FTS_PHYSICAL;
+	if (Rflag) {
+		if (Hflag)
+			fts_options |= FTS_COMFOLLOW;
+		if (Lflag) {
+			fts_options &= ~FTS_PHYSICAL;
+			fts_options |= FTS_LOGICAL;
+		}
+	}
+
+	flags = *argv;
+	if (*flags >= '0' && *flags <= '7') {
+		errno = 0;
+		val = strtol(flags, &ep, 8);
+		if (val < 0)
+			errno = ERANGE;
+		if (errno)
+                        err(1, "invalid flags: %s", flags);
+                if (*ep)
+                        errx(1, "invalid flags: %s", flags);
+		set = val;
+                oct = 1;
+	} else {
+		if (string_to_flags(&flags, &set, &clear))
+                        errx(1, "invalid flag: %s", flags);
+		clear = ~clear;
+		oct = 0;
+	}
+
+	if ((ftsp = fts_open(++argv, fts_options , 0)) == NULL)
+		err(1, "fts_open `%s'", argv[0]); 
+
+	for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
+		switch (p->fts_info) {
+		case FTS_D:
+			if (Rflag)		/* Change it at FTS_DP. */
+				continue;
+			fts_set(ftsp, p, FTS_SKIP);
+			break;
+		case FTS_DNR:			/* Warn, chflag, continue. */
+			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
+			rval = 1;
+			break;
+		case FTS_ERR:			/* Warn, continue. */
+		case FTS_NS:
+			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
+			rval = 1;
+			continue;
+		case FTS_SL:			/* Ignore. */
+		case FTS_SLNONE:
+			/*
+			 * The only symlinks that end up here are ones that
+			 * don't point to anything and ones that we found
+			 * doing a physical walk.
+			 */
+			continue;
+		default:
+			break;
+		}
+		if (oct) {
+			if (!chflags(p->fts_accpath, set))
+				continue;
+		} else {
+			p->fts_statp->st_flags |= set;
+			p->fts_statp->st_flags &= clear;
+			if (!chflags(p->fts_accpath, p->fts_statp->st_flags))
+				continue;
+		}
+		warn("%s", p->fts_path);
+		rval = 1;
+	}
+	if (errno)
+		err(1, "fts_read");
+	exit(rval);
+}
+
+void
+usage()
+{
+	(void)fprintf(stderr,
+	    "usage: chflags [-R [-H | -L | -P]] flags file ...\n");
+	exit(1);
+}
diff --git a/chmod/Makefile b/chmod/Makefile
new file mode 100644
index 0000000..34a6a63
--- /dev/null
+++ b/chmod/Makefile
@@ -0,0 +1,48 @@
+#
+# Generated by the NeXT Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = chmod
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+CFILES = chmod.c
+
+OTHERSRCS = Makefile Makefile.preamble Makefile.postamble chmod.1
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /bin
+LIBS = 
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+
+
+NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/$(NAME)/Build
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
diff --git a/chmod/Makefile.postamble b/chmod/Makefile.postamble
new file mode 100644
index 0000000..013b558
--- /dev/null
+++ b/chmod/Makefile.postamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
diff --git a/chmod/Makefile.preamble b/chmod/Makefile.preamble
new file mode 100644
index 0000000..9e10e90
--- /dev/null
+++ b/chmod/Makefile.preamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
diff --git a/chmod/PB.project b/chmod/PB.project
new file mode 100644
index 0000000..644371e
--- /dev/null
+++ b/chmod/PB.project
@@ -0,0 +1,25 @@
+{
+    DYNAMIC_CODE_GEN = YES; 
+    FILESTABLE = {
+        FRAMEWORKS = (); 
+        OTHER_LINKED = (chmod.c); 
+        OTHER_SOURCES = (Makefile, Makefile.preamble, Makefile.postamble, chmod.1); 
+    }; 
+    LANGUAGE = English; 
+    LOCALIZABLE_FILES = {}; 
+    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
+    NEXTSTEP_BUILDDIR = "/tmp/$(NAME)/Build"; 
+    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
+    NEXTSTEP_INSTALLDIR = /bin; 
+    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
+    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
+    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
+    PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; 
+    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
+    PROJECTNAME = chmod; 
+    PROJECTTYPE = Tool; 
+    PROJECTVERSION = 2.8; 
+    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
+    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
+    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
+}
diff --git a/chmod/chmod.1 b/chmod/chmod.1
new file mode 100644
index 0000000..6a52eb6
--- /dev/null
+++ b/chmod/chmod.1
@@ -0,0 +1,306 @@
+.\"	$NetBSD: chmod.1,v 1.11 1997/10/20 08:51:10 enami Exp $
+.\"
+.\" Copyright (c) 1989, 1990, 1993, 1994
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)chmod.1	8.4 (Berkeley) 3/31/94
+.\"
+.Dd March 31, 1994
+.Dt CHMOD 1
+.Os
+.Sh NAME
+.Nm chmod
+.Nd change file modes
+.Sh SYNOPSIS
+.Nm
+.Oo
+.Fl R
+.Op Fl H | Fl L | Fl P
+.Oc
+.Op Fl h
+.Ar mode
+.Ar file ...
+.Sh DESCRIPTION
+The
+.Nm
+utility modifies the file mode bits of the listed files
+as specified by the
+.Ar mode
+operand.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl H
+If the
+.Fl R
+option is specified, symbolic links on the command line are followed.
+(Symbolic links encountered in the tree traversal are not followed.)
+.It Fl L
+If the
+.Fl R
+option is specified, all symbolic links are followed.
+.It Fl P
+If the
+.Fl R
+option is specified, no symbolic links are followed.
+.It Fl R
+Change the modes of the file hierarchies rooted in the files
+instead of just the files themselves.
+.\" .It Fl h
+.\" If
+.\" .Ar file
+.\" is symbolic link, the mode of the link is changed.
+.El
+.Pp
+.\" If the option
+.\" .Fl h
+.\" is not given,
+Unless the
+.Fl H
+or
+.Fl L
+option is set,
+.Nm
+on a symbolic link always succeeds and has no effect.
+The
+.Fl H ,
+.Fl L
+and
+.Fl P
+options are ignored unless the
+.Fl R
+option is specified.
+In addition, these options override each other and the
+command's actions are determined by the last one specified.
+.Pp
+Only the owner of a file or the super-user is permitted to change
+the mode of a file.
+.Pp
+The
+.Nm
+utility exits 0 on success, and >0 if an error occurs.
+.Sh MODES
+Modes may be absolute or symbolic.
+An absolute mode is an octal number constructed by
+.Ar or-ing
+the following values:
+.Pp
+.Bl -tag -width 6n -compact -offset indent
+.It Li 4000
+set-user-ID-on-execution
+.It Li 2000
+set-group-ID-on-execution
+.It Li 1000
+sticky bit, see
+.Xr chmod 2
+.It Li 0400
+read by owner
+.It Li 0200
+write by owner
+.It Li 0100
+execute (or search for directories) by owner
+.It Li 0070
+read, write, execute/search by group
+.It Li 0007
+read, write, execute/search by others
+.El
+.Pp
+The read, write, and execute/search values for group and others
+are encoded as described for owner.
+.Pp
+The symbolic mode is described by the following grammar:
+.Bd -literal -offset indent
+mode         ::= clause [, clause ...]
+clause       ::= [who ...] [action ...] last_action
+action       ::= op [perm ...]
+last_action  ::= op [perm ...]
+who          ::= a | u | g | o
+op           ::= + | \- | =
+perm         ::= r | s | t | w | x | X | u | g | o
+.Ed
+.Pp
+The
+.Ar who
+symbols ``u'', ``g'', and ``o'' specify the user, group, and other parts
+of the mode bits, respectively.
+The
+.Ar who
+symbol ``a'' is equivalent to ``ugo''.
+.Pp
+.ne 1i
+The
+.Ar perm
+symbols represent the portions of the mode bits as follows:
+.Pp
+.Bl -tag -width Ds -compact -offset indent
+.It r
+The read bits.
+.It s
+The set-user-ID-on-execution and set-group-ID-on-execution bits.
+.It t
+The sticky bit.
+.It w
+The write bits.
+.It x
+The execute/search bits.
+.It X
+The execute/search bits if the file is a directory or any of the
+execute/search bits are set in the original (unmodified) mode.
+Operations with the
+.Ar perm
+symbol ``X'' are only meaningful in conjunction with the
+.Ar op
+symbol ``+'', and are ignored in all other cases.
+.It u
+The user permission bits in the mode of the original file.
+.It g
+The group permission bits in the mode of the original file.
+.It o
+The other permission bits in the mode of the original file.
+.El
+.Pp
+The
+.Ar op
+symbols represent the operation performed, as follows:
+.Bl -tag -width 4n
+.It +
+If no value is supplied for
+.Ar perm ,
+the ``+'' operation has no effect.
+If no value is supplied for
+.Ar who ,
+each permission bit specified in
+.Ar perm ,
+for which the corresponding bit in the file mode creation mask
+is clear, is set.
+Otherwise, the mode bits represented by the specified
+.Ar who
+and
+.Ar perm
+values are set.
+.It \&\-
+If no value is supplied for
+.Ar perm ,
+the ``\-'' operation has no effect.
+If no value is supplied for
+.Ar who ,
+each permission bit specified in
+.Ar perm ,
+for which the corresponding bit in the file mode creation mask
+is clear, is cleared.
+Otherwise, the mode bits represented by the specified
+.Ar who
+and
+.Ar perm
+values are cleared.
+.It =
+The mode bits specified by the
+.Ar who
+value are cleared, or, if no who value is specified, the owner, group
+and other mode bits are cleared.
+Then, if no value is supplied for
+.Ar who ,
+each permission bit specified in
+.Ar perm ,
+for which the corresponding bit in the file mode creation mask
+is clear, is set.
+Otherwise, the mode bits represented by the specified
+.Ar who
+and
+.Ar perm
+values are set.
+.El
+.Pp
+Each
+.Ar clause
+specifies one or more operations to be performed on the mode
+bits, and each operation is applied to the mode bits in the
+order specified.
+.Pp
+Operations upon the other permissions only (specified by the symbol
+``o'' by itself), in combination with the
+.Ar perm
+symbols ``s'' or ``t'', are ignored.
+.Sh EXAMPLES
+.Bl -tag -width "u=rwx,go=u-w" -compact
+.It Li 644
+make a file readable by anyone and writable by the owner only.
+.Pp
+.It Li go-w
+deny write permission to group and others.
+.Pp
+.It Li =rw,+X
+set the read and write permissions to the usual defaults, but
+retain any execute permissions that are currently set.
+.Pp
+.It Li +X
+make a directory or file searchable/executable by everyone if it is
+already searchable/executable by anyone.
+.Pp
+.It Li 755
+.It Li u=rwx,go=rx
+.It Li u=rwx,go=u-w
+make a file readable/executable by everyone and writable by the owner only.
+.Pp
+.It Li go=
+clear all mode bits for group and others.
+.Pp
+.It Li g=u-w
+set the group bits equal to the user bits, but clear the group write bit.
+.El
+.Sh BUGS
+There's no
+.Ar perm
+option for the naughty bits.
+.Sh SEE ALSO
+.Xr install 1 ,
+.Xr chmod 2 ,
+.Xr stat 2 ,
+.Xr umask 2 ,
+.Xr fts 3 ,
+.Xr setmode 3 ,
+.Xr symlink 7 ,
+.Xr chown 8
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be
+.St -p1003.2
+compatible with the exception of the
+.Ar perm
+symbols
+.Dq t
+and
+.Dq X
+which are not included in that standard.
diff --git a/chmod/chmod.c b/chmod/chmod.c
new file mode 100644
index 0000000..4dae785
--- /dev/null
+++ b/chmod/chmod.c
@@ -0,0 +1,242 @@
+/*	$NetBSD: chmod.c,v 1.20 1998/07/28 05:31:22 mycroft Exp $	*/
+
+/*
+ * Copyright (c) 1989, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT(
+"@(#) Copyright (c) 1989, 1993, 1994\n\
+	The Regents of the University of California.  All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)chmod.c	8.8 (Berkeley) 4/1/94";
+#else
+__RCSID("$NetBSD: chmod.c,v 1.20 1998/07/28 05:31:22 mycroft Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+
+int main __P((int, char *[]));
+void usage __P((void));
+
+int
+main(argc, argv)
+	int argc;
+	char *argv[];
+{
+	FTS *ftsp;
+	FTSENT *p;
+	mode_t *set;
+	long val;
+	int oct, omode;
+	int Hflag, Lflag, Rflag, ch, fflag, fts_options, hflag, rval;
+	char *ep, *mode;
+	int (*change_mode) __P((const char *, mode_t));
+
+	set = NULL;	/* XXX gcc -Wuninitialized */
+	omode = 0;	/* XXX gcc -Wuninitialized */
+
+	(void)setlocale(LC_ALL, "");
+
+	Hflag = Lflag = Rflag = fflag = hflag = 0;
+	while ((ch = getopt(argc, argv, "HLPRXfghorstuwx")) != -1)
+		switch (ch) {
+		case 'H':
+			Hflag = 1;
+			Lflag = 0;
+			break;
+		case 'L':
+			Lflag = 1;
+			Hflag = 0;
+			break;
+		case 'P':
+			Hflag = Lflag = 0;
+			break;
+		case 'R':
+			Rflag = 1;
+			break;
+		case 'f':		/* XXX: undocumented. */
+			fflag = 1;
+			break;
+#ifndef __APPLE__
+		case 'h':
+			/*
+			 * In System V (and probably POSIX.2) the -h option
+			 * causes chmod to change the mode of the symbolic
+			 * link.  4.4BSD's symbolic links didn't have modes,
+			 * so it was an undocumented noop.  In NetBSD 1.3,
+			 * lchmod(2) is introduced and this option does real
+			 * work.
+			 */
+			hflag = 1;
+			break;
+#endif
+		/*
+		 * XXX
+		 * "-[rwx]" are valid mode commands.  If they are the entire
+		 * argument, getopt has moved past them, so decrement optind.
+		 * Regardless, we're done argument processing.
+		 */
+		case 'g': case 'o': case 'r': case 's':
+		case 't': case 'u': case 'w': case 'X': case 'x':
+			if (argv[optind - 1][0] == '-' &&
+			    argv[optind - 1][1] == ch &&
+			    argv[optind - 1][2] == '\0')
+				--optind;
+			goto done;
+		case '?':
+		default:
+			usage();
+		}
+done:	argv += optind;
+	argc -= optind;
+
+	if (argc < 2)
+		usage();
+
+	fts_options = FTS_PHYSICAL;
+	if (Rflag) {
+		if (hflag)
+			errx(1,
+		"the -R and -h options may not be specified together.");
+		if (Hflag)
+			fts_options |= FTS_COMFOLLOW;
+		if (Lflag) {
+			fts_options &= ~FTS_PHYSICAL;
+			fts_options |= FTS_LOGICAL;
+		}
+	}
+#ifndef __APPLE__
+	if (hflag)
+		change_mode = lchmod;
+	else
+            change_mode = chmod;
+#else
+        change_mode = chmod;
+#endif
+
+	mode = *argv;
+	if (*mode >= '0' && *mode <= '7') {
+		errno = 0;
+		val = strtol(mode, &ep, 8);
+		if (val > INT_MAX || val < 0)
+			errno = ERANGE;
+		if (errno)
+			err(1, "invalid file mode: %s", mode);
+		if (*ep)
+			errx(1, "invalid file mode: %s", mode);
+		omode = val;
+		oct = 1;
+	} else {
+		if ((set = setmode(mode)) == NULL)
+			errx(1, "invalid file mode: %s", mode);
+		oct = 0;
+	}
+
+	if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL)
+		err(1, argv[0]);
+	for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
+		switch (p->fts_info) {
+		case FTS_D:
+			if (!Rflag)
+				(void)fts_set(ftsp, p, FTS_SKIP);
+			break;
+		case FTS_DNR:			/* Warn, chmod, continue. */
+			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
+			rval = 1;
+			break;
+		case FTS_DP:			/* Already changed at FTS_D. */
+			continue;
+		case FTS_ERR:			/* Warn, continue. */
+		case FTS_NS:
+			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
+			rval = 1;
+			continue;
+		case FTS_SL:			/* Ignore. */
+		case FTS_SLNONE:
+			/*
+			 * The only symlinks that end up here are ones that
+			 * don't point to anything and ones that we found
+			 * doing a physical walk.
+			 */
+#ifndef __APPLE__
+			if (!hflag)
+				continue;
+			/* else */
+			/* FALLTHROUGH */
+#else
+			continue;
+#endif
+		default:
+			break;
+		}
+		if ((*change_mode)(p->fts_accpath, oct ? omode :
+		    getmode(set, p->fts_statp->st_mode)) && !fflag) {
+			warn("%s", p->fts_path);
+			rval = 1;
+		}
+	}
+	if (errno)
+		err(1, "fts_read");
+	exit(rval);
+	/* NOTREACHED */
+}
+
+void
+usage()
+{
+#ifndef __APPLE__
+	(void)fprintf(stderr,
+	    "usage: chmod [-R [-H | -L | -P]] [-h] mode file ...\n");
+#else
+	(void)fprintf(stderr,
+	    "usage: chmod [-R [-H | -L | -P]] mode file ...\n");
+#endif
+	exit(1);
+	/* NOTREACHED */
+}
diff --git a/chown/Makefile b/chown/Makefile
new file mode 100644
index 0000000..eb0029c
--- /dev/null
+++ b/chown/Makefile
@@ -0,0 +1,50 @@
+#
+# Generated by the NeXT Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = chown
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+CFILES = chown.c
+
+OTHERSRCS = Makefile Makefile.preamble Makefile.postamble chgrp.1\
+            chown.8
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /usr/sbin
+LIBS = 
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+NEXTSTEP_PB_CFLAGS = -DSUPPORT_DOT
+
+
+NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/$(NAME)/Build
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
diff --git a/chown/Makefile.postamble b/chown/Makefile.postamble
new file mode 100644
index 0000000..4da9b62
--- /dev/null
+++ b/chown/Makefile.postamble
@@ -0,0 +1,4 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
+
+after_install::
+	$(LINKPRODUCT) $(DSTROOT)/usr/bin/chgrp
diff --git a/chown/Makefile.preamble b/chown/Makefile.preamble
new file mode 100644
index 0000000..9e10e90
--- /dev/null
+++ b/chown/Makefile.preamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
diff --git a/chown/PB.project b/chown/PB.project
new file mode 100644
index 0000000..d716382
--- /dev/null
+++ b/chown/PB.project
@@ -0,0 +1,26 @@
+{
+    DYNAMIC_CODE_GEN = YES; 
+    FILESTABLE = {
+        FRAMEWORKS = (); 
+        OTHER_LINKED = (chown.c); 
+        OTHER_SOURCES = (Makefile, Makefile.preamble, Makefile.postamble, chgrp.1, chown.8); 
+    }; 
+    LANGUAGE = English; 
+    LOCALIZABLE_FILES = {}; 
+    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
+    NEXTSTEP_BUILDDIR = "/tmp/$(NAME)/Build"; 
+    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
+    NEXTSTEP_COMPILEROPTIONS = "-DSUPPORT_DOT"; 
+    NEXTSTEP_INSTALLDIR = /usr/sbin; 
+    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
+    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
+    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
+    PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; 
+    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
+    PROJECTNAME = chown; 
+    PROJECTTYPE = Tool; 
+    PROJECTVERSION = 2.8; 
+    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
+    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
+    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
+}
diff --git a/chown/chgrp.1 b/chown/chgrp.1
new file mode 100644
index 0000000..379a94d
--- /dev/null
+++ b/chown/chgrp.1
@@ -0,0 +1,146 @@
+.\" Copyright (c) 1983, 1990, 1993, 1994
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     from: @(#)chgrp.1	8.3 (Berkeley) 3/31/94
+.\"	$NetBSD: chgrp.1,v 1.10 1997/12/21 18:11:19 kleink Exp $
+.\"
+.Dd March 31, 1994
+.Dt CHGRP 1
+.Os BSD 4.2
+.Sh NAME
+.Nm chgrp
+.Nd change group
+.Sh SYNOPSIS
+.Nm
+.Oo
+.Fl R
+.Op Fl H | Fl L | Fl P
+.Oc
+.Op Fl fh
+.Ar group
+.Ar files ...
+.Sh DESCRIPTION
+The
+.Nm
+utility sets the group ID of the file named by each
+.Ar file
+operand to the
+.Ar group
+ID specified by the group operand.
+.Pp
+Options:
+.Bl -tag -width Ds
+.It Fl H
+If the
+.Fl R
+option is specified, symbolic links on the command line are followed.
+(Symbolic links encountered in the tree traversal are not followed.)
+.It Fl L
+If the
+.Fl R
+option is specified, all symbolic links are followed.
+.It Fl P
+If the
+.Fl R
+option is specified, no symbolic links are followed.
+.It Fl R
+Change the group ID for the file hierarchies rooted
+in the files instead of just the files themselves.
+.It Fl f
+The force option ignores errors, except for usage errors and doesn't
+query about strange modes (unless the user does not have proper permissions).
+.It Fl h
+If
+.Ar file
+is a symbolic link, the group of the link is changed.
+.El
+.Pp
+If
+.Fl h
+is not given, unless the 
+.Fl H
+or
+.Fl L
+option is set,
+.Nm
+on a symbolic link always succeeds and has no effect.
+The
+.Fl H ,
+.Fl L
+and
+.Fl P
+options are ignored unless the
+.Fl R
+option is specified.
+In addition, these options override each other and the
+command's actions are determined by the last one specified.
+.Pp
+The
+.Ar group
+operand can be either a group name from the group database,
+or a numeric group ID.
+If a group name is also a numeric group ID, the operand is used as a
+group name.
+.Pp
+The user invoking
+.Nm
+must belong to the specified group and be the owner of the file,
+or be the super-user.
+.Pp
+Unless invoked by the super-user,
+.Nm
+clears the set-user-id and set-group-id bits on a file to prevent
+accidental or mischievous creation of set-user-id or set-group-id
+programs.
+.Pp
+The
+.Nm
+utility exits 0 on success, and >0 if an error occurs.
+.Sh FILES
+.Bl -tag -width /etc/group -compact
+.It Pa /etc/group
+Group ID file
+.El
+.Sh SEE ALSO
+.Xr chown 2 ,
+.Xr lchown 2 ,
+.Xr fts 3 ,
+.Xr group 5 ,
+.Xr passwd 5 ,
+.Xr symlink 7 ,
+.Xr chown 8
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be POSIX 1003.2 compatible.
diff --git a/chown/chown.8 b/chown/chown.8
new file mode 100644
index 0000000..6e8065e
--- /dev/null
+++ b/chown/chown.8
@@ -0,0 +1,154 @@
+.\" Copyright (c) 1990, 1991, 1993, 1994
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     from: @(#)chown.8	8.3 (Berkeley) 3/31/94
+.\"	$NetBSD: chown.8,v 1.11 1998/10/05 21:37:38 kim Exp $
+.\"
+.Dd March 31, 1994
+.Dt CHOWN 8
+.Os BSD 4
+.Sh NAME
+.Nm chown
+.Nd change file owner and group
+.Sh SYNOPSIS
+.Nm
+.Oo
+.Fl R
+.Op Fl H | Fl L | Fl P
+.Oc
+.Op Fl fh
+.Ar owner Op Ar :group
+.Ar file ...
+.Nm ""
+.Oo
+.Fl R
+.Op Fl H | Fl L | Fl P
+.Oc
+.Op Fl fh
+.Ar :group
+.Ar file ...
+.Sh DESCRIPTION
+.Nm
+sets the user ID and/or the group ID of the specified files.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl H
+If the
+.Fl R
+option is specified, symbolic links on the command line are followed.
+(Symbolic links encountered in the tree traversal are not followed.)
+.It Fl L
+If the
+.Fl R
+option is specified, all symbolic links are followed.
+.It Fl P
+If the
+.Fl R
+option is specified, no symbolic links are followed.
+.It Fl R
+Change the user ID and/or the group ID for the file hierarchies rooted
+in the files instead of just the files themselves.
+.It Fl f
+Don't report any failure to change file owner or group, nor modify
+the exit status to reflect such failures.
+.It Fl h
+If
+.Ar file
+is a symbolic link, the owner and/or group of the link is changed.
+.El
+.Pp
+The
+.Fl H ,
+.Fl L
+and
+.Fl P
+options are ignored unless the
+.Fl R
+option is specified.
+In addition, these options override each other and the
+command's actions are determined by the last one specified.
+.Pp
+The
+.Fl L
+option cannot be used together with the
+.Fl h
+option.
+.Pp
+The
+.Ar owner
+and
+.Ar group
+operands are both optional, however, one must be specified.
+If the
+.Ar group
+operand is specified, it must be preceded by a colon (``:'') character.
+.Pp
+The
+.Ar owner
+may be either a numeric user ID or a user name.
+If a user name is also a numeric user ID, the operand is used as a
+user name.
+The
+.Ar group
+may be either a numeric group ID or a group name.
+If a group name is also a numeric group ID, the operand is used as a
+group name.
+.Pp
+The ownership of a file may only be altered by a super-user for
+obvious security reasons.
+.Pp
+Unless invoked by the super-user,
+.Nm
+clears the set-user-id and set-group-id bits on a file to prevent
+accidental or mischievous creation of set-user-id and set-group-id
+programs.
+.Pp
+The
+.Nm
+utility exits 0 on success, and >0 if an error occurs.
+.Sh COMPATIBILITY
+Previous versions of the
+.Nm
+utility used the dot (``.'') character to distinguish the group name.
+This has been changed to be a colon (``:'') character so that user and
+group names may contain the dot character.
+.Sh SEE ALSO
+.Xr chgrp 1 ,
+.Xr find 1 ,
+.Xr chown 2 ,
+.Xr lchown 2 ,
+.Xr fts 3 ,
+.Xr symlink 7
+.Sh STANDARDS
+The
+.Nm
+command is expected to be POSIX 1003.2 compliant.
diff --git a/chown/chown.c b/chown/chown.c
new file mode 100644
index 0000000..c2dcdad
--- /dev/null
+++ b/chown/chown.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 1988, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994\n\
+	The Regents of the University of California.  All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)chown.c	8.8 (Berkeley) 4/4/94";
+#else
+__RCSID("$NetBSD: chown.c,v 1.15 1998/10/05 21:37:39 kim Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <locale.h>
+#include <fts.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+void	a_gid __P((char *));
+void	a_uid __P((char *));
+void	chownerr __P((char *));
+u_long	id __P((char *, char *));
+int	main __P((int, char **));
+void	usage __P((void));
+
+uid_t uid;
+gid_t gid;
+int Rflag, ischown, fflag;
+char *gname, *myname;
+
+int
+main(argc, argv)
+	int argc;
+	char *argv[];
+{
+	FTS *ftsp;
+	FTSENT *p;
+	int Hflag, Lflag, Pflag, ch, fts_options, hflag, rval;
+	char *cp;
+	int (*change_owner) __P((const char *, uid_t, gid_t));
+	
+	setlocale(LC_ALL, "");
+
+	myname = (cp = strrchr(*argv, '/')) ? cp + 1 : *argv;
+	ischown = myname[2] == 'o';
+	
+	Hflag = Lflag = Pflag = hflag = 0;
+	while ((ch = getopt(argc, argv, "HLPRfh")) != -1)
+		switch (ch) {
+		case 'H':
+			Hflag = 1;
+			Lflag = Pflag = 0;
+			break;
+		case 'L':
+			Lflag = 1;
+			Hflag = Pflag = 0;
+			break;
+		case 'P':
+			Pflag = 1;
+			Hflag = Lflag = 0;
+			break;
+		case 'R':
+			Rflag = 1;
+			break;
+		case 'f':
+			fflag = 1;
+			break;
+		case 'h':
+			/*
+			 * In System V the -h option causes chown/chgrp to
+			 * change the owner/group of the symbolic link.
+			 * 4.4BSD's symbolic links didn't have owners/groups,
+			 * so it was an undocumented noop.
+			 * In NetBSD 1.3, lchown(2) is introduced.
+			 */
+			hflag = 1;
+			break;
+		case '?':
+		default:
+			usage();
+		}
+	argv += optind;
+	argc -= optind;
+
+	if (argc < 2)
+		usage();
+
+	fts_options = FTS_PHYSICAL;
+	if (Rflag) {
+		if (Hflag)
+			fts_options |= FTS_COMFOLLOW;
+		if (Lflag) {
+			if (hflag)
+				errx(1, "the -L and -h options may not be specified together.");
+			fts_options &= ~FTS_PHYSICAL;
+			fts_options |= FTS_LOGICAL;
+		}
+	}
+#ifndef __APPLE__
+        if (hflag)
+		change_owner = lchown;
+	else
+            change_owner = chown;
+#else
+        change_owner = chown;
+#endif
+
+	uid = gid = -1;
+	if (ischown) {
+#ifdef SUPPORT_DOT
+		if ((cp = strchr(*argv, '.')) != NULL) {
+			*cp++ = '\0';
+			a_gid(cp);
+		} else
+#endif
+		if ((cp = strchr(*argv, ':')) != NULL) {
+			*cp++ = '\0';
+			a_gid(cp);
+		} 
+		a_uid(*argv);
+	} else 
+		a_gid(*argv);
+
+	if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL)
+		err(1, "%s", "");
+
+	for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
+		switch (p->fts_info) {
+		case FTS_D:
+			if (!Rflag)		/* Change it at FTS_DP. */
+				fts_set(ftsp, p, FTS_SKIP);
+			continue;
+		case FTS_DNR:			/* Warn, chown, continue. */
+			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
+			rval = 1;
+			break;
+		case FTS_ERR:			/* Warn, continue. */
+		case FTS_NS:
+			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
+			rval = 1;
+			continue;
+		case FTS_SL:			/* Ignore. */
+		case FTS_SLNONE:
+			/*
+			 * The only symlinks that end up here are ones that
+			 * don't point to anything and ones that we found
+			 * doing a physical walk.
+			 */
+#ifndef __APPLE__
+                    if (!hflag)
+                        continue;
+#else
+                    continue;
+#endif
+                        /* else */
+			/* FALLTHROUGH */
+		default:
+			break;
+		}
+
+		if ((*change_owner)(p->fts_accpath, uid, gid) && !fflag) {
+			warn("%s", p->fts_path);
+			rval = 1;
+		}
+	}
+	if (errno)
+		err(1, "fts_read");
+	exit(rval);
+}
+
+void
+a_gid(s)
+	char *s;
+{
+	struct group *gr;
+
+	if (*s == '\0')			/* Argument was "uid[:.]". */
+		return;
+	gname = s;
+	gid = ((gr = getgrnam(s)) == NULL) ? id(s, "group") : gr->gr_gid;
+}
+
+void
+a_uid(s)
+	char *s;
+{
+	struct passwd *pw;
+
+	if (*s == '\0')			/* Argument was "[:.]gid". */
+		return;
+	uid = ((pw = getpwnam(s)) == NULL) ? id(s, "user") : pw->pw_uid;
+}
+
+u_long
+id(name, type)
+	char *name, *type;
+{
+	u_long val;
+	char *ep;
+
+	/*
+	 * XXX
+	 * We know that uid_t's and gid_t's are unsigned longs.
+	 */
+	errno = 0;
+	val = strtoul(name, &ep, 10);
+	if (errno)
+		err(1, "%s", name);
+	if (*ep != '\0')
+		errx(1, "%s: invalid %s name", name, type);
+	return (val);
+}
+
+void
+usage()
+{
+	(void)fprintf(stderr,
+	    "usage: %s [-R [-H | -L | -P]] [-fh] %s file ...\n",
+	    myname, ischown ? "[owner][:group]" : "group");
+	exit(1);
+}
diff --git a/cksum/crc.c b/cksum/crc.c
new file mode 100644
index 0000000..ac889d6
--- /dev/null
+++ b/cksum/crc.c
@@ -0,0 +1,149 @@
+/*	$NetBSD: crc.c,v 1.8 1997/10/17 11:37:03 lukem Exp $	*/
+
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * James W. Williams of NASA Goddard Space Flight Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)crc.c	8.1 (Berkeley) 6/17/93";
+#else
+__RCSID("$NetBSD: crc.c,v 1.8 1997/10/17 11:37:03 lukem Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+static const u_int32_t crctab[] = {
+	0x0,
+	0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
+	0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6,
+	0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
+	0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac,
+	0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f,
+	0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a,
+	0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
+	0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58,
+	0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033,
+	0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe,
+	0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
+	0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4,
+	0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
+	0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5,
+	0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
+	0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07,
+	0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c,
+	0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1,
+	0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+	0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b,
+	0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698,
+	0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d,
+	0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
+	0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f,
+	0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
+	0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80,
+	0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
+	0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a,
+	0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629,
+	0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c,
+	0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
+	0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e,
+	0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65,
+	0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8,
+	0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
+	0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2,
+	0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
+	0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74,
+	0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
+	0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21,
+	0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a,
+	0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087,
+	0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
+	0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d,
+	0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce,
+	0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb,
+	0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
+	0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09,
+	0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
+	0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf,
+	0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
+};
+
+/*
+ * Compute a POSIX 1003.2 checksum.  This routine has been broken out so that
+ * other programs can use it.  It takes a file descriptor to read from and
+ * locations to store the crc and the number of bytes read.  It returns 0 on
+ * success and 1 on failure.  Errno is set on failure.
+ */
+u_int32_t crc_total = ~0;		/* The crc over a number of files. */
+
+int
+crc(fd, cval, clen)
+	register int fd;
+	u_int32_t *cval, *clen;
+{
+	register u_char *p;
+	register int nr;
+	register u_int32_t crc, len;
+	u_char buf[16 * 1024];
+
+#define	COMPUTE(var, ch)	(var) = (var) << 8 ^ crctab[(var) >> 24 ^ (ch)]
+
+	crc = len = 0;
+	crc_total = ~crc_total;
+	while ((nr = read(fd, buf, sizeof(buf))) > 0)
+		for (len += nr, p = buf; nr--; ++p) {
+			COMPUTE(crc, *p);
+			COMPUTE(crc_total, *p);
+		}
+	if (nr < 0)
+		return (1);
+
+	*clen = len;
+
+	/* Include the length of the file. */
+	for (; len != 0; len >>= 8) {
+		COMPUTE(crc, len & 0xff);
+		COMPUTE(crc_total, len & 0xff);
+	}
+
+	*cval = ~crc;
+	crc_total = ~crc_total;
+	return (0);
+}
diff --git a/compress/Makefile b/compress/Makefile
new file mode 100644
index 0000000..0c13072
--- /dev/null
+++ b/compress/Makefile
@@ -0,0 +1,49 @@
+#
+# Generated by the NeXT Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = compress
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+CFILES = compress.c zopen.c
+
+OTHERSRCS = Makefile Makefile.preamble Makefile.postamble compress.1\
+            zopen.3 uncompress.1
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /usr/bin
+LIBS = 
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+
+
+NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/developer_cmds/Build
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
diff --git a/compress/Makefile.postamble b/compress/Makefile.postamble
new file mode 100644
index 0000000..cb8937b
--- /dev/null
+++ b/compress/Makefile.postamble
@@ -0,0 +1,5 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
+
+after_install::
+	$(LINKPRODUCT) $(DSTROOT)$(INSTALLDIR)/uncompress
+#	$(LINKPRODUCT) $(DSTROOT)$(INSTALLDIR)/zcat
diff --git a/compress/Makefile.preamble b/compress/Makefile.preamble
new file mode 100644
index 0000000..9e10e90
--- /dev/null
+++ b/compress/Makefile.preamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
diff --git a/compress/PB.project b/compress/PB.project
new file mode 100644
index 0000000..d9c8269
--- /dev/null
+++ b/compress/PB.project
@@ -0,0 +1,32 @@
+{
+    DYNAMIC_CODE_GEN = YES; 
+    FILESTABLE = {
+        FRAMEWORKS = (); 
+        OTHER_LINKED = (compress.c, zopen.c); 
+        OTHER_SOURCES = (
+            Makefile, 
+            Makefile.preamble, 
+            Makefile.postamble, 
+            compress.1, 
+            zopen.3, 
+            uncompress.1
+        ); 
+    }; 
+    LANGUAGE = English; 
+    LOCALIZABLE_FILES = {}; 
+    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
+    NEXTSTEP_BUILDDIR = /tmp/developer_cmds/Build; 
+    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
+    NEXTSTEP_INSTALLDIR = /usr/bin; 
+    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
+    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
+    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
+    PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; 
+    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
+    PROJECTNAME = compress; 
+    PROJECTTYPE = Tool; 
+    PROJECTVERSION = 2.8; 
+    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
+    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
+    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
+}
diff --git a/compress/compress.1 b/compress/compress.1
new file mode 100644
index 0000000..2534855
--- /dev/null
+++ b/compress/compress.1
@@ -0,0 +1,176 @@
+.\"	$NetBSD: compress.1,v 1.6 1997/09/15 10:58:37 lukem Exp $
+.\"
+.\" Copyright (c) 1986, 1990, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" James A. Woods, derived from original work by Spencer Thomas
+.\" and Joseph Orost.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     @(#)compress.1	8.2 (Berkeley) 4/18/94
+.\"
+.Dd April 18, 1994
+.Dt COMPRESS 1
+.Os BSD 4.3
+.Sh NAME
+.Nm compress ,
+.\".Nm uncompress ,
+.Nm uncompress
+.\".Nm zcat
+.Nd compress and expand data
+.Sh SYNOPSIS
+.Nm
+.Op Fl cfv
+.Op Fl b Ar bits
+.Op Ar
+.Nm uncompress
+.Op Fl cfv
+.Op Ar 
+.\".Nm zcat
+.\".Op Ar
+.Sh DESCRIPTION
+.Nm
+reduces the size of the named files using adaptive Lempel-Ziv coding.
+Each
+.Ar file
+is renamed to the same name plus the extension
+.Dq .Z .
+As many of the modification time, access time, file flags, file mode,
+user ID, and group ID as allowed by permissions are retained in the
+new file.
+If compression would not reduce the size of a
+.Ar file ,
+the file is ignored.
+.Pp
+.Nm uncompress
+restores the compressed files to their original form, renaming the
+files by deleting the
+.Dq .Z
+extension.
+.\".Pp
+.\".Nm Zcat
+.\"is an alias for
+.\".Dq "uncompress -c" .
+.Pp
+If renaming the files would cause files to be overwritten and the standard
+input device is a terminal, the user is prompted (on the standard error
+output) for confirmation.
+If prompting is not possible or confirmation is not received, the files
+are not overwritten.
+.Pp
+If no files are specified, the standard input is compressed or uncompressed
+to the standard output.
+If either the input and output files are not regular files, the checks for
+reduction in size and file overwriting are not performed, the input file is
+not removed, and the attributes of the input file are not retained.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl b
+Specify the
+.Ar bits
+code limit (see below).
+.It Fl c
+Compressed or uncompressed output is written to the standard output.
+No files are modified.
+.It Fl f
+Force compression of
+.Ar file ,
+even if it is not actually reduced in size.
+Additionally, files are overwritten without prompting for confirmation.
+.It Fl v
+Print the percentage reduction of each file.
+.El
+.Pp
+.Nm
+uses a modified Lempel-Ziv algorithm.
+Common substrings in the file are first replaced by 9-bit codes 257 and up.
+When code 512 is reached, the algorithm switches to 10-bit codes and
+continues to use more bits until the
+limit specified by the
+.Fl b
+flag is reached (the default is 16).
+.Ar Bits
+must be between 9 and 16.
+.Pp
+After the
+.Ar bits
+limit is reached,
+.Nm
+periodically checks the compression ratio.
+If it is increasing,
+.Nm
+continues to use the existing code dictionary.
+However, if the compression ratio decreases,
+.Nm
+discards the table of substrings and rebuilds it from scratch.  This allows
+the algorithm to adapt to the next "block" of the file.
+.Pp
+The
+.Fl b
+flag is omitted for
+.Ar uncompress
+since the
+.Ar bits
+parameter specified during compression
+is encoded within the output, along with
+a magic number to ensure that neither decompression of random data nor
+recompression of compressed data is attempted.
+.Pp
+.ne 8
+The amount of compression obtained depends on the size of the
+input, the number of
+.Ar bits
+per code, and the distribution of common substrings.
+Typically, text such as source code or English is reduced by 50\-60%.
+Compression is generally much better than that achieved by Huffman
+coding (as used in the historical command pack), or adaptive Huffman
+coding (as used in the historical command compact), and takes less
+time to compute.
+.Pp
+The
+.Nm
+utility exits 0 on success, and >0 if an error occurs.
+.Sh SEE ALSO
+.Xr zcat 1
+.Rs
+.%A Welch, Terry A.
+.%D June, 1984
+.%T "A Technique for High Performance Data Compression"
+.%J "IEEE Computer"
+.%V 17:6
+.%P pp. 8-19
+.Re
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.3 .
diff --git a/compress/compress.c b/compress/compress.c
new file mode 100644
index 0000000..2aa84ee
--- /dev/null
+++ b/compress/compress.c
@@ -0,0 +1,491 @@
+/*	$NetBSD: compress.c,v 1.16 1998/03/10 12:45:44 kleink Exp $	*/
+
+/*-
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1992, 1993\n\
+	The Regents of the University of California.  All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)compress.c	8.2 (Berkeley) 1/7/94";
+#else
+__RCSID("$NetBSD: compress.c,v 1.16 1998/03/10 12:45:44 kleink Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void	compress __P((char *, char *, int));
+void	cwarn __P((const char *, ...));
+void	cwarnx __P((const char *, ...));
+void	decompress __P((char *, char *, int));
+int	permission __P((char *));
+void	setfile __P((char *, struct stat *));
+void	usage __P((int));
+
+int	main __P((int, char *[]));
+extern FILE *zopen __P((const char *fname, const char *mode, int bits));
+
+int eval, force, verbose;
+int isstdout, isstdin;
+
+int
+main(argc, argv)
+	int argc;
+	char *argv[];
+{
+        enum {COMPRESS, DECOMPRESS} style = COMPRESS;
+	size_t len;
+	int bits, cat, ch;
+	char *p, newname[MAXPATHLEN];
+
+	if ((p = strrchr(argv[0], '/')) == NULL)
+		p = argv[0];
+	else
+		++p;
+	if (!strcmp(p, "uncompress"))
+		style = DECOMPRESS;
+        else if (!strcmp(p, "compress"))
+                style = COMPRESS;
+        else if (!strcmp(p, "zcat")) {
+                style = DECOMPRESS;
+                cat = 1;
+        }
+	else
+		errx(1, "unknown program name");
+
+	bits = cat = 0;
+	while ((ch = getopt(argc, argv, "b:cdfv")) != -1)
+		switch(ch) {
+		case 'b':
+			bits = strtol(optarg, &p, 10);
+			if (*p)
+				errx(1, "illegal bit count -- %s", optarg);
+			break;
+		case 'c':
+			cat = 1;
+			break;
+		case 'd':		/* Backward compatible. */
+			style = DECOMPRESS;
+			break;
+		case 'f':
+			force = 1;
+			break;
+		case 'v':
+			verbose = 1;
+			break;
+		case '?':
+		default:
+			usage(style == COMPRESS);
+		}
+	argc -= optind;
+	argv += optind;
+
+	if (argc == 0) {
+		switch(style) {
+		case COMPRESS:
+			isstdout = 1;
+			isstdin = 1;
+			(void)compress("/dev/stdin", "/dev/stdout", bits);
+			break;
+		case DECOMPRESS:
+			isstdout = 1;
+			isstdin = 1;
+			(void)decompress("/dev/stdin", "/dev/stdout", bits);
+			break;
+		}
+		exit (eval);
+	}
+
+	if (cat == 1 && argc > 1)
+		errx(1, "the -c option permits only a single file argument");
+
+	for (; *argv; ++argv) {
+		isstdout = 0;
+		switch(style) {
+		case COMPRESS:
+			if (cat) {
+				isstdout = 1;
+				compress(*argv, "/dev/stdout", bits);
+				break;
+			}
+			if ((p = strrchr(*argv, '.')) != NULL &&
+			    !strcmp(p, ".Z")) {
+				cwarnx("%s: name already has trailing .Z",
+				    *argv);
+				break;
+			}
+			len = strlen(*argv);
+			if (len > sizeof(newname) - 3) {
+				cwarnx("%s: name too long", *argv);
+				break;
+			}
+			memmove(newname, *argv, len);
+			newname[len] = '.';
+			newname[len + 1] = 'Z';
+			newname[len + 2] = '\0';
+			compress(*argv, newname, bits);
+			break;
+		case DECOMPRESS:
+			len = strlen(*argv);
+			if ((p = strrchr(*argv, '.')) == NULL ||
+			    strcmp(p, ".Z")) {
+				if (len > sizeof(newname) - 3) {
+					cwarnx("%s: name too long", *argv);
+					break;
+				}
+				memmove(newname, *argv, len);
+				newname[len] = '.';
+				newname[len + 1] = 'Z';
+				newname[len + 2] = '\0';
+				decompress(newname,
+				    cat ? "/dev/stdout" : *argv, bits);
+				if (cat)
+					isstdout = 1;
+			} else {
+				if (len - 2 > sizeof(newname) - 1) {
+					cwarnx("%s: name too long", *argv);
+					break;
+				}
+				memmove(newname, *argv, len - 2);
+				newname[len - 2] = '\0';
+				decompress(*argv,
+				    cat ? "/dev/stdout" : newname, bits);
+				if (cat)
+					isstdout = 1;
+			}
+			break;
+		}
+	}
+	exit (eval);
+}
+
+void
+compress(in, out, bits)
+	char *in, *out;
+	int bits;
+{
+	int nr;
+	struct stat isb, sb;
+	FILE *ifp, *ofp;
+	int exists, isreg, oreg;
+	u_char buf[BUFSIZ];
+
+	if (!isstdout) {
+		exists = !stat(out, &sb);
+		if (!force && exists && S_ISREG(sb.st_mode) && !permission(out))
+			return;
+		oreg = !exists || S_ISREG(sb.st_mode);
+	} else
+		oreg = 0;
+
+	ifp = ofp = NULL;
+	if ((ifp = fopen(in, "r")) == NULL) {
+		cwarn("%s", in);
+		return;
+	}
+
+	if (!isstdin) {
+		if (stat(in, &isb)) {		/* DON'T FSTAT! */
+			cwarn("%s", in);
+			goto err;
+		}
+		if (!S_ISREG(isb.st_mode))
+			isreg = 0;
+		else
+			isreg = 1;
+	} else
+		isreg = 0;
+
+	if ((ofp = zopen(out, "w", bits)) == NULL) {
+		cwarn("%s", out);
+		goto err;
+	}
+	while ((nr = fread(buf, 1, sizeof(buf), ifp)) != 0)
+		if (fwrite(buf, 1, nr, ofp) != nr) {
+			cwarn("%s", out);
+			goto err;
+		}
+
+	if (ferror(ifp) || fclose(ifp)) {
+		cwarn("%s", in);
+		goto err;
+	}
+	ifp = NULL;
+
+	if (fclose(ofp)) {
+		cwarn("%s", out);
+		goto err;
+	}
+	ofp = NULL;
+
+	if (isreg && oreg) {
+		if (stat(out, &sb)) {
+			cwarn("%s", out);
+			goto err;
+		}
+
+		if (!force && sb.st_size >= isb.st_size) {
+			if (verbose)
+		(void)printf("%s: file would grow; left unmodified\n", in);
+			if (unlink(out))
+				cwarn("%s", out);
+			goto err;
+		}
+
+		setfile(out, &isb);
+
+		if (unlink(in))
+			cwarn("%s", in);
+
+		if (verbose) {
+			(void)printf("%s: ", out);
+			if (isb.st_size > sb.st_size)
+				(void)printf("%.0f%% compression\n",
+				    ((double)sb.st_size / isb.st_size) * 100.0);
+			else
+				(void)printf("%.0f%% expansion\n",
+				    ((double)isb.st_size / sb.st_size) * 100.0);
+		}
+	}
+	return;
+
+err:	if (ofp) {
+		if (oreg)
+			(void)unlink(out);
+		(void)fclose(ofp);
+	}
+	if (ifp)
+		(void)fclose(ifp);
+}
+
+void
+decompress(in, out, bits)
+	char *in, *out;
+	int bits;
+{
+	int nr;
+	struct stat sb;
+	FILE *ifp, *ofp;
+	int exists, isreg, oreg;
+	u_char buf[BUFSIZ];
+
+	if (!isstdout) {
+		exists = !stat(out, &sb);
+		if (!force && exists && S_ISREG(sb.st_mode) && !permission(out))
+			return;
+		oreg = !exists || S_ISREG(sb.st_mode);
+	} else
+		oreg = 0;
+
+	ifp = ofp = NULL;
+	if ((ofp = fopen(out, "w")) == NULL) {
+		cwarn("%s", out);
+		return;
+	}
+
+	if ((ifp = zopen(in, "r", bits)) == NULL) {
+		cwarn("%s", in);
+		goto err;
+	}
+	if (!isstdin) {
+		if (stat(in, &sb)) {
+			cwarn("%s", in);
+			goto err;
+		}
+		if (!S_ISREG(sb.st_mode))
+			isreg = 0;
+		else
+			isreg = 1;
+	} else
+		isreg = 0;
+
+	while ((nr = fread(buf, 1, sizeof(buf), ifp)) != 0)
+		if (fwrite(buf, 1, nr, ofp) != nr) {
+			cwarn("%s", out);
+			goto err;
+		}
+
+	if (ferror(ifp) || fclose(ifp)) {
+		cwarn("%s", in);
+		goto err;
+	}
+	ifp = NULL;
+
+	if (fclose(ofp)) {
+		cwarn("%s", out);
+		goto err;
+	}
+
+	if (isreg && oreg) {
+		setfile(out, &sb);
+
+		if (unlink(in))
+			cwarn("%s", in);
+	}
+	return;
+
+err:	if (ofp) {
+		if (oreg)
+			(void)unlink(out);
+		(void)fclose(ofp);
+	}
+	if (ifp)
+		(void)fclose(ifp);
+}
+
+void
+setfile(name, fs)
+	char *name;
+	struct stat *fs;
+{
+	static struct timeval tv[2];
+
+	fs->st_mode &= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
+
+	TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec);
+	TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec);
+	if (utimes(name, tv))
+		cwarn("utimes: %s", name);
+
+	/*
+	 * Changing the ownership probably won't succeed, unless we're root
+	 * or POSIX_CHOWN_RESTRICTED is not set.  Set uid/gid before setting
+	 * the mode; current BSD behavior is to remove all setuid bits on
+	 * chown.  If chown fails, lose setuid/setgid bits.
+	 */
+	if (chown(name, fs->st_uid, fs->st_gid)) {
+		if (errno != EPERM)
+			cwarn("chown: %s", name);
+		fs->st_mode &= ~(S_ISUID|S_ISGID);
+	}
+	if (chmod(name, fs->st_mode))
+		cwarn("chown: %s", name);
+
+	/*
+	 * Restore the file's flags.  However, do this only if the original
+	 * file had any flags set; this avoids a warning on file-systems that
+	 * do not support flags.
+	 */
+	if (fs->st_flags != 0 && chflags(name, fs->st_flags))
+		cwarn("chflags: %s", name);
+}
+
+int
+permission(fname)
+	char *fname;
+{
+	int ch, first;
+
+	if (!isatty(fileno(stderr)))
+		return (0);
+	(void)fprintf(stderr, "overwrite %s? ", fname);
+	first = ch = getchar();
+	while (ch != '\n' && ch != EOF)
+		ch = getchar();
+	return (first == 'y');
+}
+
+void
+usage(iscompress)
+	int iscompress;
+{
+	if (iscompress)
+		(void)fprintf(stderr,
+		    "usage: compress [-cfv] [-b bits] [file ...]\n");
+	else
+		(void)fprintf(stderr,
+		    "usage: uncompress [-c] [-b bits] [file ...]\n");
+	exit(1);
+}
+
+void
+#if __STDC__
+cwarnx(const char *fmt, ...)
+#else
+cwarnx(fmt, va_alist)
+	int eval;
+	const char *fmt;
+	va_dcl
+#endif
+{
+	va_list ap;
+#if __STDC__
+	va_start(ap, fmt);
+#else
+	va_start(ap);
+#endif
+	vwarnx(fmt, ap);
+	va_end(ap);
+	eval = 1;
+}
+
+void
+#if __STDC__
+cwarn(const char *fmt, ...)
+#else
+cwarn(fmt, va_alist)
+	int eval;
+	const char *fmt;
+	va_dcl
+#endif
+{
+	va_list ap;
+#if __STDC__
+	va_start(ap, fmt);
+#else
+	va_start(ap);
+#endif
+	vwarn(fmt, ap);
+	va_end(ap);
+	eval = 1;
+}
diff --git a/compress/uncompress.1 b/compress/uncompress.1
new file mode 100644
index 0000000..208c3ce
--- /dev/null
+++ b/compress/uncompress.1
@@ -0,0 +1 @@
+.so man1/compress.1
\ No newline at end of file
diff --git a/compress/zopen.3 b/compress/zopen.3
new file mode 100644
index 0000000..1e75687
--- /dev/null
+++ b/compress/zopen.3
@@ -0,0 +1,142 @@
+.\"	$NetBSD: zopen.3,v 1.4 1998/02/06 06:17:43 perry Exp $
+.\"
+.\" Copyright (c) 1992, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)zopen.3	8.1 (Berkeley) 6/9/93
+.\"
+.Dd June 9, 1993
+.Dt ZOPEN 3
+.Os
+.Sh NAME
+.Nm zopen
+.Nd compressed stream open function
+.Sh SYNOPSIS
+.Fd #include <stdio.h>
+.Ft FILE *
+.Fn zopen "const char *path" "const char *mode" "int bits"
+.Sh DESCRIPTION
+The
+.Fn zopen
+function
+opens the compressed file whose name is the string pointed to by
+.Fa path
+and associates a stream with it.
+.Pp
+The argument
+.Fa mode
+points to one of the following one-character strings:
+.Bl -tag -width indent
+.It Dq Li r
+Open compressed file for reading.
+The stream is positioned at the beginning of the file.
+.It Dq Li w
+Truncate file to zero length or create compressed file for writing.
+The stream is positioned at the beginning of the file.
+.El
+.Pp
+Any created files will have mode
+.Pf \\*q Dv S_IRUSR
+\&|
+.Dv S_IWUSR
+\&|
+.Dv S_IRGRP
+\&|
+.Dv S_IWGRP
+\&|
+.Dv S_IROTH
+\&|
+.Dv S_IWOTH Ns \\*q
+.Pq Li 0666 ,
+as modified by the process'
+umask value (see
+.Xr umask 2 ) .
+.Pp
+Files may only be read or written.
+Seek operations are not allowed.
+.Pp
+The
+.Fa bits
+argument, if non-zero, is set to the bits code limit.
+If zero, the default is 16.
+See
+.Fn compress 1
+for more information.
+.Sh RETURN VALUES
+Upon successful completion
+.Fn zopen
+returns a
+.Tn FILE
+pointer.
+Otherwise,
+.Dv NULL
+is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+.Bl -tag -width [EINVAL]
+.It Bq Er EINVAL
+The
+.Fa mode
+or
+.Fa bits
+arguments specified to
+.Fn zopen
+were invalid.
+.It Bq Er EFTYPE
+The compressed file starts with an invalid header, or the compressed
+file is compressed with more bits than can be handled.
+.El
+.Pp
+The
+.Fn zopen
+function may also fail and set
+.Va errno
+for any of the errors specified for the routines
+.Xr fopen 3
+or
+.Xr funopen 3 .
+.Sh SEE ALSO
+.Xr compress 1 ,
+.Xr fopen 3 ,
+.Xr funopen 3
+.Sh HISTORY
+The
+.Nm zopen
+function
+first appeared in
+.Bx 4.4 .
+.Sh BUGS
+The
+.Fn zopen
+function
+may not be portable to systems other than
+.Bx .
diff --git a/compress/zopen.c b/compress/zopen.c
new file mode 100644
index 0000000..c165117
--- /dev/null
+++ b/compress/zopen.c
@@ -0,0 +1,748 @@
+/*	$NetBSD: zopen.c,v 1.6 1997/09/15 10:58:39 lukem Exp $	*/
+
+/*-
+ * Copyright (c) 1985, 1986, 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Diomidis Spinellis and James A. Woods, derived from original
+ * work by Spencer Thomas and Joseph Orost.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)zopen.c	8.1 (Berkeley) 6/27/93";
+#else
+static char rcsid[] = "$NetBSD: zopen.c,v 1.6 1997/09/15 10:58:39 lukem Exp $";
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+/*-
+ * fcompress.c - File compression ala IEEE Computer, June 1984.
+ *
+ * Compress authors:
+ *		Spencer W. Thomas	(decvax!utah-cs!thomas)
+ *		Jim McKie		(decvax!mcvax!jim)
+ *		Steve Davies		(decvax!vax135!petsd!peora!srd)
+ *		Ken Turkowski		(decvax!decwrl!turtlevax!ken)
+ *		James A. Woods		(decvax!ihnp4!ames!jaw)
+ *		Joe Orost		(decvax!vax135!petsd!joe)
+ *
+ * Cleaned up and converted to library returning I/O streams by
+ * Diomidis Spinellis <dds@doc.ic.ac.uk>.
+ *
+ * zopen(filename, mode, bits)
+ *	Returns a FILE * that can be used for read or write.  The modes
+ *	supported are only "r" and "w".  Seeking is not allowed.  On
+ *	reading the file is decompressed, on writing it is compressed.
+ *	The output is compatible with compress(1) with 16 bit tables.
+ *	Any file produced by compress(1) can be read.
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define	BITS		16		/* Default bits. */
+#define	HSIZE		69001		/* 95% occupancy */
+
+/* A code_int must be able to hold 2**BITS values of type int, and also -1. */
+typedef long code_int;
+typedef long count_int;
+
+typedef u_char char_type;
+static char_type magic_header[] =
+	{'\037', '\235'};		/* 1F 9D */
+
+#define	BIT_MASK	0x1f		/* Defines for third byte of header. */
+#define	BLOCK_MASK	0x80
+
+/*
+ * Masks 0x40 and 0x20 are free.  I think 0x20 should mean that there is
+ * a fourth header byte (for expansion).
+ */
+#define	INIT_BITS 9			/* Initial number of bits/code. */
+
+#define	MAXCODE(n_bits)	((1 << (n_bits)) - 1)
+
+struct s_zstate {
+	FILE *zs_fp;			/* File stream for I/O */
+	char zs_mode;			/* r or w */
+	enum {
+		S_START, S_MIDDLE, S_EOF
+	} zs_state;			/* State of computation */
+	int zs_n_bits;			/* Number of bits/code. */
+	int zs_maxbits;			/* User settable max # bits/code. */
+	code_int zs_maxcode;		/* Maximum code, given n_bits. */
+	code_int zs_maxmaxcode;		/* Should NEVER generate this code. */
+	count_int zs_htab [HSIZE];
+	u_short zs_codetab [HSIZE];
+	code_int zs_hsize;		/* For dynamic table sizing. */
+	code_int zs_free_ent;		/* First unused entry. */
+	/*
+	 * Block compression parameters -- after all codes are used up,
+	 * and compression rate changes, start over.
+	 */
+	int zs_block_compress;
+	int zs_clear_flg;
+	long zs_ratio;
+	count_int zs_checkpoint;
+	int zs_offset;
+	long zs_in_count;		/* Length of input. */
+	long zs_bytes_out;		/* Length of compressed output. */
+	long zs_out_count;		/* # of codes output (for debugging). */
+	char_type zs_buf[BITS];
+	union {
+		struct {
+			long zs_fcode;
+			code_int zs_ent;
+			code_int zs_hsize_reg;
+			int zs_hshift;
+		} w;			/* Write paramenters */
+		struct {
+			char_type *zs_stackp;
+			int zs_finchar;
+			code_int zs_code, zs_oldcode, zs_incode;
+			int zs_roffset, zs_size;
+			char_type zs_gbuf[BITS];
+		} r;			/* Read parameters */
+	} u;
+};
+
+/* Definitions to retain old variable names */
+#define	fp		zs->zs_fp
+#define	zmode		zs->zs_mode
+#define	state		zs->zs_state
+#define	n_bits		zs->zs_n_bits
+#define	maxbits		zs->zs_maxbits
+#define	maxcode		zs->zs_maxcode
+#define	maxmaxcode	zs->zs_maxmaxcode
+#define	htab		zs->zs_htab
+#define	codetab		zs->zs_codetab
+#define	hsize		zs->zs_hsize
+#define	free_ent	zs->zs_free_ent
+#define	block_compress	zs->zs_block_compress
+#define	clear_flg	zs->zs_clear_flg
+#define	ratio		zs->zs_ratio
+#define	checkpoint	zs->zs_checkpoint
+#define	offset		zs->zs_offset
+#define	in_count	zs->zs_in_count
+#define	bytes_out	zs->zs_bytes_out
+#define	out_count	zs->zs_out_count
+#define	buf		zs->zs_buf
+#define	fcode		zs->u.w.zs_fcode
+#define	hsize_reg	zs->u.w.zs_hsize_reg
+#define	ent		zs->u.w.zs_ent
+#define	hshift		zs->u.w.zs_hshift
+#define	stackp		zs->u.r.zs_stackp
+#define	finchar		zs->u.r.zs_finchar
+#define	code		zs->u.r.zs_code
+#define	oldcode		zs->u.r.zs_oldcode
+#define	incode		zs->u.r.zs_incode
+#define	roffset		zs->u.r.zs_roffset
+#define	size		zs->u.r.zs_size
+#define	gbuf		zs->u.r.zs_gbuf
+
+/*
+ * To save much memory, we overlay the table used by compress() with those
+ * used by decompress().  The tab_prefix table is the same size and type as
+ * the codetab.  The tab_suffix table needs 2**BITS characters.  We get this
+ * from the beginning of htab.  The output stack uses the rest of htab, and
+ * contains characters.  There is plenty of room for any possible stack
+ * (stack used to be 8000 characters).
+ */
+
+#define	htabof(i)	htab[i]
+#define	codetabof(i)	codetab[i]
+
+#define	tab_prefixof(i)	codetabof(i)
+#define	tab_suffixof(i)	((char_type *)(htab))[i]
+#define	de_stack	((char_type *)&tab_suffixof(1 << BITS))
+
+#define	CHECK_GAP 10000		/* Ratio check interval. */
+
+/*
+ * the next two codes should not be changed lightly, as they must not
+ * lie within the contiguous general code space.
+ */
+#define	FIRST	257		/* First free entry. */
+#define	CLEAR	256		/* Table clear output code. */
+
+static int	cl_block __P((struct s_zstate *));
+static void	cl_hash __P((struct s_zstate *, count_int));
+static code_int	getcode __P((struct s_zstate *));
+static int	output __P((struct s_zstate *, code_int));
+static int	zclose __P((void *));
+FILE	       *zopen __P((const char *, const char *, int));
+static int	zread __P((void *, char *, int));
+static int	zwrite __P((void *, const char *, int));
+
+/*-
+ * Algorithm from "A Technique for High Performance Data Compression",
+ * Terry A. Welch, IEEE Computer Vol 17, No 6 (June 1984), pp 8-19.
+ *
+ * Algorithm:
+ * 	Modified Lempel-Ziv method (LZW).  Basically finds common
+ * substrings and replaces them with a variable size code.  This is
+ * deterministic, and can be done on the fly.  Thus, the decompression
+ * procedure needs no input table, but tracks the way the table was built.
+ */
+
+/*-
+ * compress write
+ *
+ * Algorithm:  use open addressing double hashing (no chaining) on the
+ * prefix code / next character combination.  We do a variant of Knuth's
+ * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
+ * secondary probe.  Here, the modular division first probe is gives way
+ * to a faster exclusive-or manipulation.  Also do block compression with
+ * an adaptive reset, whereby the code table is cleared when the compression
+ * ratio decreases, but after the table fills.  The variable-length output
+ * codes are re-sized at this point, and a special CLEAR code is generated
+ * for the decompressor.  Late addition:  construct the table according to
+ * file size for noticeable speed improvement on small files.  Please direct
+ * questions about this implementation to ames!jaw.
+ */
+static int
+zwrite(cookie, wbp, num)
+	void *cookie;
+	const char *wbp;
+	int num;
+{
+	code_int i;
+	int c, disp;
+	struct s_zstate *zs;
+	const u_char *bp;
+	u_char tmp;
+	int count;
+
+	if (num == 0)
+		return (0);
+
+	zs = cookie;
+	count = num;
+	bp = (u_char *)wbp;
+	if (state == S_MIDDLE)
+		goto middle;
+	state = S_MIDDLE;
+
+	maxmaxcode = 1L << maxbits;
+	if (fwrite(magic_header,
+	    sizeof(char), sizeof(magic_header), fp) != sizeof(magic_header))
+		return (-1);
+	tmp = (u_char)(maxbits | block_compress);
+	if (fwrite(&tmp, sizeof(char), sizeof(tmp), fp) != sizeof(tmp))
+		return (-1);
+
+	offset = 0;
+	bytes_out = 3;		/* Includes 3-byte header mojo. */
+	out_count = 0;
+	clear_flg = 0;
+	ratio = 0;
+	in_count = 1;
+	checkpoint = CHECK_GAP;
+	maxcode = MAXCODE(n_bits = INIT_BITS);
+	free_ent = ((block_compress) ? FIRST : 256);
+
+	ent = *bp++;
+	--count;
+
+	hshift = 0;
+	for (fcode = (long)hsize; fcode < 65536L; fcode *= 2L)
+		hshift++;
+	hshift = 8 - hshift;	/* Set hash code range bound. */
+
+	hsize_reg = hsize;
+	cl_hash(zs, (count_int)hsize_reg);	/* Clear hash table. */
+
+middle:	for (i = 0; count--;) {
+		c = *bp++;
+		in_count++;
+		fcode = (long)(((long)c << maxbits) + ent);
+		i = ((c << hshift) ^ ent);	/* Xor hashing. */
+
+		if (htabof(i) == fcode) {
+			ent = codetabof(i);
+			continue;
+		} else if ((long)htabof(i) < 0)	/* Empty slot. */
+			goto nomatch;
+		disp = hsize_reg - i;	/* Secondary hash (after G. Knott). */
+		if (i == 0)
+			disp = 1;
+probe:		if ((i -= disp) < 0)
+			i += hsize_reg;
+
+		if (htabof(i) == fcode) {
+			ent = codetabof(i);
+			continue;
+		}
+		if ((long)htabof(i) >= 0)
+			goto probe;
+nomatch:	if (output(zs, (code_int) ent) == -1)
+			return (-1);
+		out_count++;
+		ent = c;
+		if (free_ent < maxmaxcode) {
+			codetabof(i) = free_ent++;	/* code -> hashtable */
+			htabof(i) = fcode;
+		} else if ((count_int)in_count >=
+		    checkpoint && block_compress) {
+			if (cl_block(zs) == -1)
+				return (-1);
+		}
+	}
+	return (num);
+}
+
+static int
+zclose(cookie)
+	void *cookie;
+{
+	struct s_zstate *zs;
+	int rval;
+
+	zs = cookie;
+	if (zmode == 'w') {		/* Put out the final code. */
+		if (output(zs, (code_int) ent) == -1) {
+			(void)fclose(fp);
+			free(zs);
+			return (-1);
+		}
+		out_count++;
+		if (output(zs, (code_int) - 1) == -1) {
+			(void)fclose(fp);
+			free(zs);
+			return (-1);
+		}
+	}
+	rval = fclose(fp) == EOF ? -1 : 0;
+	free(zs);
+	return (rval);
+}
+
+/*-
+ * Output the given code.
+ * Inputs:
+ * 	code:	A n_bits-bit integer.  If == -1, then EOF.  This assumes
+ *		that n_bits =< (long)wordsize - 1.
+ * Outputs:
+ * 	Outputs code to the file.
+ * Assumptions:
+ *	Chars are 8 bits long.
+ * Algorithm:
+ * 	Maintain a BITS character long buffer (so that 8 codes will
+ * fit in it exactly).  Use the VAX insv instruction to insert each
+ * code in turn.  When the buffer fills up empty it and start over.
+ */
+
+static char_type lmask[9] =
+	{0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00};
+static char_type rmask[9] =
+	{0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
+
+static int
+output(zs, ocode)
+	struct s_zstate *zs;
+	code_int ocode;
+{
+	int bits, r_off;
+	char_type *bp;
+
+	r_off = offset;
+	bits = n_bits;
+	bp = buf;
+	if (ocode >= 0) {
+		/* Get to the first byte. */
+		bp += (r_off >> 3);
+		r_off &= 7;
+		/*
+		 * Since ocode is always >= 8 bits, only need to mask the first
+		 * hunk on the left.
+		 */
+		*bp = (*bp & rmask[r_off]) | ((ocode << r_off) & lmask[r_off]);
+		bp++;
+		bits -= (8 - r_off);
+		ocode >>= 8 - r_off;
+		/* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
+		if (bits >= 8) {
+			*bp++ = ocode;
+			ocode >>= 8;
+			bits -= 8;
+		}
+		/* Last bits. */
+		if (bits)
+			*bp = ocode;
+		offset += n_bits;
+		if (offset == (n_bits << 3)) {
+			bp = buf;
+			bits = n_bits;
+			bytes_out += bits;
+			if (fwrite(bp, sizeof(char), bits, fp) != bits)
+				return (-1);
+			bp += bits;
+			bits = 0;
+			offset = 0;
+		}
+		/*
+		 * If the next entry is going to be too big for the ocode size,
+		 * then increase it, if possible.
+		 */
+		if (free_ent > maxcode || (clear_flg > 0)) {
+		       /*
+			* Write the whole buffer, because the input side won't
+			* discover the size increase until after it has read it.
+			*/
+			if (offset > 0) {
+				if (fwrite(buf, 1, n_bits, fp) != n_bits)
+					return (-1);
+				bytes_out += n_bits;
+			}
+			offset = 0;
+
+			if (clear_flg) {
+				maxcode = MAXCODE(n_bits = INIT_BITS);
+				clear_flg = 0;
+			} else {
+				n_bits++;
+				if (n_bits == maxbits)
+					maxcode = maxmaxcode;
+				else
+					maxcode = MAXCODE(n_bits);
+			}
+		}
+	} else {
+		/* At EOF, write the rest of the buffer. */
+		if (offset > 0) {
+			offset = (offset + 7) / 8;
+			if (fwrite(buf, 1, offset, fp) != offset)
+				return (-1);
+			bytes_out += offset;
+		}
+		offset = 0;
+	}
+	return (0);
+}
+
+/*
+ * Decompress read.  This routine adapts to the codes in the file building
+ * the "string" table on-the-fly; requiring no table to be stored in the
+ * compressed file.  The tables used herein are shared with those of the
+ * compress() routine.  See the definitions above.
+ */
+static int
+zread(cookie, rbp, num)
+	void *cookie;
+	char *rbp;
+	int num;
+{
+	u_int count;
+	struct s_zstate *zs;
+	u_char *bp, header[3];
+
+	if (num == 0)
+		return (0);
+
+	zs = cookie;
+	count = num;
+	bp = (u_char *)rbp;
+	switch (state) {
+	case S_START:
+		state = S_MIDDLE;
+		break;
+	case S_MIDDLE:
+		goto middle;
+	case S_EOF:
+		goto eof;
+	}
+
+	/* Check the magic number */
+	if (fread(header,
+	    sizeof(char), sizeof(header), fp) != sizeof(header) ||
+	    memcmp(header, magic_header, sizeof(magic_header)) != 0) {
+		errno = EFTYPE;
+		return (-1);
+	}
+	maxbits = header[2];	/* Set -b from file. */
+	block_compress = maxbits & BLOCK_MASK;
+	maxbits &= BIT_MASK;
+	maxmaxcode = 1L << maxbits;
+	if (maxbits > BITS) {
+		errno = EFTYPE;
+		return (-1);
+	}
+	/* As above, initialize the first 256 entries in the table. */
+	maxcode = MAXCODE(n_bits = INIT_BITS);
+	for (code = 255; code >= 0; code--) {
+		tab_prefixof(code) = 0;
+		tab_suffixof(code) = (char_type) code;
+	}
+	free_ent = block_compress ? FIRST : 256;
+
+	finchar = oldcode = getcode(zs);
+	if (oldcode == -1)	/* EOF already? */
+		return (0);	/* Get out of here */
+
+	/* First code must be 8 bits = char. */
+	*bp++ = (u_char)finchar;
+	count--;
+	stackp = de_stack;
+
+	while ((code = getcode(zs)) > -1) {
+
+		if ((code == CLEAR) && block_compress) {
+			for (code = 255; code >= 0; code--)
+				tab_prefixof(code) = 0;
+			clear_flg = 1;
+			free_ent = FIRST - 1;
+			if ((code = getcode(zs)) == -1)	/* O, untimely death! */
+				break;
+		}
+		incode = code;
+
+		/* Special case for KwKwK string. */
+		if (code >= free_ent) {
+			*stackp++ = finchar;
+			code = oldcode;
+		}
+
+		/* Generate output characters in reverse order. */
+		while (code >= 256) {
+			*stackp++ = tab_suffixof(code);
+			code = tab_prefixof(code);
+		}
+		*stackp++ = finchar = tab_suffixof(code);
+
+		/* And put them out in forward order.  */
+middle:		do {
+			if (count-- == 0)
+				return (num);
+			*bp++ = *--stackp;
+		} while (stackp > de_stack);
+
+		/* Generate the new entry. */
+		if ((code = free_ent) < maxmaxcode) {
+			tab_prefixof(code) = (u_short) oldcode;
+			tab_suffixof(code) = finchar;
+			free_ent = code + 1;
+		}
+
+		/* Remember previous code. */
+		oldcode = incode;
+	}
+	state = S_EOF;
+eof:	return (num - count);
+}
+
+/*-
+ * Read one code from the standard input.  If EOF, return -1.
+ * Inputs:
+ * 	stdin
+ * Outputs:
+ * 	code or -1 is returned.
+ */
+static code_int
+getcode(zs)
+	struct s_zstate *zs;
+{
+	code_int gcode;
+	int r_off, bits;
+	char_type *bp;
+
+	bp = gbuf;
+	if (clear_flg > 0 || roffset >= size || free_ent > maxcode) {
+		/*
+		 * If the next entry will be too big for the current gcode
+		 * size, then we must increase the size.  This implies reading
+		 * a new buffer full, too.
+		 */
+		if (free_ent > maxcode) {
+			n_bits++;
+			if (n_bits == maxbits)	/* Won't get any bigger now. */
+				maxcode = maxmaxcode;
+			else
+				maxcode = MAXCODE(n_bits);
+		}
+		if (clear_flg > 0) {
+			maxcode = MAXCODE(n_bits = INIT_BITS);
+			clear_flg = 0;
+		}
+		size = fread(gbuf, 1, n_bits, fp);
+		if (size <= 0)			/* End of file. */
+			return (-1);
+		roffset = 0;
+		/* Round size down to integral number of codes. */
+		size = (size << 3) - (n_bits - 1);
+	}
+	r_off = roffset;
+	bits = n_bits;
+
+	/* Get to the first byte. */
+	bp += (r_off >> 3);
+	r_off &= 7;
+
+	/* Get first part (low order bits). */
+	gcode = (*bp++ >> r_off);
+	bits -= (8 - r_off);
+	r_off = 8 - r_off;	/* Now, roffset into gcode word. */
+
+	/* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
+	if (bits >= 8) {
+		gcode |= *bp++ << r_off;
+		r_off += 8;
+		bits -= 8;
+	}
+
+	/* High order bits. */
+	gcode |= (*bp & rmask[bits]) << r_off;
+	roffset += n_bits;
+
+	return (gcode);
+}
+
+static int
+cl_block(zs)			/* Table clear for block compress. */
+	struct s_zstate *zs;
+{
+	long rat;
+
+	checkpoint = in_count + CHECK_GAP;
+
+	if (in_count > 0x007fffff) {	/* Shift will overflow. */
+		rat = bytes_out >> 8;
+		if (rat == 0)		/* Don't divide by zero. */
+			rat = 0x7fffffff;
+		else
+			rat = in_count / rat;
+	} else
+		rat = (in_count << 8) / bytes_out;	/* 8 fractional bits. */
+	if (rat > ratio)
+		ratio = rat;
+	else {
+		ratio = 0;
+		cl_hash(zs, (count_int) hsize);
+		free_ent = FIRST;
+		clear_flg = 1;
+		if (output(zs, (code_int) CLEAR) == -1)
+			return (-1);
+	}
+	return (0);
+}
+
+static void
+cl_hash(zs, cl_hsize)			/* Reset code table. */
+	struct s_zstate *zs;
+	count_int cl_hsize;
+{
+	count_int *htab_p;
+	long i, m1;
+
+	m1 = -1;
+	htab_p = htab + cl_hsize;
+	i = cl_hsize - 16;
+	do {			/* Might use Sys V memset(3) here. */
+		*(htab_p - 16) = m1;
+		*(htab_p - 15) = m1;
+		*(htab_p - 14) = m1;
+		*(htab_p - 13) = m1;
+		*(htab_p - 12) = m1;
+		*(htab_p - 11) = m1;
+		*(htab_p - 10) = m1;
+		*(htab_p - 9) = m1;
+		*(htab_p - 8) = m1;
+		*(htab_p - 7) = m1;
+		*(htab_p - 6) = m1;
+		*(htab_p - 5) = m1;
+		*(htab_p - 4) = m1;
+		*(htab_p - 3) = m1;
+		*(htab_p - 2) = m1;
+		*(htab_p - 1) = m1;
+		htab_p -= 16;
+	} while ((i -= 16) >= 0);
+	for (i += 16; i > 0; i--)
+		*--htab_p = m1;
+}
+
+FILE *
+zopen(fname, mode, bits)
+	const char *fname, *mode;
+	int bits;
+{
+	struct s_zstate *zs;
+
+	if ((mode[0] != 'r' && mode[0] != 'w') || mode[1] != '\0' ||
+	    bits < 0 || bits > BITS) {
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	if ((zs = calloc(1, sizeof(struct s_zstate))) == NULL)
+		return (NULL);
+
+	maxbits = bits ? bits : BITS;	/* User settable max # bits/code. */
+	maxmaxcode = 1 << maxbits;	/* Should NEVER generate this code. */
+	hsize = HSIZE;			/* For dynamic table sizing. */
+	free_ent = 0;			/* First unused entry. */
+	block_compress = BLOCK_MASK;
+	clear_flg = 0;
+	ratio = 0;
+	checkpoint = CHECK_GAP;
+	in_count = 1;			/* Length of input. */
+	out_count = 0;			/* # of codes output (for debugging). */
+	state = S_START;
+	roffset = 0;
+	size = 0;
+
+	/*
+	 * Layering compress on top of stdio in order to provide buffering,
+	 * and ensure that reads and write work with the data specified.
+	 */
+	if ((fp = fopen(fname, mode)) == NULL) {
+		free(zs);
+		return (NULL);
+	}
+	switch (*mode) {
+	case 'r':
+		zmode = 'r';
+		return (funopen(zs, zread, NULL, NULL, zclose));
+	case 'w':
+		zmode = 'w';
+		return (funopen(zs, NULL, zwrite, NULL, zclose));
+	}
+	/* NOTREACHED */
+	return (NULL);
+}
diff --git a/cp/Makefile b/cp/Makefile
new file mode 100644
index 0000000..8d778e8
--- /dev/null
+++ b/cp/Makefile
@@ -0,0 +1,51 @@
+#
+# Generated by the NeXT Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = cp
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+HFILES = extern.h
+
+CFILES = cp.c utils.c
+
+OTHERSRCS = Makefile Makefile.preamble Makefile.postamble cp.1
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /bin
+LIBS = 
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+NEXTSTEP_PB_CFLAGS = -DVM_AND_BUFFER_CACHE_SYNCHRONIZED
+
+
+NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/$(NAME)/Build
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
diff --git a/cp/Makefile.postamble b/cp/Makefile.postamble
new file mode 100644
index 0000000..013b558
--- /dev/null
+++ b/cp/Makefile.postamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
diff --git a/cp/Makefile.preamble b/cp/Makefile.preamble
new file mode 100644
index 0000000..9e10e90
--- /dev/null
+++ b/cp/Makefile.preamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
diff --git a/cp/PB.project b/cp/PB.project
new file mode 100644
index 0000000..e3be88f
--- /dev/null
+++ b/cp/PB.project
@@ -0,0 +1,27 @@
+{
+    DYNAMIC_CODE_GEN = YES; 
+    FILESTABLE = {
+        FRAMEWORKS = (); 
+        H_FILES = (extern.h); 
+        OTHER_LINKED = (cp.c, utils.c); 
+        OTHER_SOURCES = (Makefile, Makefile.preamble, Makefile.postamble, cp.1); 
+    }; 
+    LANGUAGE = English; 
+    LOCALIZABLE_FILES = {}; 
+    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
+    NEXTSTEP_BUILDDIR = "/tmp/$(NAME)/Build"; 
+    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
+    NEXTSTEP_COMPILEROPTIONS = "-DVM_AND_BUFFER_CACHE_SYNCHRONIZED"; 
+    NEXTSTEP_INSTALLDIR = /bin; 
+    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
+    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
+    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
+    PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; 
+    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
+    PROJECTNAME = cp; 
+    PROJECTTYPE = Tool; 
+    PROJECTVERSION = 2.8; 
+    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
+    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
+    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
+}
diff --git a/cp/cp.1 b/cp/cp.1
new file mode 100644
index 0000000..e5016c8
--- /dev/null
+++ b/cp/cp.1
@@ -0,0 +1,215 @@
+.\"	$NetBSD: cp.1,v 1.12 1997/10/11 02:14:42 enami Exp $
+.\"
+.\" Copyright (c) 1989, 1990, 1993, 1994
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)cp.1	8.3 (Berkeley) 4/18/94
+.\"
+.Dd April 18, 1994
+.Dt CP 1
+.Os BSD 4
+.Sh NAME
+.Nm cp
+.Nd copy files
+.Sh SYNOPSIS
+.Nm
+.Oo
+.Fl R
+.Op Fl H | Fl L | Fl P
+.Oc
+.Op Fl f | i
+.Op Fl p
+.Ar source_file target_file
+.Nm cp
+.Oo
+.Fl R
+.Op Fl H | Fl L | Fl P
+.Oc
+.Op Fl f | i
+.Op Fl p
+.Ar source_file ... target_directory
+.Sh DESCRIPTION
+In the first synopsis form, the
+.Nm
+utility copies the contents of the
+.Ar source_file
+to the
+.Ar target_file .
+In the second synopsis form,
+the contents of each named
+.Ar source_file
+is copied to the destination
+.Ar target_directory .
+The names of the files themselves are not changed.
+If
+.Nm
+detects an attempt to copy a file to itself, the copy will fail.
+.Pp
+The following options are available:
+.Bl -tag -width flag
+.It Fl H
+If the
+.Fl R
+option is specified, symbolic links on the command line are followed.
+(Symbolic links encountered in the tree traversal are not followed.)
+.It Fl L
+If the
+.Fl R
+option is specified, all symbolic links are followed.
+.It Fl P
+If the
+.Fl R
+option is specified, no symbolic links are followed.
+.It Fl R
+If
+.Ar source_file
+designates a directory,
+.Nm
+copies the directory and the entire subtree connected at that point.
+This option also causes symbolic links to be copied, rather than
+indirected through, and for
+.Nm
+to create special files rather than copying them as normal files.
+Created directories have the same mode as the corresponding source
+directory, unmodified by the process' umask.
+.It Fl f
+Foreach existing destination pathname, attempt to overwrite it. If permissions
+do not allow copy to succeed, remove it and create a new file, without
+prompting for confirmation.
+(The
+.Fl i
+option is ignored if the
+.Fl f
+option is specified.)
+.It Fl i
+Causes
+.Nm
+to write a prompt to the standard error output before copying a file
+that would overwrite an existing file.
+If the response from the standard input begins with the character
+.Sq Li y ,
+the file copy is attempted.
+.It Fl p
+Causes
+.Nm
+to preserve in the copy as many of the modification time, access time,
+file flags, file mode, user ID, and group ID as allowed by permissions.
+.Pp
+If the user ID and group ID cannot be preserved, no error message
+is displayed and the exit value is not altered.
+.Pp
+If the source file has its set user ID bit on and the user ID cannot
+be preserved, the set user ID bit is not preserved
+in the copy's permissions.
+If the source file has its set group ID bit on and the group ID cannot
+be preserved, the set group ID bit is not preserved
+in the copy's permissions.
+If the source file has both its set user ID and set group ID bits on,
+and either the user ID or group ID cannot be preserved, neither
+the set user ID or set group ID bits are preserved in the copy's
+permissions.
+.El
+.Pp
+For each destination file that already exists, its contents are
+overwritten if permissions allow, but its mode, user ID, and group
+ID are unchanged.
+.Pp
+In the second synopsis form, 
+.Ar target_directory 
+must exist unless there is only one named
+.Ar source_file
+which is a directory and the 
+.Fl R 
+flag is specified.
+.Pp
+If the destination file does not exist, the mode of the source file is
+used as modified by the file mode creation mask
+.Pf ( Ic umask ,
+see
+.Xr csh 1 ) .
+If the source file has its set user ID bit on, that bit is removed
+unless both the source file and the destination file are owned by the
+same user.
+If the source file has its set group ID bit on, that bit is removed
+unless both the source file and the destination file are in the same
+group and the user is a member of that group.
+If both the set user ID and set group ID bits are set, all of the above
+conditions must be fulfilled or both bits are removed.
+.Pp
+Appropriate permissions are required for file creation or overwriting.
+.Pp
+Symbolic links are always followed unless the 
+.Fl R 
+flag is set, in which case symbolic links are not followed, by default.
+The
+.Fl H
+or 
+.Fl L
+flags (in conjunction with the
+.Fl R
+flag) cause symbolic links to be followed as described above.
+The
+.Fl H ,
+.Fl L
+and
+.Fl P
+options are ignored unless the
+.Fl R
+option is specified.
+In addition, these options override each other and the
+command's actions are determined by the last one specified.
+.Pp
+.Nm
+exits 0 on success, >0 if an error occurred.
+.Sh COMPATIBILITY
+Historic versions of the
+.Nm
+utility had a
+.Fl r
+option.
+This implementation supports that option, however, its use is strongly
+discouraged, as it does not correctly copy special files, symbolic links
+or fifo's.
+.Sh SEE ALSO
+.Xr mv 1 ,
+.Xr rcp 1 ,
+.Xr umask 2 , 
+.Xr fts 3 ,
+.Xr symlink 7
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be
+.St -p1003.2
+compatible.
diff --git a/cp/cp.c b/cp/cp.c
new file mode 100644
index 0000000..55377bc
--- /dev/null
+++ b/cp/cp.c
@@ -0,0 +1,484 @@
+/*	$NetBSD: cp.c,v 1.24 1998/08/19 01:29:11 thorpej Exp $	*/
+
+/*
+ * Copyright (c) 1988, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * David Hitz of Auspex Systems Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT(
+"@(#) Copyright (c) 1988, 1993, 1994\n\
+	The Regents of the University of California.  All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)cp.c	8.5 (Berkeley) 4/29/95";
+#else
+__RCSID("$NetBSD: cp.c,v 1.24 1998/08/19 01:29:11 thorpej Exp $");
+#endif
+#endif /* not lint */
+
+/*
+ * Cp copies source files to target files.
+ * 
+ * The global PATH_T structure "to" always contains the path to the
+ * current target file.  Since fts(3) does not change directories,
+ * this path can be either absolute or dot-relative.
+ * 
+ * The basic algorithm is to initialize "to" and use fts(3) to traverse
+ * the file hierarchy rooted in the argument list.  A trivial case is the
+ * case of 'cp file1 file2'.  The more interesting case is the case of
+ * 'cp file1 file2 ... fileN dir' where the hierarchy is traversed and the
+ * path (relative to the root of the traversal) is appended to dir (stored
+ * in "to") to form the final target path.
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+#define	STRIP_TRAILING_SLASH(p) {					\
+        while ((p).p_end > (p).p_path + 1 && (p).p_end[-1] == '/')	\
+                *--(p).p_end = 0;					\
+}
+
+PATH_T to = { to.p_path, "" };
+
+uid_t myuid;
+int Rflag, iflag, pflag, rflag, fflag;
+mode_t myumask;
+
+enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
+
+int main __P((int, char *[]));
+int copy __P((char *[], enum op, int));
+int mastercmp __P((const FTSENT **, const FTSENT **));
+
+int
+main(argc, argv)
+	int argc;
+	char *argv[];
+{
+	struct stat to_stat, tmp_stat;
+	enum op type;
+	int Hflag, Lflag, Pflag, ch, fts_options, r;
+	char *target;
+
+	Hflag = Lflag = Pflag = Rflag = 0;
+	while ((ch = getopt(argc, argv, "HLPRfipr")) != -1) 
+		switch (ch) {
+		case 'H':
+			Hflag = 1;
+			Lflag = Pflag = 0;
+			break;
+		case 'L':
+			Lflag = 1;
+			Hflag = Pflag = 0;
+			break;
+		case 'P':
+			Pflag = 1;
+			Hflag = Lflag = 0;
+			break;
+		case 'R':
+			Rflag = 1;
+			break;
+		case 'f':
+			fflag = 1;
+			iflag = 0;
+			break;
+		case 'i':
+			iflag = isatty(fileno(stdin));
+			fflag = 0;
+			break;
+		case 'p':
+			pflag = 1;
+			break;
+		case 'r':
+			rflag = 1;
+			break;
+		case '?':
+		default:
+			usage();
+			break;
+		}
+	argc -= optind;
+	argv += optind;
+
+	if (argc < 2)
+		usage();
+
+	fts_options = FTS_NOCHDIR | FTS_PHYSICAL;
+	if (rflag) {
+		if (Rflag)
+			errx(1,
+		    "the -R and -r options may not be specified together.");
+		if (Hflag || Lflag || Pflag)
+			errx(1,
+	"the -H, -L, and -P options may not be specified with the -r option.");
+		fts_options &= ~FTS_PHYSICAL;
+		fts_options |= FTS_LOGICAL;
+	}
+	if (Rflag) {
+		if (Hflag)
+			fts_options |= FTS_COMFOLLOW;
+		if (Lflag) {
+			fts_options &= ~FTS_PHYSICAL;
+			fts_options |= FTS_LOGICAL;
+		}
+	} else {
+		fts_options &= ~FTS_PHYSICAL;
+		fts_options |= FTS_LOGICAL;
+	}
+
+	myuid = getuid();
+
+	/* Copy the umask for explicit mode setting. */
+	myumask = umask(0);
+	(void)umask(myumask);
+
+	/* Save the target base in "to". */
+	target = argv[--argc];
+	if (strlen(target) > MAXPATHLEN)
+		errx(1, "%s: name too long", target);
+	(void)strcpy(to.p_path, target);
+	to.p_end = to.p_path + strlen(to.p_path);
+        if (to.p_path == to.p_end) {
+		*to.p_end++ = '.';
+		*to.p_end = 0;
+	}
+        STRIP_TRAILING_SLASH(to);
+	to.target_end = to.p_end;
+
+	/* Set end of argument list for fts(3). */
+	argv[argc] = NULL;     
+	
+	/*
+	 * Cp has two distinct cases:
+	 *
+	 * cp [-R] source target
+	 * cp [-R] source1 ... sourceN directory
+	 *
+	 * In both cases, source can be either a file or a directory.
+	 *
+	 * In (1), the target becomes a copy of the source. That is, if the
+	 * source is a file, the target will be a file, and likewise for
+	 * directories.
+	 *
+	 * In (2), the real target is not directory, but "directory/source".
+	 */
+	r = stat(to.p_path, &to_stat);
+	if (r == -1 && errno != ENOENT)
+		err(1, "%s", to.p_path);
+	if (r == -1 || !S_ISDIR(to_stat.st_mode)) {
+		/*
+		 * Case (1).  Target is not a directory.
+		 */ 
+		if (argc > 1) {
+			usage();
+			exit(1);
+		}
+		/*
+		 * Need to detect the case:
+		 *	cp -R dir foo
+		 * Where dir is a directory and foo does not exist, where
+		 * we want pathname concatenations turned on but not for
+		 * the initial mkdir().
+		 */
+		if (r == -1) {
+			if (rflag || (Rflag && (Lflag || Hflag)))
+				r = stat(*argv, &tmp_stat);
+			else
+				r = lstat(*argv, &tmp_stat);
+			if (r == -1)
+				err(1, "%s", *argv);
+			
+			if (S_ISDIR(tmp_stat.st_mode) && (Rflag || rflag))
+				type = DIR_TO_DNE;
+			else
+				type = FILE_TO_FILE;
+		} else
+			type = FILE_TO_FILE;
+	} else {
+		/*
+		 * Case (2).  Target is a directory.
+		 */
+		type = FILE_TO_DIR;
+	}
+
+	exit (copy(argv, type, fts_options));
+	/* NOTREACHED */
+}
+
+int
+copy(argv, type, fts_options)
+	char *argv[];
+	enum op type;
+	int fts_options;
+{
+	struct stat to_stat;
+	FTS *ftsp;
+	FTSENT *curr;
+	int base, dne, nlen, rval;
+	char *p, *tmp;
+
+	base = 0;	/* XXX gcc -Wuninitialized (see comment below) */
+
+	if ((ftsp = fts_open(argv, fts_options, mastercmp)) == NULL)
+		err(1, argv[0]);
+	for (rval = 0; (curr = fts_read(ftsp)) != NULL;) {
+		switch (curr->fts_info) {
+		case FTS_NS:
+		case FTS_ERR:
+			warnx("%s: %s",
+			    curr->fts_path, strerror(curr->fts_errno));
+			rval = 1;
+			continue;
+		case FTS_DC:			/* Warn, continue. */
+			warnx("%s: directory causes a cycle", curr->fts_path);
+			rval = 1;
+			continue;
+		}
+
+		/*
+		 * If we are in case (2) or (3) above, we need to append the 
+                 * source name to the target name.  
+                 */
+		if (type != FILE_TO_FILE) {
+			if ((curr->fts_namelen +
+			    to.target_end - to.p_path + 1) > MAXPATHLEN) {
+				warnx("%s/%s: name too long (not copied)", 
+				    to.p_path, curr->fts_name);
+				rval = 1;
+				continue;
+			}
+
+			/*
+			 * Need to remember the roots of traversals to create
+			 * correct pathnames.  If there's a directory being
+			 * copied to a non-existent directory, e.g.
+			 *	cp -R a/dir noexist
+			 * the resulting path name should be noexist/foo, not
+			 * noexist/dir/foo (where foo is a file in dir), which
+			 * is the case where the target exists.
+			 *
+			 * Also, check for "..".  This is for correct path
+			 * concatentation for paths ending in "..", e.g.
+			 *	cp -R .. /tmp
+			 * Paths ending in ".." are changed to ".".  This is
+			 * tricky, but seems the easiest way to fix the problem.
+			 *
+			 * XXX
+			 * Since the first level MUST be FTS_ROOTLEVEL, base
+			 * is always initialized.
+			 */
+			if (curr->fts_level == FTS_ROOTLEVEL) {
+				if (type != DIR_TO_DNE) {
+					p = strrchr(curr->fts_path, '/');
+					base = (p == NULL) ? 0 : 
+					    (int)(p - curr->fts_path + 1);
+
+					if (!strcmp(&curr->fts_path[base], 
+					    ".."))
+						base += 1;
+				} else
+					base = curr->fts_pathlen;
+			}
+
+			p = &curr->fts_path[base];
+			nlen = curr->fts_pathlen - base;
+
+			tmp = to.target_end;
+			if (*p != '/' && *(tmp - 1) != '/')
+				*tmp++ = '/';
+			*tmp = 0;
+
+			(void)strncat(tmp, p, nlen);
+			to.p_end = tmp + nlen;
+			*to.p_end = 0;
+			STRIP_TRAILING_SLASH(to);
+		}
+
+		/* Not an error but need to remember it happened */
+		if (stat(to.p_path, &to_stat) == -1)
+			dne = 1;
+		else {
+			if (to_stat.st_dev == curr->fts_statp->st_dev &&
+			    to_stat.st_ino == curr->fts_statp->st_ino) {
+				warnx("%s and %s are identical (not copied).",
+				    to.p_path, curr->fts_path);
+				rval = 1;
+				if (S_ISDIR(curr->fts_statp->st_mode))
+					(void)fts_set(ftsp, curr, FTS_SKIP);
+				continue;
+			}
+			if (!S_ISDIR(curr->fts_statp->st_mode) &&
+			    S_ISDIR(to_stat.st_mode)) {
+		warnx("cannot overwrite directory %s with non-directory %s",
+				    to.p_path, curr->fts_path);
+				rval = 1;
+				continue;
+			}
+			dne = 0;
+		}
+
+		switch (curr->fts_statp->st_mode & S_IFMT) {
+		case S_IFLNK:
+			if (copy_link(curr, !dne))
+				rval = 1;
+			break;
+		case S_IFDIR:
+			if (!Rflag && !rflag) {
+				if (curr->fts_info == FTS_DP)
+					warnx("%s is a directory (not copied).",
+					    curr->fts_path);
+				(void)fts_set(ftsp, curr, FTS_SKIP);
+				rval = 1;
+				break;
+			}
+
+                        /*
+                         * Directories get noticed twice:
+                         *  In the first pass, create it if needed.
+                         *  In the second pass, after the children have been copied, set the permissions.
+                         */
+			if (curr->fts_info == FTS_D) /* First pass */
+			{
+				/*
+				 * If the directory doesn't exist, create the new
+				 * one with the from file mode plus owner RWX bits,
+				 * modified by the umask.  Trade-off between being
+				 * able to write the directory (if from directory is
+				 * 555) and not causing a permissions race.  If the
+				 * umask blocks owner writes, we fail..
+				 */
+				if (dne) {
+					if (mkdir(to.p_path, 
+					    curr->fts_statp->st_mode | S_IRWXU) < 0)
+						err(1, "%s", to.p_path);
+				} else if (!S_ISDIR(to_stat.st_mode)) {
+					errno = ENOTDIR;
+					err(1, "%s", to.p_path);
+				}
+			}
+			else if (curr->fts_info == FTS_DP) /* Second pass */
+			{
+	                        /*
+				 * If not -p and directory didn't exist, set it to be
+				 * the same as the from directory, umodified by the 
+                        	 * umask; arguably wrong, but it's been that way 
+                        	 * forever.
+				 */
+				if (pflag && setfile(curr->fts_statp, 0))
+					rval = 1;
+				else if (dne)
+					(void)chmod(to.p_path, 
+					    curr->fts_statp->st_mode);
+			}
+			else
+                        {
+                        	warnx("directory %s encountered when not expected.", curr->fts_path);
+                        	rval = 1;
+                                break;
+                        }
+
+			break;
+		case S_IFBLK:
+		case S_IFCHR:
+			if (Rflag) {
+				if (copy_special(curr->fts_statp, !dne))
+					rval = 1;
+			} else
+				if (copy_file(curr, dne))
+					rval = 1;
+			break;
+		case S_IFIFO:
+			if (Rflag) {
+				if (copy_fifo(curr->fts_statp, !dne))
+					rval = 1;
+			} else 
+				if (copy_file(curr, dne))
+					rval = 1;
+			break;
+		default:
+			if (copy_file(curr, dne))
+				rval = 1;
+			break;
+		}
+	}
+	if (errno)
+		err(1, "fts_read");
+	return (rval);
+}
+
+/*
+ * mastercmp --
+ *	The comparison function for the copy order.  The order is to copy
+ *	non-directory files before directory files.  The reason for this
+ *	is because files tend to be in the same cylinder group as their
+ *	parent directory, whereas directories tend not to be.  Copying the
+ *	files first reduces seeking.
+ */
+int
+mastercmp(a, b)
+	const FTSENT **a, **b;
+{
+	int a_info, b_info;
+
+	a_info = (*a)->fts_info;
+	if (a_info == FTS_ERR || a_info == FTS_NS || a_info == FTS_DNR)
+		return (0);
+	b_info = (*b)->fts_info;
+	if (b_info == FTS_ERR || b_info == FTS_NS || b_info == FTS_DNR)
+		return (0);
+	if (a_info == FTS_D)
+		return (-1);
+	if (b_info == FTS_D)
+		return (1);
+	return (0);
+}
diff --git a/cp/extern.h b/cp/extern.h
new file mode 100644
index 0000000..7ae079e
--- /dev/null
+++ b/cp/extern.h
@@ -0,0 +1,59 @@
+/*	$NetBSD: extern.h,v 1.4 1998/07/28 03:47:14 mycroft Exp $	*/
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)extern.h	8.2 (Berkeley) 4/1/94
+ */
+
+typedef struct {
+	char *p_end;			/* pointer to NULL at end of path */
+	char *target_end;               /* pointer to end of target base */
+	char p_path[MAXPATHLEN + 1];	/* pointer to the start of a path */
+} PATH_T;
+
+extern PATH_T to;
+extern uid_t myuid;
+extern int iflag, pflag, fflag;
+extern mode_t myumask;
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int	copy_fifo __P((struct stat *, int));
+int	copy_file __P((FTSENT *, int));
+int	copy_link __P((FTSENT *, int));
+int	copy_special __P((struct stat *, int));
+int	set_utimes __P((const char *, struct stat *));
+int	setfile __P((struct stat *, int));
+void	usage __P((void));
+__END_DECLS
diff --git a/cp/utils.c b/cp/utils.c
new file mode 100644
index 0000000..5a61282
--- /dev/null
+++ b/cp/utils.c
@@ -0,0 +1,356 @@
+/*	$NetBSD: utils.c,v 1.15 1998/08/19 01:29:11 thorpej Exp $	*/
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)utils.c	8.3 (Berkeley) 4/1/94";
+#else
+__RCSID("$NetBSD: utils.c,v 1.15 1998/08/19 01:29:11 thorpej Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+int
+set_utimes(file, fs)
+	const char * file;
+	struct stat * fs;
+{
+    static struct timeval tv[2];
+
+    TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec);
+    TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec);
+
+    if (utimes(file, tv)) {
+	warn("utimes: %s", file);
+	return (1);
+    }
+    return (0);
+}
+
+int
+copy_file(entp, dne)
+	FTSENT *entp;
+	int dne;
+{
+	static char buf[MAXBSIZE];
+	struct stat to_stat, *fs;
+	int ch, checkch, from_fd, rcount, rval, to_fd, wcount;
+#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
+	char *p;
+#endif
+	
+	if ((from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) {
+		warn("%s", entp->fts_path);
+		return (1);
+	}
+
+	fs = entp->fts_statp;
+
+	/*
+	 * If the file exists and we're interactive, verify with the user.
+	 * If the file DNE, set the mode to be the from file, minus setuid
+	 * bits, modified by the umask; arguably wrong, but it makes copying
+	 * executables work right and it's been that way forever.  (The
+	 * other choice is 666 or'ed with the execute bits on the from file
+	 * modified by the umask.)
+	 */
+	if (!dne) {
+		if (iflag) {
+			(void)fprintf(stderr, "overwrite %s? ", to.p_path);
+			checkch = ch = getchar();
+			while (ch != '\n' && ch != EOF)
+				ch = getchar();
+			if (checkch != 'y' && checkch != 'Y') {
+				(void)close(from_fd);
+				return (0);
+			}
+		}
+		/* overwrite existing destination file name */
+		to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0);
+	} else
+		to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
+		    fs->st_mode & ~(S_ISUID | S_ISGID));
+
+	if (to_fd == -1 && fflag) {
+		/*
+		 * attempt to remove existing destination file name and
+		 * create a new file
+		 */
+		(void)unlink(to.p_path);
+		to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
+			     fs->st_mode & ~(S_ISUID | S_ISGID));
+	}
+
+	if (to_fd == -1) {
+		warn("%s", to.p_path);
+		(void)close(from_fd);
+		return (1);;
+	}
+
+	rval = 0;
+
+	/*
+	 * There's no reason to do anything other than close the file
+	 * now if it's empty, so let's not bother.
+	 */
+	if (fs->st_size > 0) {
+		/*
+		 * Mmap and write if less than 8M (the limit is so we don't totally
+		 * trash memory on big files).  This is really a minor hack, but it
+		 * wins some CPU back.
+		 */
+#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
+		if (fs->st_size <= 8 * 1048576) {
+			if ((p = mmap(NULL, (size_t)fs->st_size, PROT_READ,
+			    MAP_FILE|MAP_SHARED, from_fd, (off_t)0)) == (char *)-1) {
+				warn("%s", entp->fts_path);
+				rval = 1;
+			} else {
+				if (write(to_fd, p, fs->st_size) != fs->st_size) {
+					warn("%s", to.p_path);
+					rval = 1;
+				}
+				/* Some systems don't unmap on close(2). */
+				if (munmap(p, fs->st_size) < 0) {
+					warn("%s", entp->fts_path);
+					rval = 1;
+				}
+			}
+		} else
+#endif
+		{
+			while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
+				wcount = write(to_fd, buf, rcount);
+				if (rcount != wcount || wcount == -1) {
+					warn("%s", to.p_path);
+					rval = 1;
+					break;
+				}
+			}
+			if (rcount < 0) {
+				warn("%s", entp->fts_path);
+				rval = 1;
+			}
+		}
+	}
+
+	if (rval == 1) {
+		(void)close(from_fd);
+		(void)close(to_fd);
+		return (1);
+	}
+
+	if (pflag && setfile(fs, to_fd))
+		rval = 1;
+	/*
+	 * If the source was setuid or setgid, lose the bits unless the
+	 * copy is owned by the same user and group.
+	 */
+#define	RETAINBITS \
+	(S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
+	else if (fs->st_mode & (S_ISUID | S_ISGID) && fs->st_uid == myuid) {
+		if (fstat(to_fd, &to_stat)) {
+			warn("%s", to.p_path);
+			rval = 1;
+		} else if (fs->st_gid == to_stat.st_gid &&
+		    fchmod(to_fd, fs->st_mode & RETAINBITS & ~myumask)) {
+			warn("%s", to.p_path);
+			rval = 1;
+		}
+	}
+	(void)close(from_fd);
+	if (close(to_fd)) {
+		warn("%s", to.p_path);
+		rval = 1;
+	}
+	/* set the mod/access times now after close of the fd */
+	if (pflag && set_utimes(to.p_path, fs)) { 
+	    rval = 1;
+	}
+	return (rval);
+}
+
+int
+copy_link(p, exists)
+	FTSENT *p;
+	int exists;
+{
+	int len;
+	char target[MAXPATHLEN];
+
+	if ((len = readlink(p->fts_path, target, sizeof(target))) == -1) {
+		warn("readlink: %s", p->fts_path);
+		return (1);
+	}
+	target[len] = '\0';
+	if (exists && unlink(to.p_path)) {
+		warn("unlink: %s", to.p_path);
+		return (1);
+	}
+	if (symlink(target, to.p_path)) {
+		warn("symlink: %s", target);
+		return (1);
+	}
+	return (pflag ? setfile(p->fts_statp, 0) : 0);
+}
+
+int
+copy_fifo(from_stat, exists)
+	struct stat *from_stat;
+	int exists;
+{
+	if (exists && unlink(to.p_path)) {
+		warn("unlink: %s", to.p_path);
+		return (1);
+	}
+	if (mkfifo(to.p_path, from_stat->st_mode)) {
+		warn("mkfifo: %s", to.p_path);
+		return (1);
+	}
+	return (pflag ? setfile(from_stat, 0) : 0);
+}
+
+int
+copy_special(from_stat, exists)
+	struct stat *from_stat;
+	int exists;
+{
+	if (exists && unlink(to.p_path)) {
+		warn("unlink: %s", to.p_path);
+		return (1);
+	}
+	if (mknod(to.p_path, from_stat->st_mode, from_stat->st_rdev)) {
+		warn("mknod: %s", to.p_path);
+		return (1);
+	}
+	return (pflag ? setfile(from_stat, 0) : 0);
+}
+
+
+/*
+ * Function: setfile
+ *
+ * Purpose:
+ *   Set the owner/group/permissions for the "to" file to the information
+ *   in the stat structure.  If fd is zero, also call set_utimes() to set
+ *   the mod/access times.  If fd is non-zero, the caller must do a utimes
+ *   itself after close(fd).
+ */
+int
+setfile(fs, fd)
+	struct stat *fs;
+	int fd;
+{
+	int rval, islink;
+
+	rval = 0;
+	islink = S_ISLNK(fs->st_mode);
+	fs->st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
+
+	/*
+	 * Changing the ownership probably won't succeed, unless we're root
+	 * or POSIX_CHOWN_RESTRICTED is not set.  Set uid/gid before setting
+	 * the mode; current BSD behavior is to remove all setuid bits on
+	 * chown.  If chown fails, lose setuid/setgid bits.
+	 */
+	if (fd ? fchown(fd, fs->st_uid, fs->st_gid) :
+#ifdef __APPLE__
+	    chown(to.p_path, fs->st_uid, fs->st_gid)) {
+#else
+	    lchown(to.p_path, fs->st_uid, fs->st_gid)) {
+#endif
+		if (errno != EPERM) {
+			warn("chown: %s", to.p_path);
+			rval = 1;
+		}
+		fs->st_mode &= ~(S_ISUID | S_ISGID);
+	}
+#ifdef __APPLE__
+	if (fd ? fchmod(fd, fs->st_mode) : chmod(to.p_path, fs->st_mode)) {
+#else
+	if (fd ? fchmod(fd, fs->st_mode) : lchmod(to.p_path, fs->st_mode)) {
+#endif
+		warn("chmod: %s", to.p_path);
+		rval = 1;
+	}
+
+	if (!islink) {
+		/*
+		 * XXX
+		 * NFS doesn't support chflags; ignore errors unless
+		 * there's reason to believe we're losing bits.
+		 * (Note, this still won't be right if the server
+		 * supports flags and we were trying to *remove* flags
+		 * on a file that we copied, i.e., that we didn't create.)
+		 */
+		errno = 0;
+		if (fd ? fchflags(fd, fs->st_flags) :
+		    chflags(to.p_path, fs->st_flags))
+			if (errno != EOPNOTSUPP || fs->st_flags != 0) {
+				warn("chflags: %s", to.p_path);
+				rval = 1;
+			}
+	}
+	/* if fd is non-zero, caller must call set_utimes() after close() */
+	if (fd == 0 && set_utimes(to.p_path, fs))
+	    rval = 1;
+	return (rval);
+}
+
+void
+usage()
+{
+	(void)fprintf(stderr, "%s\n%s\n",
+	    "usage: cp [-R [-H | -L | -P]] [-f | -i] [-p] src target",
+	    "       cp [-R [-H | -L | -P]] [-f | -i] [-p] src1 ... srcN directory");
+	exit(1);
+	/* NOTREACHED */
+}
diff --git a/csh/strpct.c b/csh/strpct.c
new file mode 100644
index 0000000..ac3b32d
--- /dev/null
+++ b/csh/strpct.c
@@ -0,0 +1,99 @@
+/*	$NetBSD: strpct.c,v 1.2 1998/05/08 18:43:54 fair Exp $	*/
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Erik E. Fair
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Calculate a percentage without resorting to floating point
+ * and return a pointer to a string
+ *
+ * "digits" is the number of digits past the decimal place you want
+ * (zero being the straight percentage with no decimals)
+ *
+ * Erik E. Fair <fair@clock.org>, May 8, 1997
+ */
+
+#include <sys/types.h>
+#include <machine/limits.h>
+
+#include <stdio.h>
+
+char * strpct __P((u_long, u_long, u_int));
+
+char *
+strpct(numerator, denominator, digits)
+	u_long  numerator, denominator;
+	u_int   digits;
+{
+        int i;
+        u_long result, factor;
+        static char     percent[32];
+
+        /* I should check for digit overflow here, too XXX */
+	factor = 100L;
+        for(i = 0; i < digits; i++) {
+                factor *= 10;
+        }
+
+        /* watch out for overflow! */
+        if (numerator < (ULONG_MAX / factor)) {
+                numerator *= factor;
+        } else {
+                /* toss some of the bits of lesser significance */
+                denominator /= factor;
+        }
+
+        if (denominator == 0L)
+                denominator = 1L;
+
+        result = numerator / denominator;
+
+        if (digits == 0) {
+                (void) snprintf(percent, sizeof(percent), "%lu%%", result);
+        } else {
+                char    fmt[32];
+
+                /* indirection to produce the right output format */
+                (void) snprintf(fmt, sizeof(fmt), "%%lu.%%0%ulu%%%%", digits);
+
+                factor /= 100L;         /* undo initialization */
+
+                (void) snprintf(percent, sizeof(percent),
+                        fmt, result / factor, result % factor);
+        }       
+
+        return(percent);
+}
diff --git a/dd/Makefile b/dd/Makefile
new file mode 100644
index 0000000..323723a
--- /dev/null
+++ b/dd/Makefile
@@ -0,0 +1,50 @@
+#
+# Generated by the NeXT Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = dd
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+HFILES = dd.h extern.h
+
+CFILES = args.c conv.c conv_tab.c dd.c misc.c position.c
+
+OTHERSRCS = Makefile Makefile.preamble Makefile.postamble dd.1
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /bin
+LIBS = 
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+
+
+NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/$(NAME)/Build
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
diff --git a/dd/Makefile.postamble b/dd/Makefile.postamble
new file mode 100644
index 0000000..013b558
--- /dev/null
+++ b/dd/Makefile.postamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
diff --git a/dd/Makefile.preamble b/dd/Makefile.preamble
new file mode 100644
index 0000000..9e10e90
--- /dev/null
+++ b/dd/Makefile.preamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
diff --git a/dd/PB.project b/dd/PB.project
new file mode 100644
index 0000000..db89643
--- /dev/null
+++ b/dd/PB.project
@@ -0,0 +1,26 @@
+{
+    DYNAMIC_CODE_GEN = YES; 
+    FILESTABLE = {
+        FRAMEWORKS = (); 
+        H_FILES = (dd.h, extern.h); 
+        OTHER_LINKED = (args.c, conv.c, conv_tab.c, dd.c, misc.c, position.c); 
+        OTHER_SOURCES = (Makefile, Makefile.preamble, Makefile.postamble, dd.1); 
+    }; 
+    LANGUAGE = English; 
+    LOCALIZABLE_FILES = {}; 
+    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
+    NEXTSTEP_BUILDDIR = "/tmp/$(NAME)/Build"; 
+    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
+    NEXTSTEP_INSTALLDIR = /bin; 
+    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
+    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
+    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
+    PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; 
+    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
+    PROJECTNAME = dd; 
+    PROJECTTYPE = Tool; 
+    PROJECTVERSION = 2.8; 
+    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
+    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
+    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
+}
diff --git a/dd/args.c b/dd/args.c
new file mode 100644
index 0000000..733b147
--- /dev/null
+++ b/dd/args.c
@@ -0,0 +1,412 @@
+/*	$NetBSD: args.c,v 1.13 1998/07/28 03:47:15 mycroft Exp $	*/
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)args.c	8.3 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: args.c,v 1.13 1998/07/28 03:47:15 mycroft Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "dd.h"
+#include "extern.h"
+
+static int	c_arg __P((const void *, const void *));
+static int	c_conv __P((const void *, const void *));
+static void	f_bs __P((char *));
+static void	f_cbs __P((char *));
+static void	f_conv __P((char *));
+static void	f_count __P((char *));
+static void	f_files __P((char *));
+static void	f_ibs __P((char *));
+static void	f_if __P((char *));
+static void	f_obs __P((char *));
+static void	f_of __P((char *));
+static void	f_seek __P((char *));
+static void	f_skip __P((char *));
+static u_long	get_bsz __P((char *));
+
+static const struct arg {
+	char *name;
+	void (*f) __P((char *));
+	u_int set, noset;
+} args[] = {
+	{ "bs",		f_bs,		C_BS,	 C_BS|C_IBS|C_OBS|C_OSYNC },
+	{ "cbs",	f_cbs,		C_CBS,	 C_CBS },
+	{ "conv",	f_conv,		0,	 0 },
+	{ "count",	f_count,	C_COUNT, C_COUNT },
+	{ "files",	f_files,	C_FILES, C_FILES },
+	{ "ibs",	f_ibs,		C_IBS,	 C_BS|C_IBS },
+	{ "if",		f_if,		C_IF,	 C_IF },
+	{ "obs",	f_obs,		C_OBS,	 C_BS|C_OBS },
+	{ "of",		f_of,		C_OF,	 C_OF },
+	{ "seek",	f_seek,		C_SEEK,	 C_SEEK },
+	{ "skip",	f_skip,		C_SKIP,	 C_SKIP },
+};
+
+static char *oper;
+
+/*
+ * args -- parse JCL syntax of dd.
+ */
+void
+jcl(argv)
+	char **argv;
+{
+	struct arg *ap, tmp;
+	char *arg;
+
+	in.dbsz = out.dbsz = 512;
+
+	while ((oper = *++argv) != NULL) {
+		if ((arg = strchr(oper, '=')) == NULL)
+			errx(1, "unknown operand %s", oper);
+		*arg++ = '\0';
+		if (!*arg)
+			errx(1, "no value specified for %s", oper);
+		tmp.name = oper;
+		if (!(ap = (struct arg *)bsearch(&tmp, args,
+		    sizeof(args)/sizeof(struct arg), sizeof(struct arg),
+		    c_arg)))
+			errx(1, "unknown operand %s", tmp.name);
+		if (ddflags & ap->noset)
+			errx(1, "%s: illegal argument combination or already set",
+			    tmp.name);
+		ddflags |= ap->set;
+		ap->f(arg);
+	}
+
+	/* Final sanity checks. */
+
+	if (ddflags & C_BS) {
+		/*
+		 * Bs is turned off by any conversion -- we assume the user
+		 * just wanted to set both the input and output block sizes
+		 * and didn't want the bs semantics, so we don't warn.
+		 */
+		if (ddflags & (C_BLOCK|C_LCASE|C_SWAB|C_UCASE|C_UNBLOCK))
+			ddflags &= ~C_BS;
+
+		/* Bs supersedes ibs and obs. */
+		if (ddflags & C_BS && ddflags & (C_IBS|C_OBS))
+			warnx("bs supersedes ibs and obs");
+	}
+
+	/*
+	 * Ascii/ebcdic and cbs implies block/unblock.
+	 * Block/unblock requires cbs and vice-versa.
+	 */
+	if (ddflags & (C_BLOCK|C_UNBLOCK)) {
+		if (!(ddflags & C_CBS))
+			errx(1, "record operations require cbs");
+		if (cbsz == 0)
+			errx(1, "cbs cannot be zero");
+		cfunc = ddflags & C_BLOCK ? block : unblock;
+	} else if (ddflags & C_CBS) {
+		if (ddflags & (C_ASCII|C_EBCDIC)) {
+			if (ddflags & C_ASCII) {
+				ddflags |= C_UNBLOCK;
+				cfunc = unblock;
+			} else {
+				ddflags |= C_BLOCK;
+				cfunc = block;
+			}
+		} else
+			errx(1, "cbs meaningless if not doing record operations");
+		if (cbsz == 0)
+			errx(1, "cbs cannot be zero");
+	} else
+		cfunc = def;
+
+	if (in.dbsz == 0 || out.dbsz == 0)
+		errx(1, "buffer sizes cannot be zero");
+
+	/*
+	 * Check to make sure that the buffers are not too large.
+	 */
+	if (in.dbsz > INT_MAX || out.dbsz > INT_MAX)
+		errx(1, "buffer sizes cannot be greater than %d", INT_MAX);
+
+	/* Read, write and seek calls take off_t as arguments. 
+	 *
+	 * The following check is not done because an off_t is a quad
+	 *  for current NetBSD implementations. 
+	 *
+	 * if (in.offset > INT_MAX/in.dbsz || out.offset > INT_MAX/out.dbsz)
+	 *	errx(1, "seek offsets cannot be larger than %d", INT_MAX);
+	 */
+}
+
+static int
+c_arg(a, b)
+	const void *a, *b;
+{
+
+	return (strcmp(((const struct arg *)a)->name,
+	    ((const struct arg *)b)->name));
+}
+
+static void
+f_bs(arg)
+	char *arg;
+{
+
+	in.dbsz = out.dbsz = (int)get_bsz(arg);
+}
+
+static void
+f_cbs(arg)
+	char *arg;
+{
+
+	cbsz = (int)get_bsz(arg);
+}
+
+static void
+f_count(arg)
+	char *arg;
+{
+
+	cpy_cnt = (u_int)get_bsz(arg);
+	if (!cpy_cnt)
+		terminate(0);
+}
+
+static void
+f_files(arg)
+	char *arg;
+{
+
+	files_cnt = (int)get_bsz(arg);
+}
+
+static void
+f_ibs(arg)
+	char *arg;
+{
+
+	if (!(ddflags & C_BS))
+		in.dbsz = (int)get_bsz(arg);
+}
+
+static void
+f_if(arg)
+	char *arg;
+{
+
+	in.name = arg;
+}
+
+static void
+f_obs(arg)
+	char *arg;
+{
+
+	if (!(ddflags & C_BS))
+		out.dbsz = (int)get_bsz(arg);
+}
+
+static void
+f_of(arg)
+	char *arg;
+{
+
+	out.name = arg;
+}
+
+static void
+f_seek(arg)
+	char *arg;
+{
+
+	out.offset = (u_int)get_bsz(arg);
+}
+
+static void
+f_skip(arg)
+	char *arg;
+{
+
+	in.offset = (u_int)get_bsz(arg);
+}
+
+#ifdef	NO_CONV
+/* Build a small version (i.e. for a ramdisk root) */
+static void
+f_conv(arg)
+	char *arg;
+{
+	errx(1, "conv option disabled");
+}
+#else	/* NO_CONV */
+
+static const struct conv {
+	char *name;
+	u_int set, noset;
+	const u_char *ctab;
+} clist[] = {
+	{ "ascii",	C_ASCII,	C_EBCDIC,	e2a_POSIX },
+	{ "block",	C_BLOCK,	C_UNBLOCK,	NULL },
+	{ "ebcdic",	C_EBCDIC,	C_ASCII,	a2e_POSIX },
+	{ "ibm",	C_EBCDIC,	C_ASCII,	a2ibm_POSIX },
+	{ "lcase",	C_LCASE,	C_UCASE,	NULL },
+	{ "noerror",	C_NOERROR,	0,		NULL },
+	{ "notrunc",	C_NOTRUNC,	0,		NULL },
+	{ "oldascii",	C_ASCII,	C_EBCDIC,	e2a_32V },
+	{ "oldebcdic",	C_EBCDIC,	C_ASCII,	a2e_32V },
+	{ "oldibm",	C_EBCDIC,	C_ASCII,	a2ibm_32V },
+	{ "osync",	C_OSYNC,	C_BS,		NULL },
+	{ "swab",	C_SWAB,		0,		NULL },
+	{ "sync",	C_SYNC,		0,		NULL },
+	{ "ucase",	C_UCASE,	C_LCASE,	NULL },
+	{ "unblock",	C_UNBLOCK,	C_BLOCK,	NULL },
+};
+
+static void
+f_conv(arg)
+	char *arg;
+{
+	struct conv *cp, tmp;
+
+	while (arg != NULL) {
+		tmp.name = strsep(&arg, ",");
+		if (!(cp = (struct conv *)bsearch(&tmp, clist,
+		    sizeof(clist)/sizeof(struct conv), sizeof(struct conv),
+		    c_conv)))
+			errx(1, "unknown conversion %s", tmp.name);
+		if (ddflags & cp->noset)
+			errx(1, "%s: illegal conversion combination", tmp.name);
+		ddflags |= cp->set;
+		if (cp->ctab)
+			ctab = cp->ctab;
+	}
+}
+
+static int
+c_conv(a, b)
+	const void *a, *b;
+{
+
+	return (strcmp(((const struct conv *)a)->name,
+	    ((const struct conv *)b)->name));
+}
+
+#endif	/* NO_CONV */
+
+/*
+ * Convert an expression of the following forms to an unsigned long.
+ * 	1) A positive decimal number.
+ *	2) A positive decimal number followed by a b (mult by 512).
+ *	3) A positive decimal number followed by a k (mult by 1024).
+ *	4) A positive decimal number followed by a m (mult by 512).
+ *	5) A positive decimal number followed by a w (mult by sizeof int)
+ *	6) Two or more positive decimal numbers (with/without k,b or w).
+ *	   seperated by x (also * for backwards compatibility), specifying
+ *	   the product of the indicated values.
+ */
+static u_long
+get_bsz(val)
+	char *val;
+{
+	u_long num, t;
+	char *expr;
+
+	num = strtoul(val, &expr, 0);
+	if (num == ULONG_MAX)			/* Overflow. */
+		err(1, "%s", oper);
+	if (expr == val)			/* No digits. */
+		errx(1, "%s: illegal numeric value", oper);
+
+	switch (*expr) {
+	case 'b':
+		t = num;
+		num *= 512;
+		if (t > num)
+			goto erange;
+		++expr;
+		break;
+	case 'k':
+		t = num;
+		num *= 1024;
+		if (t > num)
+			goto erange;
+		++expr;
+		break;
+	case 'm':
+		t = num;
+		num *= 1048576;
+		if (t > num)
+			goto erange;
+		++expr;
+		break;
+	case 'w':
+		t = num;
+		num *= sizeof(int);
+		if (t > num)
+			goto erange;
+		++expr;
+		break;
+	}
+
+	switch (*expr) {
+	case '\0':
+		break;
+	case '*':				/* Backward compatible. */
+	case 'x':
+		t = num;
+		num *= get_bsz(expr + 1);
+		if (t > num)
+erange:			errx(1, "%s: %s", oper, strerror(ERANGE));
+		break;
+	default:
+		errx(1, "%s: illegal numeric value", oper);
+	}
+	return (num);
+}
diff --git a/dd/conv.c b/dd/conv.c
new file mode 100644
index 0000000..552e0d9
--- /dev/null
+++ b/dd/conv.c
@@ -0,0 +1,283 @@
+/*	$NetBSD: conv.c,v 1.8 1998/07/28 05:15:46 mycroft Exp $	*/
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)conv.c	8.3 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: conv.c,v 1.8 1998/07/28 05:15:46 mycroft Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+
+#include <err.h>
+#include <string.h>
+
+#include "dd.h"
+#include "extern.h"
+
+/*
+ * def --
+ * Copy input to output.  Input is buffered until reaches obs, and then
+ * output until less than obs remains.  Only a single buffer is used.
+ * Worst case buffer calculation is (ibs + obs - 1).
+ */
+void
+def()
+{
+	int cnt;
+	u_char *inp;
+	const u_char *t;
+
+	if ((t = ctab) != NULL)
+		for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp)
+			*inp = t[*inp];
+
+	/* Make the output buffer look right. */
+	out.dbp = in.dbp;
+	out.dbcnt = in.dbcnt;
+
+	if (in.dbcnt >= out.dbsz) {
+		/* If the output buffer is full, write it. */
+		dd_out(0);
+
+		/*
+		 * Ddout copies the leftover output to the beginning of
+		 * the buffer and resets the output buffer.  Reset the
+		 * input buffer to match it.
+	 	 */
+		in.dbp = out.dbp;
+		in.dbcnt = out.dbcnt;
+	}
+}
+
+void
+def_close()
+{
+	/* Just update the count, everything is already in the buffer. */
+	if (in.dbcnt)
+		out.dbcnt = in.dbcnt;
+}
+
+#ifdef	NO_CONV
+/* Build a smaller version (i.e. for a miniroot) */
+/* These can not be called, but just in case...  */
+static char no_block[] = "unblock and -DNO_CONV?";
+void block()       { errx(1, no_block + 2); }
+void block_close() { errx(1, no_block + 2); }
+void unblock()       { errx(1, no_block); }
+void unblock_close() { errx(1, no_block); }
+#else	/* NO_CONV */
+
+/*
+ * Copy variable length newline terminated records with a max size cbsz
+ * bytes to output.  Records less than cbs are padded with spaces.
+ *
+ * max in buffer:  MAX(ibs, cbsz)
+ * max out buffer: obs + cbsz
+ */
+void
+block()
+{
+	static int intrunc;
+	int ch = 0;	/* pacify gcc */
+	int cnt, maxlen;
+	u_char *inp, *outp;
+	const u_char *t;
+
+	/*
+	 * Record truncation can cross block boundaries.  If currently in a
+	 * truncation state, keep tossing characters until reach a newline.
+	 * Start at the beginning of the buffer, as the input buffer is always
+	 * left empty.
+	 */
+	if (intrunc) {
+		for (inp = in.db, cnt = in.dbrcnt;
+		    cnt && *inp++ != '\n'; --cnt);
+		if (!cnt) {
+			in.dbcnt = 0;
+			in.dbp = in.db;
+			return;
+		}
+		intrunc = 0;
+		/* Adjust the input buffer numbers. */
+		in.dbcnt = cnt - 1;
+		in.dbp = inp + cnt - 1;
+	}
+
+	/*
+	 * Copy records (max cbsz size chunks) into the output buffer.  The
+	 * translation is done as we copy into the output buffer.
+	 */
+	for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) {
+		maxlen = MIN(cbsz, in.dbcnt);
+		if ((t = ctab) != NULL)
+			for (cnt = 0;
+			    cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
+				*outp++ = t[ch];
+		else
+			for (cnt = 0;
+			    cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
+				*outp++ = ch;
+		/*
+		 * Check for short record without a newline.  Reassemble the
+		 * input block.
+		 */
+		if (ch != '\n' && in.dbcnt < cbsz) {
+			(void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
+			break;
+		}
+
+		/* Adjust the input buffer numbers. */
+		in.dbcnt -= cnt;
+		if (ch == '\n')
+			--in.dbcnt;
+
+		/* Pad short records with spaces. */
+		if (cnt < cbsz)
+			(void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt);
+		else {
+			/*
+			 * If the next character wouldn't have ended the
+			 * block, it's a truncation.
+			 */
+			if (!in.dbcnt || *inp != '\n')
+				++st.trunc;
+
+			/* Toss characters to a newline. */
+			for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt);
+			if (!in.dbcnt)
+				intrunc = 1;
+			else
+				--in.dbcnt;
+		}
+
+		/* Adjust output buffer numbers. */
+		out.dbp += cbsz;
+		if ((out.dbcnt += cbsz) >= out.dbsz)
+			dd_out(0);
+		outp = out.dbp;
+	}
+	in.dbp = in.db + in.dbcnt;
+}
+
+void
+block_close()
+{
+	/*
+	 * Copy any remaining data into the output buffer and pad to a record.
+	 * Don't worry about truncation or translation, the input buffer is
+	 * always empty when truncating, and no characters have been added for
+	 * translation.  The bottom line is that anything left in the input
+	 * buffer is a truncated record.  Anything left in the output buffer
+	 * just wasn't big enough.
+	 */
+	if (in.dbcnt) {
+		++st.trunc;
+		(void)memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt);
+		(void)memset(out.dbp + in.dbcnt,
+		    ctab ? ctab[' '] : ' ', cbsz - in.dbcnt);
+		out.dbcnt += cbsz;
+	}
+}
+
+/*
+ * Convert fixed length (cbsz) records to variable length.  Deletes any
+ * trailing blanks and appends a newline.
+ *
+ * max in buffer:  MAX(ibs, cbsz) + cbsz
+ * max out buffer: obs + cbsz
+ */
+void
+unblock()
+{
+	int cnt;
+	u_char *inp;
+	const u_char *t;
+
+	/* Translation and case conversion. */
+	if ((t = ctab) != NULL)
+		for (cnt = in.dbrcnt, inp = in.dbp; cnt--;)
+			*--inp = t[*inp];
+	/*
+	 * Copy records (max cbsz size chunks) into the output buffer.  The
+	 * translation has to already be done or we might not recognize the
+	 * spaces.
+	 */
+	for (inp = in.db; in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) {
+		for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t);
+		if (t >= inp) {
+			cnt = t - inp + 1;
+			(void)memmove(out.dbp, inp, cnt);
+			out.dbp += cnt;
+			out.dbcnt += cnt;
+		}
+		++out.dbcnt;
+		*out.dbp++ = '\n';
+		if (out.dbcnt >= out.dbsz)
+			dd_out(0);
+	}
+	if (in.dbcnt)
+		(void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
+	in.dbp = in.db + in.dbcnt;
+}
+
+void
+unblock_close()
+{
+	int cnt;
+	u_char *t;
+
+	if (in.dbcnt) {
+		warnx("%s: short input record", in.name);
+		for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t);
+		if (t >= in.db) {
+			cnt = t - in.db + 1;
+			(void)memmove(out.dbp, in.db, cnt);
+			out.dbp += cnt;
+			out.dbcnt += cnt;
+		}
+		++out.dbcnt;
+		*out.dbp++ = '\n';
+	}
+}
+
+#endif	/* NO_CONV */
diff --git a/dd/conv_tab.c b/dd/conv_tab.c
new file mode 100644
index 0000000..2f41d87
--- /dev/null
+++ b/dd/conv_tab.c
@@ -0,0 +1,291 @@
+/*	$NetBSD: conv_tab.c,v 1.8 1997/07/20 21:58:38 christos Exp $	*/
+
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)conv_tab.c	8.1 (Berkeley) 5/31/93";
+#else
+__RCSID("$NetBSD: conv_tab.c,v 1.8 1997/07/20 21:58:38 christos Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+
+/*
+ * There are currently six tables:
+ *
+ *	ebcdic		-> ascii	32V		conv=oldascii
+ *	ascii		-> ebcdic	32V		conv=oldebcdic
+ *	ascii		-> ibm ebcdic	32V		conv=oldibm
+ *
+ *	ebcdic		-> ascii	POSIX/S5	conv=ascii
+ *	ascii		-> ebcdic	POSIX/S5	conv=ebcdic
+ *	ascii		-> ibm ebcdic	POSIX/S5	conv=ibm
+ *
+ * Other tables are built from these if multiple conversions are being
+ * done.
+ *
+ * Tables used for conversions to/from IBM and EBCDIC to support an extension
+ * to POSIX P1003.2/D11. The tables referencing POSIX contain data extracted
+ * from tables 4-3 and 4-4 in P1003.2/Draft 11.  The historic tables were
+ * constructed by running against a file with all possible byte values.
+ *
+ * More information can be obtained in "Correspondences of 8-Bit and Hollerith
+ * Codes for Computer Environments-A USASI Tutorial", Communications of the
+ * ACM, Volume 11, Number 11, November 1968, pp. 783-789.
+ */
+
+u_char casetab[256];
+
+/* EBCDIC to ASCII -- 32V compatible. */
+const u_char e2a_32V[] = {
+	0000, 0001, 0002, 0003, 0234, 0011, 0206, 0177,		/* 0000 */
+	0227, 0215, 0216, 0013, 0014, 0015, 0016, 0017,		/* 0010 */
+	0020, 0021, 0022, 0023, 0235, 0205, 0010, 0207,		/* 0020 */
+	0030, 0031, 0222, 0217, 0034, 0035, 0036, 0037,		/* 0030 */
+	0200, 0201, 0202, 0203, 0204, 0012, 0027, 0033,		/* 0040 */
+	0210, 0211, 0212, 0213, 0214, 0005, 0006, 0007,		/* 0050 */
+	0220, 0221, 0026, 0223, 0224, 0225, 0226, 0004,		/* 0060 */
+	0230, 0231, 0232, 0233, 0024, 0025, 0236, 0032,		/* 0070 */
+	0040, 0240, 0241, 0242, 0243, 0244, 0245, 0246,		/* 0100 */
+	0247, 0250, 0133, 0056, 0074, 0050, 0053, 0041,		/* 0110 */
+	0046, 0251, 0252, 0253, 0254, 0255, 0256, 0257,		/* 0120 */
+	0260, 0261, 0135, 0044, 0052, 0051, 0073, 0136,		/* 0130 */
+	0055, 0057, 0262, 0263, 0264, 0265, 0266, 0267,		/* 0140 */
+	0270, 0271, 0174, 0054, 0045, 0137, 0076, 0077,		/* 0150 */
+	0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301,		/* 0160 */
+	0302, 0140, 0072, 0043, 0100, 0047, 0075, 0042,		/* 0170 */
+	0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147,		/* 0200 */
+	0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311,		/* 0210 */
+	0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160,		/* 0220 */
+	0161, 0162, 0313, 0314, 0315, 0316, 0317, 0320,		/* 0230 */
+	0321, 0176, 0163, 0164, 0165, 0166, 0167, 0170,		/* 0240 */
+	0171, 0172, 0322, 0323, 0324, 0325, 0326, 0327,		/* 0250 */
+	0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,		/* 0260 */
+	0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,		/* 0270 */
+	0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107,		/* 0300 */
+	0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355,		/* 0310 */
+	0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120,		/* 0320 */
+	0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363,		/* 0330 */
+	0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130,		/* 0340 */
+	0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371,		/* 0350 */
+	0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,		/* 0360 */
+	0070, 0071, 0372, 0373, 0374, 0375, 0376, 0377,		/* 0370 */
+};
+
+/* ASCII to EBCDIC -- 32V compatible. */
+const u_char a2e_32V[] = {
+	0000, 0001, 0002, 0003, 0067, 0055, 0056, 0057,		/* 0000 */
+	0026, 0005, 0045, 0013, 0014, 0015, 0016, 0017,		/* 0010 */
+	0020, 0021, 0022, 0023, 0074, 0075, 0062, 0046,		/* 0020 */
+	0030, 0031, 0077, 0047, 0034, 0035, 0036, 0037,		/* 0030 */
+	0100, 0117, 0177, 0173, 0133, 0154, 0120, 0175,		/* 0040 */
+	0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141,		/* 0050 */
+	0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,		/* 0060 */
+	0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157,		/* 0070 */
+	0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307,		/* 0100 */
+	0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326,		/* 0110 */
+	0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346,		/* 0120 */
+	0347, 0350, 0351, 0112, 0340, 0132, 0137, 0155,		/* 0130 */
+	0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207,		/* 0140 */
+	0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226,		/* 0150 */
+	0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246,		/* 0160 */
+	0247, 0250, 0251, 0300, 0152, 0320, 0241, 0007,		/* 0170 */
+	0040, 0041, 0042, 0043, 0044, 0025, 0006, 0027,		/* 0200 */
+	0050, 0051, 0052, 0053, 0054, 0011, 0012, 0033,		/* 0210 */
+	0060, 0061, 0032, 0063, 0064, 0065, 0066, 0010,		/* 0220 */
+	0070, 0071, 0072, 0073, 0004, 0024, 0076, 0341,		/* 0230 */
+	0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110,		/* 0240 */
+	0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127,		/* 0250 */
+	0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147,		/* 0260 */
+	0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165,		/* 0270 */
+	0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215,		/* 0300 */
+	0216, 0217, 0220, 0232, 0233, 0234, 0235, 0236,		/* 0310 */
+	0237, 0240, 0252, 0253, 0254, 0255, 0256, 0257,		/* 0320 */
+	0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,		/* 0330 */
+	0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,		/* 0340 */
+	0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333,		/* 0350 */
+	0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355,		/* 0360 */
+	0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377,		/* 0370 */
+};
+
+/* ASCII to IBM EBCDIC -- 32V compatible. */
+const u_char a2ibm_32V[] = {
+	0000, 0001, 0002, 0003, 0067, 0055, 0056, 0057,		/* 0000 */
+	0026, 0005, 0045, 0013, 0014, 0015, 0016, 0017,		/* 0010 */
+	0020, 0021, 0022, 0023, 0074, 0075, 0062, 0046,		/* 0020 */
+	0030, 0031, 0077, 0047, 0034, 0035, 0036, 0037,		/* 0030 */
+	0100, 0132, 0177, 0173, 0133, 0154, 0120, 0175,		/* 0040 */
+	0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141,		/* 0050 */
+	0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,		/* 0060 */
+	0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157,		/* 0070 */
+	0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307,		/* 0100 */
+	0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326,		/* 0110 */
+	0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346,		/* 0120 */
+	0347, 0350, 0351, 0255, 0340, 0275, 0137, 0155,		/* 0130 */
+	0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207,		/* 0140 */
+	0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226,		/* 0150 */
+	0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246,		/* 0160 */
+	0247, 0250, 0251, 0300, 0117, 0320, 0241, 0007,		/* 0170 */
+	0040, 0041, 0042, 0043, 0044, 0025, 0006, 0027,		/* 0200 */
+	0050, 0051, 0052, 0053, 0054, 0011, 0012, 0033,		/* 0210 */
+	0060, 0061, 0032, 0063, 0064, 0065, 0066, 0010,		/* 0220 */
+	0070, 0071, 0072, 0073, 0004, 0024, 0076, 0341,		/* 0230 */
+	0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110,		/* 0240 */
+	0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127,		/* 0250 */
+	0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147,		/* 0260 */
+	0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165,		/* 0270 */
+	0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215,		/* 0300 */
+	0216, 0217, 0220, 0232, 0233, 0234, 0235, 0236,		/* 0310 */
+	0237, 0240, 0252, 0253, 0254, 0255, 0256, 0257,		/* 0320 */
+	0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,		/* 0330 */
+	0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,		/* 0340 */
+	0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333,		/* 0350 */
+	0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355,		/* 0360 */
+	0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377,		/* 0370 */
+};
+
+/* EBCDIC to ASCII -- POSIX and System V compatible. */
+const u_char e2a_POSIX[] = {
+	0000, 0001, 0002, 0003, 0234, 0011, 0206, 0177,		/* 0000 */
+	0227, 0215, 0216, 0013, 0014, 0015, 0016, 0017,		/* 0010 */
+	0020, 0021, 0022, 0023, 0235, 0205, 0010, 0207,		/* 0020 */
+	0030, 0031, 0222, 0217, 0034, 0035, 0036, 0037,		/* 0030 */
+	0200, 0201, 0202, 0203, 0204, 0012, 0027, 0033,		/* 0040 */
+	0210, 0211, 0212, 0213, 0214, 0005, 0006, 0007,		/* 0050 */
+	0220, 0221, 0026, 0223, 0224, 0225, 0226, 0004,		/* 0060 */
+	0230, 0231, 0232, 0233, 0024, 0025, 0236, 0032,		/* 0070 */
+	0040, 0240, 0241, 0242, 0243, 0244, 0245, 0246,		/* 0100 */
+	0247, 0250, 0325, 0056, 0074, 0050, 0053, 0174,		/* 0110 */
+	0046, 0251, 0252, 0253, 0254, 0255, 0256, 0257,		/* 0120 */
+	0260, 0261, 0041, 0044, 0052, 0051, 0073, 0176,		/* 0130 */
+	0055, 0057, 0262, 0263, 0264, 0265, 0266, 0267,		/* 0140 */
+	0270, 0271, 0313, 0054, 0045, 0137, 0076, 0077,		/* 0150 */
+	0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301,		/* 0160 */
+	0302, 0140, 0072, 0043, 0100, 0047, 0075, 0042,		/* 0170 */
+	0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147,		/* 0200 */
+	0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311,		/* 0210 */
+	0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160,		/* 0220 */
+	0161, 0162, 0136, 0314, 0315, 0316, 0317, 0320,		/* 0230 */
+	0321, 0345, 0163, 0164, 0165, 0166, 0167, 0170,		/* 0240 */
+	0171, 0172, 0322, 0323, 0324, 0133, 0326, 0327,		/* 0250 */
+	0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,		/* 0260 */
+	0340, 0341, 0342, 0343, 0344, 0135, 0346, 0347,		/* 0270 */
+	0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107,		/* 0300 */
+	0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355,		/* 0310 */
+	0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120,		/* 0320 */
+	0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363,		/* 0330 */
+	0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130,		/* 0340 */
+	0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371,		/* 0350 */
+	0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,		/* 0360 */
+	0070, 0071, 0372, 0373, 0374, 0375, 0376, 0377,		/* 0370 */
+};
+
+/* ASCII to EBCDIC -- POSIX and System V compatible. */
+const u_char a2e_POSIX[] = {
+	0000, 0001, 0002, 0003, 0067, 0055, 0056, 0057,		/* 0000 */
+	0026, 0005, 0045, 0013, 0014, 0015, 0016, 0017,		/* 0010 */
+	0020, 0021, 0022, 0023, 0074, 0075, 0062, 0046,		/* 0020 */
+	0030, 0031, 0077, 0047, 0034, 0035, 0036, 0037,		/* 0030 */
+	0100, 0132, 0177, 0173, 0133, 0154, 0120, 0175,		/* 0040 */
+	0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141,		/* 0050 */
+	0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,		/* 0060 */
+	0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157,		/* 0070 */
+	0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307,		/* 0100 */
+	0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326,		/* 0110 */
+	0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346,		/* 0120 */
+	0347, 0350, 0351, 0255, 0340, 0275, 0232, 0155,		/* 0130 */
+	0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207,		/* 0140 */
+	0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226,		/* 0150 */
+	0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246,		/* 0160 */
+	0247, 0250, 0251, 0300, 0117, 0320, 0137, 0007,		/* 0170 */
+	0040, 0041, 0042, 0043, 0044, 0025, 0006, 0027,		/* 0200 */
+	0050, 0051, 0052, 0053, 0054, 0011, 0012, 0033,		/* 0210 */
+	0060, 0061, 0032, 0063, 0064, 0065, 0066, 0010,		/* 0220 */
+	0070, 0071, 0072, 0073, 0004, 0024, 0076, 0341,		/* 0230 */
+	0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110,		/* 0240 */
+	0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127,		/* 0250 */
+	0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147,		/* 0260 */
+	0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165,		/* 0270 */
+	0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215,		/* 0300 */
+	0216, 0217, 0220, 0152, 0233, 0234, 0235, 0236,		/* 0310 */
+	0237, 0240, 0252, 0253, 0254, 0112, 0256, 0257,		/* 0320 */
+	0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,		/* 0330 */
+	0270, 0271, 0272, 0273, 0274, 0241, 0276, 0277,		/* 0340 */
+	0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333,		/* 0350 */
+	0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355,		/* 0360 */
+	0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377,		/* 0370 */
+};
+
+/* ASCII to IBM EBCDIC -- POSIX and System V compatible. */
+const u_char a2ibm_POSIX[] = {
+	0000, 0001, 0002, 0003, 0067, 0055, 0056, 0057,		/* 0000 */
+	0026, 0005, 0045, 0013, 0014, 0015, 0016, 0017,		/* 0010 */
+	0020, 0021, 0022, 0023, 0074, 0075, 0062, 0046,		/* 0020 */
+	0030, 0031, 0077, 0047, 0034, 0035, 0036, 0037,		/* 0030 */
+	0100, 0132, 0177, 0173, 0133, 0154, 0120, 0175,		/* 0040 */
+	0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141,		/* 0050 */
+	0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,		/* 0060 */
+	0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157,		/* 0070 */
+	0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307,		/* 0100 */
+	0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326,		/* 0110 */
+	0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346,		/* 0120 */
+	0347, 0350, 0351, 0255, 0340, 0275, 0137, 0155,		/* 0130 */
+	0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207,		/* 0140 */
+	0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226,		/* 0150 */
+	0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246,		/* 0160 */
+	0247, 0250, 0251, 0300, 0117, 0320, 0241, 0007,		/* 0170 */
+	0040, 0041, 0042, 0043, 0044, 0025, 0006, 0027,		/* 0200 */
+	0050, 0051, 0052, 0053, 0054, 0011, 0012, 0033,		/* 0210 */
+	0060, 0061, 0032, 0063, 0064, 0065, 0066, 0010,		/* 0220 */
+	0070, 0071, 0072, 0073, 0004, 0024, 0076, 0341,		/* 0230 */
+	0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110,		/* 0240 */
+	0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127,		/* 0250 */
+	0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147,		/* 0260 */
+	0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165,		/* 0270 */
+	0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215,		/* 0300 */
+	0216, 0217, 0220, 0232, 0233, 0234, 0235, 0236,		/* 0310 */
+	0237, 0240, 0252, 0253, 0254, 0255, 0256, 0257,		/* 0320 */
+	0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,		/* 0330 */
+	0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,		/* 0340 */
+	0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333,		/* 0350 */
+	0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355,		/* 0360 */
+	0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377,		/* 0370 */
+};
diff --git a/dd/dd.1 b/dd/dd.1
new file mode 100644
index 0000000..5f98028
--- /dev/null
+++ b/dd/dd.1
@@ -0,0 +1,355 @@
+.\"	$NetBSD: dd.1,v 1.7 1998/02/06 05:39:31 perry Exp $
+.\"
+.\" Copyright (c) 1990, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Keith Muller of the University of California, San Diego.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)dd.1	8.2 (Berkeley) 1/13/94
+.\"
+.Dd January 13, 1994
+.Dt DD 1
+.Os
+.Sh NAME
+.Nm dd
+.Nd convert and copy a file
+.Sh SYNOPSIS
+.Nm
+.Op operands ...
+.Sh DESCRIPTION
+The
+.Nm
+utility copies the standard input to the standard output.
+Input data is read and written in 512-byte blocks.
+If input reads are short, input from multiple reads are aggregated
+to form the output block.
+When finished,
+.Nm
+displays the number of complete and partial input and output blocks
+and truncated input records to the standard error output.
+.Pp
+The following operands are available:
+.Bl -tag -width of=file
+.It Cm bs= Ns Ar n
+Set both input and output block size, superseding the
+.Cm ibs
+and
+.Cm obs
+operands.
+If no conversion values other than
+.Cm noerror ,
+.Cm notrunc
+or
+.Cm sync
+are specified, then each input block is copied to the output as a
+single block without any aggregation of short blocks.
+.It Cm cbs= Ns Ar n
+Set the conversion record size to
+.Va n
+bytes.
+The conversion record size is required by the record oriented conversion
+values.
+.It Cm count= Ns Ar n
+Copy only
+.Va n
+input blocks.
+.It Cm files= Ns Ar n
+Copy
+.Va n
+input files before terminating.
+This operand is only applicable when the input device is a tape.
+.It Cm ibs= Ns Ar n
+Set the input block size to
+.Va n
+bytes instead of the default 512.
+.It Cm if= Ns Ar file
+Read input from
+.Ar file
+instead of the standard input.
+.It Cm obs= Ns Ar n
+Set the output block size to
+.Va n
+bytes instead of the default 512.
+.It Cm of= Ns Ar file
+Write output to
+.Ar file
+instead of the standard output.
+Any regular output file is truncated unless the
+.Cm notrunc
+conversion value is specified.
+If an initial portion of the output file is skipped (see the
+.Cm seek
+operand)
+the output file is truncated at that point.
+.It Cm seek= Ns Ar n
+Seek
+.Va n
+blocks from the beginning of the output before copying.
+On non-tape devices, a
+.Xr lseek 2
+operation is used.
+Otherwise, existing blocks are read and the data discarded.
+If the user does not have read permission for the tape, it is positioned
+using the tape
+.Xr ioctl 2
+function calls.
+If the seek operation is past the end of file, space from the current
+end of file to the specified offset is filled with blocks of
+.Tn NUL
+bytes.
+.It Cm skip= Ns Ar n
+Skip
+.Va n
+blocks from the beginning of the input before copying.
+On input which supports seeks, a
+.Xr lseek 2
+operation is used.
+Otherwise, input data is read and discarded.
+For pipes, the correct number of bytes is read.
+For all other devices, the correct number of blocks is read without
+distinguishing between a partial or complete block being read.
+.It Xo
+.Cm conv=
+.Ns Cm value Ns Op \&, Cm value \&...
+.Xc
+Where
+.Cm value
+is one of the symbols from the following list.
+.Bl -tag -width unblock
+.It Cm ascii , oldascii
+The same as the
+.Cm unblock
+value except that characters are translated from
+.Tn EBCDIC
+to
+.Tn ASCII
+before the
+records are converted.
+(These values imply
+.Cm unblock
+if the operand
+.Cm cbs
+is also specified.)
+There are two conversion maps for
+.Tn ASCII .
+The value
+.Cm ascii
+specifies the recommended one which is compatible with 
+.At V .
+The value
+.Cm oldascii
+specifies the one used in historic
+.Tn AT&T
+and pre-
+.Bx 4.3 Reno
+systems.
+.It Cm block
+Treats the input as a sequence of newline or end-of-file terminated variable
+length records independent of input and output block boundaries.
+Any trailing newline character is discarded.
+Each input record is converted to a fixed length output record where the
+length is specified by the
+.Cm cbs
+operand.
+Input records shorter than the conversion record size are padded with spaces.
+Input records longer than the conversion record size are truncated.
+The number of truncated input records, if any, are reported to the standard
+error output at the completion of the copy.
+.It Cm ebcdic , ibm , oldebcdic , oldibm
+The same as the
+.Cm block
+value except that characters are translated from
+.Tn ASCII
+to
+.Tn EBCDIC
+after the
+records are converted.
+(These values imply
+.Cm block
+if the operand
+.Cm cbs
+is also specified.)
+There are four conversion maps for
+.Tn EBCDIC .
+The value
+.Cm ebcdic
+specifies the recommended one which is compatible with
+.At V .
+The value
+.Cm ibm
+is a slightly different mapping, which is compatible with the
+.At V
+.Cm ibm
+value.
+The values
+.Cm oldebcdic
+and
+.Cm oldibm
+are maps used in historic
+.Tn AT&T
+and pre
+.Bx 4.3 Reno
+systems.
+.It Cm lcase
+Transform uppercase characters into lowercase characters.
+.It Cm noerror
+Do not stop processing on an input error.
+When an input error occurs, a diagnostic message followed by the current
+input and output block counts will be written to the standard error output
+in the same format as the standard completion message.
+If the
+.Cm sync
+conversion is also specified, any missing input data will be replaced
+with
+.Tn NUL
+bytes (or with spaces if a block oriented conversion value was
+specified) and processed as a normal input buffer.
+If the
+.Cm sync
+conversion is not specified, the input block is omitted from the output.
+On input files which are not tapes or pipes, the file offset
+will be positioned past the block in which the error occurred using
+.Xr lseek 2 .
+.It Cm notrunc
+Do not truncate the output file.
+This will preserve any blocks in the output file not explicitly written
+by
+.Nm "" .
+The
+.Cm notrunc
+value is not supported for tapes.
+.It Cm osync
+Pad the final output block to the full output block size.
+If the input file is not a multiple of the output block size
+after conversion, this conversion forces the final output block
+to be the same size as preceding blocks for use on devices that require
+regularly sized blocks to be written.
+This option is incompatible with use of the
+.Cm bs= Ns Ar n
+block size specification.
+.It Cm swab
+Swap every pair of input bytes.
+If an input buffer has an odd number of bytes, the last byte will be
+ignored during swapping.
+.It Cm sync
+Pad every input block to the input buffer size.
+Spaces are used for pad bytes if a block oriented conversion value is
+specified, otherwise
+.Tn NUL
+bytes are used.
+.It Cm ucase
+Transform lowercase characters into uppercase characters.
+.It Cm unblock
+Treats the input as a sequence of fixed length records independent of input
+and output block boundaries.
+The length of the input records is specified by the
+.Cm cbs
+operand.
+Any trailing space characters are discarded and a newline character is
+appended.
+.El
+.El
+.Pp
+Where sizes are specified, a decimal number of bytes is expected.
+If the number ends with a ``b'', ``k'', ``m'' or ``w'', the number
+is multiplied by 512, 1024 (1K), 1048576 (1M) or the number of bytes
+in an integer, respectively.
+Two or more numbers may be separated by an ``x'' to indicate a product.
+.Pp
+When finished,
+.Nm
+displays the number of complete and partial input and output blocks,
+truncated input records and odd-length byte-swapping blocks to the
+standard error output.
+A partial input block is one where less than the input block size
+was read.
+A partial output block is one where less than the output block size
+was written.
+Partial output blocks to tape devices are considered fatal errors.
+Otherwise, the rest of the block will be written.
+Partial output blocks to character devices will produce a warning message.
+A truncated input block is one where a variable length record oriented
+conversion value was specified and the input line was too long to
+fit in the conversion record or was not newline terminated.
+.Pp
+Normally, data resulting from input or conversion or both are aggregated
+into output blocks of the specified size.
+After the end of input is reached, any remaining output is written as
+a block.
+This means that the final output block may be shorter than the output
+block size.
+.Pp
+If
+.Nm
+receives a
+.Dv SIGINFO
+(see the ``status'' argument for
+.Xr stty 1 )
+signal, the current input and output block counts will
+be written to the standard error output
+in the same format as the standard completion message.
+If
+.Nm
+receives a
+.Dv SIGINT
+signal, the current input and output block counts will
+be written to the standard error output
+in the same format as the standard completion message and
+.Nm
+will exit.
+.Pp
+The
+.Nm
+utility exits 0 on success and >0 if an error occurred.
+.Sh SEE ALSO
+.Xr cp 1 ,
+.Xr mt 1 ,
+.Xr tr 1
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be a superset of the
+.St -p1003.2
+standard.
+The
+.Cm files
+operand and the
+.Cm ascii ,
+.Cm ebcdic ,
+.Cm ibm ,
+.Cm oldascii ,
+.Cm oldebcdic
+and
+.Cm oldibm
+values are extensions to the
+.Tn POSIX
+standard.
diff --git a/dd/dd.c b/dd/dd.c
new file mode 100644
index 0000000..17f870f
--- /dev/null
+++ b/dd/dd.c
@@ -0,0 +1,412 @@
+/*	$NetBSD: dd.c,v 1.12 1998/08/19 01:32:44 thorpej Exp $	*/
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1991, 1993, 1994\n\
+	The Regents of the University of California.  All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)dd.c	8.5 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: dd.c,v 1.12 1998/08/19 01:32:44 thorpej Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mtio.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "dd.h"
+#include "extern.h"
+
+static void dd_close __P((void));
+static void dd_in __P((void));
+static void getfdtype __P((IO *));
+static void setup __P((void));
+
+int main __P((int, char *[]));
+
+IO	in, out;		/* input/output state */
+STAT	st;			/* statistics */
+void	(*cfunc) __P((void));	/* conversion function */
+u_long	cpy_cnt;		/* # of blocks to copy */
+u_int	ddflags;		/* conversion options */
+u_int	cbsz;			/* conversion block size */
+u_int	files_cnt = 1;		/* # of files to copy */
+const u_char	*ctab;		/* conversion table */
+
+int
+main(argc, argv)
+	int argc;
+	char *argv[];
+{
+	jcl(argv);
+	setup();
+
+	(void)signal(SIGINFO, summaryx);
+	(void)signal(SIGINT, terminate);
+
+	(void)atexit(summary);
+
+	while (files_cnt--)
+		dd_in();
+
+	dd_close();
+	exit(0);
+	/* NOTREACHED */
+}
+
+static void
+setup()
+{
+	u_int cnt;
+
+	if (in.name == NULL) {
+		in.name = "stdin";
+		in.fd = STDIN_FILENO;
+	} else {
+		in.fd = open(in.name, O_RDONLY, 0);
+		if (in.fd < 0)
+			err(1, "%s", in.name);
+	}
+
+	getfdtype(&in);
+
+	if (files_cnt > 1 && !(in.flags & ISTAPE))
+		errx(1, "files is not supported for non-tape devices");
+
+	if (out.name == NULL) {
+		/* No way to check for read access here. */
+		out.fd = STDOUT_FILENO;
+		out.name = "stdout";
+	} else {
+#define	OFLAGS \
+    (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC))
+		out.fd = open(out.name, O_RDWR | OFLAGS, DEFFILEMODE);
+		/*
+		 * May not have read access, so try again with write only.
+		 * Without read we may have a problem if output also does
+		 * not support seeks.
+		 */
+		if (out.fd < 0) {
+			out.fd = open(out.name, O_WRONLY | OFLAGS, DEFFILEMODE);
+			out.flags |= NOREAD;
+		}
+		if (out.fd < 0)
+			err(1, "%s", out.name);
+	}
+
+	getfdtype(&out);
+
+	/*
+	 * Allocate space for the input and output buffers.  If not doing
+	 * record oriented I/O, only need a single buffer.
+	 */
+	if (!(ddflags & (C_BLOCK|C_UNBLOCK))) {
+		if ((in.db = malloc(out.dbsz + in.dbsz - 1)) == NULL)
+			err(1, "%s", "");
+		out.db = in.db;
+	} else if ((in.db =
+	    malloc((u_int)(MAX(in.dbsz, cbsz) + cbsz))) == NULL ||
+	    (out.db = malloc((u_int)(out.dbsz + cbsz))) == NULL)
+		err(1, "%s", "");
+	in.dbp = in.db;
+	out.dbp = out.db;
+
+	/* Position the input/output streams. */
+	if (in.offset)
+		pos_in();
+	if (out.offset)
+		pos_out();
+
+	/*
+	 * Truncate the output file; ignore errors because it fails on some
+	 * kinds of output files, tapes, for example.
+	 */
+	if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK))
+		(void)ftruncate(out.fd, (off_t)out.offset * out.dbsz);
+
+	/*
+	 * If converting case at the same time as another conversion, build a
+	 * table that does both at once.  If just converting case, use the
+	 * built-in tables.
+	 */
+	if (ddflags & (C_LCASE|C_UCASE)) {
+#ifdef	NO_CONV
+		/* Should not get here, but just in case... */
+		errx(1, "case conv and -DNO_CONV");
+#else	/* NO_CONV */
+		if (ddflags & C_ASCII || ddflags & C_EBCDIC) {
+			if (ddflags & C_LCASE) {
+				for (cnt = 0; cnt < 0377; ++cnt)
+					casetab[cnt] = tolower(ctab[cnt]);
+			} else {
+				for (cnt = 0; cnt < 0377; ++cnt)
+					casetab[cnt] = toupper(ctab[cnt]);
+			}
+		} else {
+			if (ddflags & C_LCASE) {
+				for (cnt = 0; cnt < 0377; ++cnt)
+					casetab[cnt] = tolower(cnt);
+			} else {
+				for (cnt = 0; cnt < 0377; ++cnt)
+					casetab[cnt] = toupper(cnt);
+			}
+		}
+
+		ctab = casetab;
+#endif	/* NO_CONV */
+	}
+
+	(void)time(&st.start);			/* Statistics timestamp. */
+}
+
+static void
+getfdtype(io)
+	IO *io;
+{
+	struct mtget mt;
+	struct stat sb;
+
+	if (fstat(io->fd, &sb))
+		err(1, "%s", io->name);
+	if (S_ISCHR(sb.st_mode))
+		io->flags |= ioctl(io->fd, MTIOCGET, &mt) ? ISCHR : ISTAPE;
+	else if (lseek(io->fd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE)
+		io->flags |= ISPIPE;		/* XXX fixed in 4.4BSD */
+}
+
+static void
+dd_in()
+{
+	int flags, n;
+
+	for (flags = ddflags;;) {
+		if (cpy_cnt && (st.in_full + st.in_part) >= cpy_cnt)
+			return;
+
+		/*
+		 * Clear the buffer first if doing "sync" on input.
+		 * If doing block operations use spaces.  This will
+		 * affect not only the C_NOERROR case, but also the
+		 * last partial input block which should be padded
+		 * with zero and not garbage.
+		 */
+		if (flags & C_SYNC) {
+			if (flags & (C_BLOCK|C_UNBLOCK))
+				(void)memset(in.dbp, ' ', in.dbsz);
+			else
+				(void)memset(in.dbp, 0, in.dbsz);
+		}
+
+		n = read(in.fd, in.dbp, in.dbsz);
+		if (n == 0) {
+			in.dbrcnt = 0;
+			return;
+		}
+
+		/* Read error. */
+		if (n < 0) {
+			/*
+			 * If noerror not specified, die.  POSIX requires that
+			 * the warning message be followed by an I/O display.
+			 */
+			if (!(flags & C_NOERROR))
+				err(1, "%s", in.name);
+			warn("%s", in.name);
+			summary();
+
+			/*
+			 * If it's not a tape drive or a pipe, seek past the
+			 * error.  If your OS doesn't do the right thing for
+			 * raw disks this section should be modified to re-read
+			 * in sector size chunks.
+			 */
+			if (!(in.flags & (ISPIPE|ISTAPE)) &&
+			    lseek(in.fd, (off_t)in.dbsz, SEEK_CUR))
+				warn("%s", in.name);
+
+			/* If sync not specified, omit block and continue. */
+			if (!(ddflags & C_SYNC))
+				continue;
+
+			/* Read errors count as full blocks. */
+			in.dbcnt += in.dbrcnt = in.dbsz;
+			++st.in_full;
+
+		/* Handle full input blocks. */
+		} else if (n == in.dbsz) {
+			in.dbcnt += in.dbrcnt = n;
+			++st.in_full;
+
+		/* Handle partial input blocks. */
+		} else {
+			/* If sync, use the entire block. */
+			if (ddflags & C_SYNC)
+				in.dbcnt += in.dbrcnt = in.dbsz;
+			else
+				in.dbcnt += in.dbrcnt = n;
+			++st.in_part;
+		}
+
+		/*
+		 * POSIX states that if bs is set and no other conversions
+		 * than noerror, notrunc or sync are specified, the block
+		 * is output without buffering as it is read.
+		 */
+		if (ddflags & C_BS) {
+			out.dbcnt = in.dbcnt;
+			dd_out(1);
+			in.dbcnt = 0;
+			continue;
+		}
+
+		if (ddflags & C_SWAB) {
+			if ((n = in.dbcnt) & 1) {
+				++st.swab;
+				--n;
+			}
+			swab(in.dbp, in.dbp, n);
+		}
+
+		in.dbp += in.dbrcnt;
+		(*cfunc)();
+	}
+}
+
+/*
+ * Cleanup any remaining I/O and flush output.  If necesssary, output file
+ * is truncated.
+ */
+static void
+dd_close()
+{
+	if (cfunc == def)
+		def_close();
+	else if (cfunc == block)
+		block_close();
+	else if (cfunc == unblock)
+		unblock_close();
+	if (ddflags & C_OSYNC && out.dbcnt < out.dbsz) {
+		(void)memset(out.dbp, 0, out.dbsz - out.dbcnt);
+		out.dbcnt = out.dbsz;
+	}
+	if (out.dbcnt)
+		dd_out(1);
+}
+
+void
+dd_out(force)
+	int force;
+{
+	static int warned;
+	int cnt, n, nw;
+	u_char *outp;
+
+	/*
+	 * Write one or more blocks out.  The common case is writing a full
+	 * output block in a single write; increment the full block stats.
+	 * Otherwise, we're into partial block writes.  If a partial write,
+	 * and it's a character device, just warn.  If a tape device, quit.
+	 *
+	 * The partial writes represent two cases.  1: Where the input block
+	 * was less than expected so the output block was less than expected.
+	 * 2: Where the input block was the right size but we were forced to
+	 * write the block in multiple chunks.  The original versions of dd(1)
+	 * never wrote a block in more than a single write, so the latter case
+	 * never happened.
+	 *
+	 * One special case is if we're forced to do the write -- in that case
+	 * we play games with the buffer size, and it's usually a partial write.
+	 */
+	outp = out.db;
+	for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) {
+		for (cnt = n;; cnt -= nw) {
+			nw = write(out.fd, outp, cnt);
+			if (nw <= 0) {
+				if (nw == 0)
+					errx(1, "%s: end of device", out.name);
+				if (errno != EINTR)
+					err(1, "%s", out.name);
+				nw = 0;
+			}
+			outp += nw;
+			st.bytes += nw;
+			if (nw == n) {
+				if (n != out.dbsz)
+					++st.out_part;
+				else
+					++st.out_full;
+				break;
+			}
+			++st.out_part;
+			if (nw == cnt)
+				break;
+			if (out.flags & ISCHR && !warned) {
+				warned = 1;
+				warnx("%s: short write on character device",
+				    out.name);
+			}
+			if (out.flags & ISTAPE)
+				errx(1, "%s: short write on tape device", out.name);
+		}
+		if ((out.dbcnt -= n) < out.dbsz)
+			break;
+	}
+
+	/* Reassemble the output block. */
+	if (out.dbcnt)
+		(void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt);
+	out.dbp = out.db + out.dbcnt;
+}
diff --git a/dd/dd.h b/dd/dd.h
new file mode 100644
index 0000000..6d001ed
--- /dev/null
+++ b/dd/dd.h
@@ -0,0 +1,98 @@
+/*	$NetBSD: dd.h,v 1.5 1998/02/04 06:42:31 enami Exp $	*/
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)dd.h	8.3 (Berkeley) 4/2/94
+ */
+
+/* Input/output stream state. */
+typedef struct {
+	u_char	*db;			/* buffer address */
+	u_char	*dbp;			/* current buffer I/O address */
+	u_long	dbcnt;			/* current buffer byte count */
+	int	dbrcnt;			/* last read byte count */
+	u_long	dbsz;			/* buffer size */
+
+#define	ISCHR		0x01		/* character device (warn on short) */
+#define	ISPIPE		0x02		/* pipe (not truncatable) */
+#define	ISTAPE		0x04		/* tape (not seekable) */
+#define	NOREAD		0x08		/* not readable */
+	u_int	flags;
+
+	char 	*name;			/* name */
+	int	fd;			/* file descriptor */
+	u_long	offset;			/* # of blocks to skip */
+
+	u_long	f_stats;		/* # of full blocks processed */
+	u_long	p_stats;		/* # of partial blocks processed */
+	u_long	s_stats;		/* # of odd swab blocks */
+	u_long	t_stats;		/* # of truncations */
+} IO;
+
+typedef struct {
+	u_long	in_full;		/* # of full input blocks */
+	u_long	in_part;		/* # of partial input blocks */
+	u_long	out_full;		/* # of full output blocks */
+	u_long	out_part;		/* # of partial output blocks */
+	u_long	trunc;			/* # of truncated records */
+	u_long	swab;			/* # of odd-length swab blocks */
+	u_quad_t bytes;			/* # of bytes written */
+	time_t	start;			/* start time of dd */
+} STAT;
+
+/* Flags (in ddflags). */
+#define	C_ASCII		0x00001
+#define	C_BLOCK		0x00002
+#define	C_BS		0x00004
+#define	C_CBS		0x00008
+#define	C_COUNT		0x00010
+#define	C_EBCDIC	0x00020
+#define	C_FILES		0x00040
+#define	C_IBS		0x00080
+#define	C_IF		0x00100
+#define	C_LCASE		0x00200
+#define	C_NOERROR	0x00400
+#define	C_NOTRUNC	0x00800
+#define	C_OBS		0x01000
+#define	C_OF		0x02000
+#define	C_SEEK		0x04000
+#define	C_SKIP		0x08000
+#define	C_SWAB		0x10000
+#define	C_SYNC		0x20000
+#define	C_UCASE		0x40000
+#define	C_UNBLOCK	0x80000
+#define	C_OSYNC		0x100000
diff --git a/dd/extern.h b/dd/extern.h
new file mode 100644
index 0000000..79e272b
--- /dev/null
+++ b/dd/extern.h
@@ -0,0 +1,69 @@
+/*	$NetBSD: extern.h,v 1.8 1997/07/20 21:58:40 christos Exp $	*/
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)extern.h	8.3 (Berkeley) 4/2/94
+ */
+
+#include <sys/cdefs.h>
+
+void block __P((void));
+void block_close __P((void));
+void dd_out __P((int));
+void def __P((void));
+void def_close __P((void));
+void jcl __P((char **));
+void pos_in __P((void));
+void pos_out __P((void));
+void summary __P((void));
+void summaryx __P((int));
+void terminate __P((int));
+void unblock __P((void));
+void unblock_close __P((void));
+
+extern IO in, out;
+extern STAT st;
+extern void (*cfunc) __P((void));
+extern u_long cpy_cnt;
+extern u_int cbsz;
+extern u_int ddflags;
+extern u_int files_cnt;
+extern const u_char *ctab;
+extern const u_char a2e_32V[], a2e_POSIX[];
+extern const u_char e2a_32V[], e2a_POSIX[];
+extern const u_char a2ibm_32V[], a2ibm_POSIX[];
+extern u_char casetab[];
diff --git a/dd/misc.c b/dd/misc.c
new file mode 100644
index 0000000..8254392
--- /dev/null
+++ b/dd/misc.c
@@ -0,0 +1,108 @@
+/*	$NetBSD: misc.c,v 1.8 1998/07/28 05:31:23 mycroft Exp $	*/
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)misc.c	8.3 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: misc.c,v 1.8 1998/07/28 05:31:23 mycroft Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "dd.h"
+#include "extern.h"
+
+void
+summary()
+{
+	time_t secs;
+	char buf[100];
+
+	(void)time(&secs);
+	if ((secs -= st.start) == 0)
+		secs = 1;
+	/* Use snprintf(3) so that we don't reenter stdio(3). */
+	(void)snprintf(buf, sizeof(buf),
+	    "%lu+%lu records in\n%lu+%lu records out\n",
+	    st.in_full, st.in_part, st.out_full, st.out_part);
+	(void)write(STDERR_FILENO, buf, strlen(buf));
+	if (st.swab) {
+		(void)snprintf(buf, sizeof(buf), "%lu odd length swab %s\n",
+		     st.swab, (st.swab == 1) ? "block" : "blocks");
+		(void)write(STDERR_FILENO, buf, strlen(buf));
+	}
+	if (st.trunc) {
+		(void)snprintf(buf, sizeof(buf), "%lu truncated %s\n",
+		     st.trunc, (st.trunc == 1) ? "block" : "blocks");
+		(void)write(STDERR_FILENO, buf, strlen(buf));
+	}
+	(void)snprintf(buf, sizeof(buf),
+	    "%qu bytes transferred in %lu secs (%qu bytes/sec)\n",
+	    (long long) st.bytes, (long) secs, (long long) (st.bytes / secs));
+	(void)write(STDERR_FILENO, buf, strlen(buf));
+}
+
+/* ARGSUSED */
+void
+summaryx(notused)
+	int notused;
+{
+
+	summary();
+}
+
+/* ARGSUSED */
+void
+terminate(notused)
+	int notused;
+{
+
+	exit(0);
+	/* NOTREACHED */
+}
diff --git a/dd/position.c b/dd/position.c
new file mode 100644
index 0000000..e302477
--- /dev/null
+++ b/dd/position.c
@@ -0,0 +1,174 @@
+/*	$NetBSD: position.c,v 1.6 1997/07/25 06:46:24 phil Exp $	*/
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)position.c	8.3 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: position.c,v 1.6 1997/07/25 06:46:24 phil Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mtio.h>
+
+#include <err.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "dd.h"
+#include "extern.h"
+
+/*
+ * Position input/output data streams before starting the copy.  Device type
+ * dependent.  Seekable devices use lseek, and the rest position by reading.
+ * Seeking past the end of file can cause null blocks to be written to the
+ * output.
+ */
+void
+pos_in()
+{
+	int bcnt, cnt, nr, warned;
+
+	/* If not a character, pipe or tape device, try to seek on it. */
+	if (!(in.flags & (ISCHR|ISPIPE|ISTAPE))) {
+		if (lseek(in.fd, (off_t)in.offset * (off_t)in.dbsz, SEEK_CUR)
+		    == -1)
+			err(1, "%s", in.name);
+		return;
+	}
+
+	/*
+	 * Read the data.  If a pipe, read until satisfy the number of bytes
+	 * being skipped.  No differentiation for reading complete and partial
+	 * blocks for other devices.
+	 */
+	for (bcnt = in.dbsz, cnt = in.offset, warned = 0; cnt;) {
+		if ((nr = read(in.fd, in.db, bcnt)) > 0) {
+			if (in.flags & ISPIPE) {
+				if (!(bcnt -= nr)) {
+					bcnt = in.dbsz;
+					--cnt;
+				}
+			} else
+				--cnt;
+			continue;
+		}
+
+		if (nr == 0) {
+			if (files_cnt > 1) {
+				--files_cnt;
+				continue;
+			}
+			errx(1, "skip reached end of input");
+		}
+
+		/*
+		 * Input error -- either EOF with no more files, or I/O error.
+		 * If noerror not set die.  POSIX requires that the warning
+		 * message be followed by an I/O display.
+		 */
+		if (ddflags & C_NOERROR) {
+			if (!warned) {
+				warn("%s", in.name);
+				warned = 1;
+				summary();
+			}
+			continue;
+		}
+		err(1, "%s", in.name);
+	}
+}
+
+void
+pos_out()
+{
+	struct mtop t_op;
+	int cnt, n;
+
+	/*
+	 * If not a tape, try seeking on the file.  Seeking on a pipe is
+	 * going to fail, but don't protect the user -- they shouldn't
+	 * have specified the seek operand.
+	 */
+	if (!(out.flags & ISTAPE)) {
+		if (lseek(out.fd,
+		    (off_t)out.offset * (off_t)out.dbsz, SEEK_SET) == -1)
+			err(1, "%s", out.name);
+		return;
+	}
+
+	/* If no read access, try using mtio. */
+	if (out.flags & NOREAD) {
+		t_op.mt_op = MTFSR;
+		t_op.mt_count = out.offset;
+
+		if (ioctl(out.fd, MTIOCTOP, &t_op) < 0)
+			err(1, "%s", out.name);
+		return;
+	}
+
+	/* Read it. */
+	for (cnt = 0; cnt < out.offset; ++cnt) {
+		if ((n = read(out.fd, out.db, out.dbsz)) > 0)
+			continue;
+
+		if (n < 0)
+			err(1, "%s", out.name);
+
+		/*
+		 * If reach EOF, fill with NUL characters; first, back up over
+		 * the EOF mark.  Note, cnt has not yet been incremented, so
+		 * the EOF read does not count as a seek'd block.
+		 */
+		t_op.mt_op = MTBSR;
+		t_op.mt_count = 1;
+		if (ioctl(out.fd, MTIOCTOP, &t_op) == -1)
+			err(1, "%s", out.name);
+
+		while (cnt++ < out.offset)
+			if ((n = write(out.fd, out.db, out.dbsz)) != out.dbsz)
+				err(1, "%s", out.name);
+		break;
+	}
+}
diff --git a/df/Makefile b/df/Makefile
new file mode 100644
index 0000000..154ddff
--- /dev/null
+++ b/df/Makefile
@@ -0,0 +1,48 @@
+#
+# Generated by the NeXT Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = df
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+CFILES = df.c
+
+OTHERSRCS = Makefile Makefile.preamble Makefile.postamble df.1
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /bin
+LIBS = 
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+
+
+NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/$(NAME)/Build
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
diff --git a/df/Makefile.postamble b/df/Makefile.postamble
new file mode 100644
index 0000000..234330d
--- /dev/null
+++ b/df/Makefile.postamble
@@ -0,0 +1,4 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
+
+INSTALL_AS_GROUP    = operator
+INSTALL_PERMISSIONS = 2555
diff --git a/df/Makefile.preamble b/df/Makefile.preamble
new file mode 100644
index 0000000..7782dbf
--- /dev/null
+++ b/df/Makefile.preamble
@@ -0,0 +1,5 @@
+vpath strpct.c ../csh
+
+CFILES += strpct.c
+
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
diff --git a/df/PB.project b/df/PB.project
new file mode 100644
index 0000000..b036be4
--- /dev/null
+++ b/df/PB.project
@@ -0,0 +1,25 @@
+{
+    DYNAMIC_CODE_GEN = YES; 
+    FILESTABLE = {
+        FRAMEWORKS = (); 
+        OTHER_LINKED = (df.c); 
+        OTHER_SOURCES = (Makefile, Makefile.preamble, Makefile.postamble, df.1); 
+    }; 
+    LANGUAGE = English; 
+    LOCALIZABLE_FILES = {}; 
+    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
+    NEXTSTEP_BUILDDIR = "/tmp/$(NAME)/Build"; 
+    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
+    NEXTSTEP_INSTALLDIR = /bin; 
+    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
+    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
+    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
+    PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; 
+    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
+    PROJECTNAME = df; 
+    PROJECTTYPE = Tool; 
+    PROJECTVERSION = 2.8; 
+    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
+    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
+    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
+}
diff --git a/df/df.1 b/df/df.1
new file mode 100644
index 0000000..ccedb98
--- /dev/null
+++ b/df/df.1
@@ -0,0 +1,122 @@
+.\"	$NetBSD: df.1,v 1.14 1997/10/20 08:51:31 enami Exp $
+.\"
+.\" Copyright (c) 1989, 1990, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)df.1	8.2 (Berkeley) 1/13/92
+.\"
+.Dd January 13, 1994
+.Dt DF 1
+.Os BSD 4
+.Sh NAME
+.Nm df
+.Nd display free disk space
+.Sh SYNOPSIS
+.Nm
+.Op Fl ikln
+.Op Fl t Ar type
+.Op Ar file | Ar file_system ...
+.Sh DESCRIPTION
+.Nm
+displays statistics about the amount of free disk space on the specified
+.Ar file_system
+or on the file system of which
+.Ar file
+is a part.
+Values are displayed in 512-byte per block block counts.
+If neither a file or a
+.Ar file_system
+operand is specified,
+statistics for all mounted file systems are displayed
+(subject to the
+.Fl l
+and
+.Fl t
+options below).
+.Pp
+The following options are available:
+.Bl -tag -width Ds
+.It Fl i
+Include statistics on the number of free inodes.
+.It Fl k
+By default, all sizes are reported in 512-byte block counts.
+The
+.Fl k
+option causes the numbers to be reported in kilobyte counts.
+.It Fl l
+Display statistics only about mounted file systems with the MNT_LOCAL
+flag set.  If a non-local file system is given as an argument, a
+warning is issued and no information is given on that file system.
+.It Fl n
+Print out the previously obtained statistics from the file systems.
+This option should be used if it is possible that one or more
+file systems are in a state such that they will not be able to provide
+statistics without a long delay.
+When this option is specified,
+.Nm
+will not request new statistics from the file systems, but will respond
+with the possibly stale statistics that were previously obtained.
+.It Fl t Ar type
+Is used to indicate the actions should only be taken on
+filesystems of the specified type.
+More than one type may be specified in a comma separated list.
+The list of filesystem types can be prefixed with
+.Dq no
+to specify the filesystem types for which action should
+.Em not
+be taken.  If a file system is given on the command line that is not of
+the specified type, a warning is issued and no information is given on
+that file system.
+.El
+.Sh ENVIRONMENT VARIABLES
+.Bl -tag -width BLOCKSIZE
+.It Ev BLOCKSIZE
+If the environment variable
+.Ev BLOCKSIZE
+is set, and the
+.Fl k
+option is not specified, the block counts will be displayed in units of that
+size block.
+.El
+.Sh SEE ALSO
+.Xr quota 1 ,
+.Xr statfs 2 ,
+.Xr fstatfs 2 ,
+.Xr getfsstat 2 ,
+.Xr getmntinfo 3 ,
+.Xr fstab 5 ,
+.Xr mount 8 ,
+.Xr quot 8
+.Sh HISTORY
+A
+.Nm
+utility appeared in
+.At v6 .
diff --git a/df/df.c b/df/df.c
new file mode 100644
index 0000000..0a1cadd
--- /dev/null
+++ b/df/df.c
@@ -0,0 +1,455 @@
+/*	$NetBSD: df.c,v 1.30 1998/07/28 05:31:24 mycroft Exp $	*/
+
+/*
+ * Copyright (c) 1980, 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT(
+"@(#) Copyright (c) 1980, 1990, 1993, 1994\n\
+	The Regents of the University of California.  All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)df.c	8.7 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: df.c,v 1.30 1998/07/28 05:31:24 mycroft Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+
+#include <ufs/ufs/ufsmount.h>
+
+#ifdef __APPLE__
+#define MOUNT_FFS "ffs"
+#endif
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+extern char * strpct __P((u_long num, u_long denom, u_int digits));
+
+int	 main __P((int, char *[]));
+int	 bread __P((off_t, void *, int));
+char	*getmntpt __P((char *));
+void	 prtstat __P((struct statfs *, int));
+int	 ufs_df __P((char *, struct statfs *));
+int	 selected __P((const char *));
+void	 maketypelist __P((char *));
+long	 regetmntinfo __P((struct statfs **, long));
+void	 usage __P((void));
+
+int	iflag, kflag, lflag, nflag;
+char	**typelist = NULL;
+struct	ufs_args mdev;
+
+int
+main(argc, argv)
+	int argc;
+	char *argv[];
+{
+	struct stat stbuf;
+	struct statfs *mntbuf;
+	long mntsize;
+	int ch, i, maxwidth, width;
+	char *mntpt;
+
+	while ((ch = getopt(argc, argv, "iklnt:")) != -1)
+		switch (ch) {
+		case 'i':
+			iflag = 1;
+			break;
+		case 'k':
+			kflag = 1;
+			break;
+		case 'l':
+			lflag = 1;
+			break;
+		case 'n':
+			nflag = 1;
+			break;
+		case 't':
+			if (typelist != NULL)
+				errx(1, "only one -t option may be specified.");
+			maketypelist(optarg);
+			break;
+		case '?':
+		default:
+			usage();
+		}
+	argc -= optind;
+	argv += optind;
+
+	mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
+	if (mntsize == 0)
+	        err(1, "retrieving information on mounted file systems");
+
+	if (!*argv) {
+		mntsize = regetmntinfo(&mntbuf, mntsize);
+	} else {
+		mntbuf = malloc(argc * sizeof(struct statfs));
+		mntsize = 0;
+		for (; *argv; argv++) {
+			if (stat(*argv, &stbuf) < 0) {
+				if ((mntpt = getmntpt(*argv)) == 0) {
+					warn("%s", *argv);
+					continue;
+				}
+			} else if (S_ISCHR(stbuf.st_mode)) {
+				if (!ufs_df(*argv, &mntbuf[mntsize]))
+					++mntsize;
+				continue;
+			} else if (S_ISBLK(stbuf.st_mode)) {
+				if ((mntpt = getmntpt(*argv)) == 0) {
+#ifdef __APPLE__ /* We lack mkdtemp() */
+					mntpt = mktemp(strdup("/tmp/df.XXXXXX"));
+					mdev.fspec = *argv;
+					if (mkdir(mntpt, DEFFILEMODE) != 0) {
+#else
+					mntpt = strdup("/tmp/df.XXXXXX");
+					if (!mkdtemp(mntpt)) {
+#endif
+						warn("%s", mntpt);
+						continue;
+					}
+					mdev.fspec = *argv;
+					if (mount(MOUNT_FFS, mntpt, MNT_RDONLY,
+					    &mdev) != 0) {
+						(void)rmdir(mntpt);
+						if (!ufs_df(*argv,
+						    &mntbuf[mntsize]))
+							++mntsize;
+						continue;
+					} else if (!statfs(mntpt,
+					    &mntbuf[mntsize])) {
+						mntbuf[mntsize].f_mntonname[0] =
+						    '\0';
+						++mntsize;
+					} else
+						warn("%s", *argv);
+					(void)unmount(mntpt, 0);
+					(void)rmdir(mntpt);
+					continue;
+				}
+			} else
+				mntpt = *argv;
+			/*
+			 * Statfs does not take a `wait' flag, so we cannot
+			 * implement nflag here.
+			 */
+			if (!statfs(mntpt, &mntbuf[mntsize]))
+				if (lflag &&
+				    (mntbuf[mntsize].f_flags & MNT_LOCAL) == 0)
+					warnx("Warning: %s is not a local %s",
+					    *argv, "file system");
+				else if
+				    (!selected(mntbuf[mntsize].f_fstypename))
+					warnx("Warning: %s mounted as a %s %s",
+					    *argv,
+					    mntbuf[mntsize].f_fstypename,
+					    "file system");
+				else
+					++mntsize;
+			else
+				warn("%s", *argv);
+		}
+	}
+
+	maxwidth = 0;
+	for (i = 0; i < mntsize; i++) {
+		width = strlen(mntbuf[i].f_mntfromname);
+		if (width > maxwidth)
+			maxwidth = width;
+	}
+	for (i = 0; i < mntsize; i++)
+		prtstat(&mntbuf[i], maxwidth);
+	exit(0);
+	/* NOTREACHED */
+}
+
+char *
+getmntpt(name)
+	char *name;
+{
+	long mntsize, i;
+	struct statfs *mntbuf;
+
+	mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
+	for (i = 0; i < mntsize; i++) {
+		if (!strcmp(mntbuf[i].f_mntfromname, name))
+			return (mntbuf[i].f_mntonname);
+	}
+	return (0);
+}
+
+static enum { IN_LIST, NOT_IN_LIST } which;
+
+int
+selected(type)
+	const char *type;
+{
+	char **av;
+
+	/* If no type specified, it's always selected. */
+	if (typelist == NULL)
+		return (1);
+	for (av = typelist; *av != NULL; ++av)
+		if (!strncmp(type, *av, MFSNAMELEN))
+			return (which == IN_LIST ? 1 : 0);
+	return (which == IN_LIST ? 0 : 1);
+}
+
+void
+maketypelist(fslist)
+	char *fslist;
+{
+	int i;
+	char *nextcp, **av;
+
+	if ((fslist == NULL) || (fslist[0] == '\0'))
+		errx(1, "empty type list");
+
+	/*
+	 * XXX
+	 * Note: the syntax is "noxxx,yyy" for no xxx's and
+	 * no yyy's, not the more intuitive "noyyy,noyyy".
+	 */
+	if (fslist[0] == 'n' && fslist[1] == 'o') {
+		fslist += 2;
+		which = NOT_IN_LIST;
+	} else
+		which = IN_LIST;
+
+	/* Count the number of types. */
+	for (i = 1, nextcp = fslist;
+	    (nextcp = strchr(nextcp, ',')) != NULL; i++)
+		++nextcp;
+
+	/* Build an array of that many types. */
+	if ((av = typelist = malloc((i + 1) * sizeof(char *))) == NULL)
+		err(1, "can't allocate type array");
+	av[0] = fslist;
+	for (i = 1, nextcp = fslist;
+	    (nextcp = strchr(nextcp, ',')) != NULL; i++) {
+		*nextcp = '\0';
+		av[i] = ++nextcp;
+	}
+	/* Terminate the array. */
+	av[i] = NULL;
+}
+
+/*
+ * Make a pass over the filesystem info in ``mntbuf'' filtering out
+ * filesystem types not in ``fsmask'' and possibly re-stating to get
+ * current (not cached) info.  Returns the new count of valid statfs bufs.
+ */
+long
+regetmntinfo(mntbufp, mntsize)
+	struct statfs **mntbufp;
+	long mntsize;
+{
+	int i, j;
+	struct statfs *mntbuf;
+
+	if (!lflag && typelist == NULL)
+		return (nflag ? mntsize : getmntinfo(mntbufp, MNT_WAIT));
+
+	mntbuf = *mntbufp;
+	j = 0;
+	for (i = 0; i < mntsize; i++) {
+		if (lflag && (mntbuf[i].f_flags & MNT_LOCAL) == 0)
+			continue;
+		if (!selected(mntbuf[i].f_fstypename))
+			continue;
+		if (nflag)
+			mntbuf[j] = mntbuf[i];
+		else
+			(void)statfs(mntbuf[i].f_mntonname, &mntbuf[j]);
+		j++;
+	}
+	return (j);
+}
+
+/*
+ * Convert statfs returned filesystem size into BLOCKSIZE units.
+ * Attempts to avoid overflow for large filesystems.
+ */
+#define fsbtoblk(num, fsbs, bs) \
+        ((long int) ((((float) fsbs) != 0 && ((float) fsbs) < ((float) bs)) ? \
+                ((float) num) / (((float) bs) / ((float) fsbs)) : ((float) num) * (((float) fsbs) / ((float) bs))))
+
+/*
+ * Print out status about a filesystem.
+ */
+void
+prtstat(sfsp, maxwidth)
+	struct statfs *sfsp;
+	int maxwidth;
+{
+	static long blocksize;
+	static int headerlen, timesthrough;
+	static char *header;
+	long used, availblks, inodes;
+	static char     *full = "100%";
+
+	if (maxwidth < 11)
+		maxwidth = 11;
+	if (++timesthrough == 1) {
+		if (kflag) {
+			blocksize = 1024;
+			header = "1K-blocks";
+			headerlen = strlen(header);
+		} else
+			header = getbsize(&headerlen, &blocksize);
+		(void)printf("%-*.*s %s     Used    Avail Capacity",
+		    maxwidth, maxwidth, "Filesystem", header);
+		if (iflag)
+			(void)printf(" iused   ifree  %%iused");
+		(void)printf("  Mounted on\n");
+	}
+	(void)printf("%-*.*s", maxwidth, maxwidth, sfsp->f_mntfromname);
+	used = sfsp->f_blocks - sfsp->f_bfree;
+	availblks = sfsp->f_bavail + used;
+	(void)printf(" %*ld %8ld %8ld", headerlen,
+	    fsbtoblk(sfsp->f_blocks, sfsp->f_bsize, blocksize),
+	    fsbtoblk(used, sfsp->f_bsize, blocksize),
+	    fsbtoblk(sfsp->f_bavail, sfsp->f_bsize, blocksize));
+	(void)printf(" %6s",
+	    availblks == 0 ? full : strpct((u_long)used, (u_long)availblks, 0));
+	if (iflag) {
+		inodes = sfsp->f_files;
+		used = inodes - sfsp->f_ffree;
+		(void)printf(" %7ld %7ld %6s ", used, sfsp->f_ffree,
+		   inodes == 0 ? full : strpct((u_long)used, (u_long)inodes, 0));
+	} else 
+		(void)printf("  ");
+	(void)printf("  %s\n", sfsp->f_mntonname);
+}
+
+/*
+ * This code constitutes the pre-system call Berkeley df code for extracting
+ * information from filesystem superblocks.
+ */
+#include <ufs/ufs/dinode.h>
+#include <ufs/ffs/fs.h>
+#include <errno.h>
+#include <fstab.h>
+
+union {
+	struct fs iu_fs;
+	char dummy[SBSIZE];
+} sb;
+#define sblock sb.iu_fs
+
+int	rfd;
+
+int
+ufs_df(file, sfsp)
+	char *file;
+	struct statfs *sfsp;
+{
+	char *mntpt;
+	static int synced;
+
+	if (synced++ == 0)
+		sync();
+
+	if ((rfd = open(file, O_RDONLY)) < 0) {
+		warn("%s", file);
+		return (-1);
+	}
+	if (bread((off_t)SBOFF, &sblock, SBSIZE) == 0) {
+		(void)close(rfd);
+		return (-1);
+	}
+	sfsp->f_type = 0;
+	sfsp->f_flags = 0;
+	sfsp->f_bsize = sblock.fs_fsize;
+	sfsp->f_iosize = sblock.fs_bsize;
+	sfsp->f_blocks = sblock.fs_dsize;
+	sfsp->f_bfree = sblock.fs_cstotal.cs_nbfree * sblock.fs_frag +
+		sblock.fs_cstotal.cs_nffree;
+	sfsp->f_bavail = freespace(&sblock, sblock.fs_minfree);
+	sfsp->f_files =  sblock.fs_ncg * sblock.fs_ipg;
+	sfsp->f_ffree = sblock.fs_cstotal.cs_nifree;
+	sfsp->f_fsid.val[0] = 0;
+	sfsp->f_fsid.val[1] = 0;
+	if ((mntpt = getmntpt(file)) == 0)
+		mntpt = "";
+	(void)memmove(&sfsp->f_mntonname[0], mntpt, MNAMELEN);
+	(void)memmove(&sfsp->f_mntfromname[0], file, MNAMELEN);
+	(void)strncpy(sfsp->f_fstypename, MOUNT_FFS, MFSNAMELEN);
+	(void)close(rfd);
+	return (0);
+}
+
+int
+bread(off, buf, cnt)
+	off_t off;
+	void *buf;
+	int cnt;
+{
+	int nr;
+
+	(void)lseek(rfd, off, SEEK_SET);
+	if ((nr = read(rfd, buf, cnt)) != cnt) {
+		/* Probably a dismounted disk if errno == EIO. */
+		if (errno != EIO)
+			(void)fprintf(stderr, "\ndf: %qd: %s\n",
+			    (long long)off, strerror(nr > 0 ? EIO : errno));
+		return (0);
+	}
+	return (1);
+}
+
+void
+usage()
+{
+	(void)fprintf(stderr, "usage: df [-ikln] [-t type] [file | file_system ...]\n");
+	exit(1);
+	/* NOTREACHED */
+}
diff --git a/du/Makefile b/du/Makefile
new file mode 100644
index 0000000..d4a2b75
--- /dev/null
+++ b/du/Makefile
@@ -0,0 +1,48 @@
+#
+# Generated by the NeXT Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = du
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+CFILES = du.c
+
+OTHERSRCS = Makefile Makefile.preamble Makefile.postamble du.1
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /usr/bin
+LIBS = 
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+
+
+NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/developer_cmds/Build
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
diff --git a/du/Makefile.postamble b/du/Makefile.postamble
new file mode 100644
index 0000000..013b558
--- /dev/null
+++ b/du/Makefile.postamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
diff --git a/du/Makefile.preamble b/du/Makefile.preamble
new file mode 100644
index 0000000..9e10e90
--- /dev/null
+++ b/du/Makefile.preamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
diff --git a/du/PB.project b/du/PB.project
new file mode 100644
index 0000000..6334025
--- /dev/null
+++ b/du/PB.project
@@ -0,0 +1,25 @@
+{
+    DYNAMIC_CODE_GEN = YES; 
+    FILESTABLE = {
+        FRAMEWORKS = (); 
+        OTHER_LINKED = (du.c); 
+        OTHER_SOURCES = (Makefile, Makefile.preamble, Makefile.postamble, du.1); 
+    }; 
+    LANGUAGE = English; 
+    LOCALIZABLE_FILES = {}; 
+    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
+    NEXTSTEP_BUILDDIR = /tmp/developer_cmds/Build; 
+    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
+    NEXTSTEP_INSTALLDIR = /usr/bin; 
+    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
+    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
+    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
+    PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; 
+    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
+    PROJECTNAME = du; 
+    PROJECTTYPE = Tool; 
+    PROJECTVERSION = 2.8; 
+    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
+    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
+    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
+}
diff --git a/du/du.1 b/du/du.1
new file mode 100644
index 0000000..6c5ca9c
--- /dev/null
+++ b/du/du.1
@@ -0,0 +1,134 @@
+.\"	$NetBSD: du.1,v 1.8 1998/02/15 17:08:17 kleink Exp $
+.\"
+.\" Copyright (c) 1990, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)du.1	8.2 (Berkeley) 4/1/94
+.\"
+.Dd October 4, 1996
+.Dt DU 1
+.Os
+.Sh NAME
+.Nm du
+.Nd display disk usage statistics
+.Sh SYNOPSIS
+.Nm
+.Op Fl H | Fl L | Fl P
+.Op Fl a | Fl s
+.Op Fl ckrx
+.Op Ar file ...
+.Sh DESCRIPTION
+The
+.Nm
+utility displays the file system block usage for each file argument
+and for each directory in the file hierarchy rooted in each directory
+argument.
+If no file is specified, the block usage of the hierarchy rooted in
+the current directory is displayed.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl H
+Symbolic links on the command line are followed.
+(Symbolic links encountered in the tree traversal are not followed.)
+.It Fl L
+All symbolic links are followed.
+.It Fl P
+No symbolic links are followed.
+.It Fl a
+Display an entry for each file in the file hierarchy.
+.It Fl k
+By default,
+.Nm
+displays the number of blocks as returned by the
+.Xr stat  2
+system call, i.e. 512-byte blocks.
+If the
+.Fl k
+flag is specified, the number displayed is the number of 1024-byte
+blocks.
+Partial numbers of blocks are rounded up.
+.It Fl c
+Display the grand total after all the arguments have been processed.
+.It Fl r
+Generate warning messages about directories that cannot be read.
+This is the default behaviour.
+.It Fl s
+Display only the grand total for the specified files.
+.It Fl x
+Filesystem mount points are not traversed.
+.El
+.Pp
+.Nm
+counts the storage used by symbolic links and not the files they
+reference unless the
+.Fl H
+or 
+.Fl L 
+option is specified.  
+If either the
+.Fl H
+or
+.Fl L
+options are specified, storage used by any symbolic links which are
+followed is not counted or displayed.
+The
+.Fl H ,
+.Fl L
+and
+.Fl P
+options override each other and the command's actions are determined
+by the last one specified.
+.Pp
+Files having multiple hard links are counted (and displayed) a single
+time per
+.Nm
+execution.
+.Sh ENVIRONMENT VARIABLES
+.Bl -tag -width BLOCKSIZE
+.It Ev BLOCKSIZE
+If the environment variable
+.Ev BLOCKSIZE
+is set, and the 
+.Fl k
+option is not specified, the block counts will be displayed in units of that
+size block.
+.El
+.Sh SEE ALSO
+.Xr df 1 ,
+.Xr fts 3 ,
+.Xr symlink 7 ,
+.Xr quot 8
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v6 .
diff --git a/du/du.c b/du/du.c
new file mode 100644
index 0000000..3d6914f
--- /dev/null
+++ b/du/du.c
@@ -0,0 +1,255 @@
+/*	$NetBSD: du.c,v 1.14 1998/02/15 17:08:18 kleink Exp $	*/
+
+/*
+ * Copyright (c) 1989, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Newcomb.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1989, 1993, 1994\n\
+	The Regents of the University of California.  All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)du.c	8.5 (Berkeley) 5/4/95";
+#else
+__RCSID("$NetBSD: du.c,v 1.14 1998/02/15 17:08:18 kleink Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int	linkchk __P((FTSENT *));
+int	main __P((int, char **));
+void	usage __P((void));
+
+int
+main(argc, argv)
+	int argc;
+	char *argv[];
+{
+	FTS *fts;
+	FTSENT *p;
+	long blocksize, totalblocks;
+	int ftsoptions, listdirs, listfiles;
+	int Hflag, Lflag, Pflag, aflag, ch, cflag, kflag, notused, rval, sflag;
+	char **save;
+
+	save = argv;
+	Hflag = Lflag = Pflag = aflag = cflag = kflag = sflag = 0;
+	totalblocks = 0;
+	ftsoptions = FTS_PHYSICAL;
+	while ((ch = getopt(argc, argv, "HLPackrsx")) != -1)
+		switch (ch) {
+		case 'H':
+			Hflag = 1;
+			Lflag = Pflag = 0;
+			break;
+		case 'L':
+			Lflag = 1;
+			Hflag = Pflag = 0;
+			break;
+		case 'P':
+			Pflag = 1;
+			Hflag = Lflag = 0;
+			break;
+		case 'a':
+			aflag = 1;
+			break;
+		case 'c':
+			cflag = 1;
+			break;
+		case 'k':
+			blocksize = 1024;
+			kflag = 1;
+			break;
+		case 'r':
+			break;
+		case 's':
+			sflag = 1;
+			break;
+		case 'x':
+			ftsoptions |= FTS_XDEV;
+			break;
+		case '?':
+		default:
+			usage();
+		}
+	argc -= optind;
+	argv += optind;
+
+	/*
+	 * XXX
+	 * Because of the way that fts(3) works, logical walks will not count
+	 * the blocks actually used by symbolic links.  We rationalize this by
+	 * noting that users computing logical sizes are likely to do logical
+	 * copies, so not counting the links is correct.  The real reason is
+	 * that we'd have to re-implement the kernel's symbolic link traversing
+	 * algorithm to get this right.  If, for example, you have relative
+	 * symbolic links referencing other relative symbolic links, it gets
+	 * very nasty, very fast.  The bottom line is that it's documented in
+	 * the man page, so it's a feature.
+	 */
+	if (Hflag)
+		ftsoptions |= FTS_COMFOLLOW;
+	if (Lflag) {
+		ftsoptions &= ~FTS_PHYSICAL;
+		ftsoptions |= FTS_LOGICAL;
+	}
+
+	if (aflag) {
+		if (sflag)
+			usage();
+		listdirs = listfiles = 1;
+	} else if (sflag)
+		listdirs = listfiles = 0;
+	else {
+		listfiles = 0;
+		listdirs = 1;
+	}
+
+	if (!*argv) {
+		argv = save;
+		argv[0] = ".";
+		argv[1] = NULL;
+	}
+
+	if (!kflag)
+		(void)getbsize(&notused, &blocksize);
+	blocksize /= 512;
+
+	if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL)
+		err(1, "fts_open `%s'", *argv);
+
+	for (rval = 0; (p = fts_read(fts)) != NULL;)
+		switch (p->fts_info) {
+		case FTS_D:			/* Ignore. */
+			break;
+		case FTS_DP:
+			p->fts_parent->fts_number += 
+			    p->fts_number += p->fts_statp->st_blocks;
+			if (cflag)
+				totalblocks += p->fts_statp->st_blocks;
+			/*
+			 * If listing each directory, or not listing files
+			 * or directories and this is post-order of the
+			 * root of a traversal, display the total.
+			 */
+			if (listdirs || (!listfiles && !p->fts_level))
+				(void)printf("%ld\t%s\n",
+				    howmany(p->fts_number, blocksize),
+				    p->fts_path);
+			break;
+		case FTS_DC:			/* Ignore. */
+			break;
+		case FTS_DNR:			/* Warn, continue. */
+		case FTS_ERR:
+		case FTS_NS:
+			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
+			rval = 1;
+			break;
+		default:
+			if (p->fts_statp->st_nlink > 1 && linkchk(p))
+				break;
+			/*
+			 * If listing each file, or a non-directory file was
+			 * the root of a traversal, display the total.
+			 */
+			if (listfiles || !p->fts_level)
+				(void)printf("%qd\t%s\n", (long long)
+				    howmany(p->fts_statp->st_blocks, blocksize),
+				    p->fts_path);
+			p->fts_parent->fts_number += p->fts_statp->st_blocks;
+			if (cflag)
+				totalblocks += p->fts_statp->st_blocks;
+		}
+	if (errno)
+		err(1, "fts_read");
+	if (cflag)
+		(void)printf("%ld\ttotal\n",
+		    howmany(totalblocks, blocksize));
+	exit(0);
+}
+
+typedef struct _ID {
+	dev_t	dev;
+	ino_t	inode;
+} ID;
+
+int
+linkchk(p)
+	FTSENT *p;
+{
+	static ID *files;
+	static int maxfiles, nfiles;
+	ID *fp, *start;
+	ino_t ino;
+	dev_t dev;
+
+	ino = p->fts_statp->st_ino;
+	dev = p->fts_statp->st_dev;
+	if ((start = files) != NULL)
+		for (fp = start + nfiles - 1; fp >= start; --fp)
+			if (ino == fp->inode && dev == fp->dev)
+				return (1);
+
+	if (nfiles == maxfiles && (files = realloc((char *)files,
+	    (u_int)(sizeof(ID) * (maxfiles += 128)))) == NULL)
+		err(1, "realloc");
+	files[nfiles].inode = ino;
+	files[nfiles].dev = dev;
+	++nfiles;
+	return (0);
+}
+
+void
+usage()
+{
+
+	(void)fprintf(stderr,
+		"usage: du [-H | -L | -P] [-a | -s] [-ckx] [file ...]\n");
+	exit(1);
+}
diff --git a/install/Makefile b/install/Makefile
new file mode 100644
index 0000000..d36083c
--- /dev/null
+++ b/install/Makefile
@@ -0,0 +1,50 @@
+#
+# Generated by the NeXT Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = install
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+HFILES = pathnames.h
+
+CFILES = xinstall.c
+
+OTHERSRCS = Makefile Makefile.preamble Makefile.postamble install.1
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /usr/bin
+LIBS = 
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+
+
+NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/developer_cmds/Build
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
diff --git a/install/Makefile.postamble b/install/Makefile.postamble
new file mode 100644
index 0000000..013b558
--- /dev/null
+++ b/install/Makefile.postamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
diff --git a/install/Makefile.preamble b/install/Makefile.preamble
new file mode 100644
index 0000000..7a86fc2
--- /dev/null
+++ b/install/Makefile.preamble
@@ -0,0 +1,5 @@
+vpath stat_flags.c ../ls
+
+CFILES += stat_flags.c
+
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
diff --git a/install/PB.project b/install/PB.project
new file mode 100644
index 0000000..519a9e7
--- /dev/null
+++ b/install/PB.project
@@ -0,0 +1,26 @@
+{
+    DYNAMIC_CODE_GEN = YES; 
+    FILESTABLE = {
+        FRAMEWORKS = (); 
+        H_FILES = (pathnames.h); 
+        OTHER_LINKED = (xinstall.c); 
+        OTHER_SOURCES = (Makefile, Makefile.preamble, Makefile.postamble, install.1); 
+    }; 
+    LANGUAGE = English; 
+    LOCALIZABLE_FILES = {}; 
+    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
+    NEXTSTEP_BUILDDIR = /tmp/developer_cmds/Build; 
+    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
+    NEXTSTEP_INSTALLDIR = /usr/bin; 
+    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
+    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
+    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
+    PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; 
+    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
+    PROJECTNAME = install; 
+    PROJECTTYPE = Tool; 
+    PROJECTVERSION = 2.8; 
+    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
+    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
+    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
+}
diff --git a/install/install.1 b/install/install.1
new file mode 100644
index 0000000..e9acb8c
--- /dev/null
+++ b/install/install.1
@@ -0,0 +1,183 @@
+.\"	$NetBSD: install.1,v 1.11 1998/09/28 08:16:15 christos Exp $
+.\"
+.\" Copyright (c) 1987, 1990, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     @(#)install.1	8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt INSTALL 1
+.Os BSD 4.2
+.Sh NAME
+.Nm install
+.Nd install binaries
+.Sh SYNOPSIS
+.Nm
+.Op Fl cps
+.Op Fl f Ar flags
+.Op Fl m Ar mode
+.Op Fl o Ar owner
+.Op Fl g Ar group
+.Op Fl l Ar linkflags
+.Op Fl S Ar stripflag
+.Ar file1 file2
+.Nm ""
+.Op Fl cps
+.Op Fl f Ar flags
+.Op Fl m Ar mode
+.Op Fl o Ar owner
+.Op Fl g Ar group
+.Op Fl l Ar linkflags
+.Op Fl S Ar stripflag
+.Ar file1
+\&...
+.Ar fileN directory
+.Nm ""
+.Fl pd
+.Op Fl m Ar mode
+.Op Fl o Ar owner
+.Op Fl g Ar group
+.Ar directory
+\&...
+.Sh DESCRIPTION
+The file(s) are moved (copied if the
+.Fl c
+option is specified, or linked if the
+.Fl l
+option is specified) to the target file or directory.
+If the destination is a directory, then the
+.Ar file
+is moved into
+.Ar directory
+with its original filename.
+If the target file already exists, it is overwritten if permissions
+allow.
+.Pp
+.Bl -tag -width Ds
+.It Fl c
+Copy the file.
+This flag turns off the default behavior of
+.Nm
+where it deletes the original file after creating the target.
+.It Fl f
+Specify the target's file flags.
+(See
+.Xr chflags 1
+for a list of possible flags and their meanings.)
+.It Fl g
+Specify a group.
+.It Fl m
+Specify an alternative mode.
+The default mode is set to rwxr-xr-x (0755).
+The specified mode may be either an octal or symbolic value; see
+.Xr chmod  1
+for a description of possible mode values.
+.It Fl l Ar linkflags
+Instead of copying the file make a link to the source. The type of the
+link is determined by the 
+.Ar linkflags
+argument. Valid
+.Ar linkflags
+are:
+.Ar a
+(absolute),
+.Ar r
+(relative),
+.Ar h
+(hard),
+.Ar s
+(symbolic),
+.Ar m
+(mixed). Absolute and relative have effect only for symbolic links. Mixed links
+are hard links for files on the same filesystem, symbolic otherwise.
+.It Fl o
+Specify an owner.
+.It Fl p
+Preserve the source files access and modification times.
+.It Fl s
+.Nm
+exec's the command
+.Xr strip  1
+to strip binaries so that install can be portable over a large
+number of systems and binary types.  If the environment variable
+.Ev STRIP
+is set, it is used as the
+.Xr strip 1
+program.
+.It Fl S Ar stripflags
+.Nm
+passes
+.Ar stripflags
+as option arguments to
+.Xr strip  1 .
+When -S is used,
+.Xr strip  1
+is invoked via the
+.Xr sh  1
+shell, allowing a single -S argument be to specified to
+.Nm
+which the shell can then tokenize. Normally,
+.Nm
+invokes
+.Xr strip  1
+directly. This flag implies -s.
+.It Fl d
+Create directories. 
+Missing parent directories are created as required.
+.El
+.Pp
+By default,
+.Nm
+preserves all file flags, with the exception of the ``nodump'' flag.
+.Pp
+The
+.Nm
+utility attempts to prevent moving a file onto itself.
+.Pp
+Installing
+.Pa /dev/null
+creates an empty file.
+.Pp
+Upon successful completion a value of 0 is returned.
+Otherwise, a value of 1 is returned.
+.Sh SEE ALSO
+.Xr chflags 1 ,
+.Xr chgrp 1 ,
+.Xr chmod 1 ,
+.Xr cp 1 ,
+.Xr mv 1 ,
+.Xr strip 1 ,
+.Xr chown 8
+.Sh HISTORY
+The
+.Nm
+utility appeared in
+.Bx 4.2 .
diff --git a/install/pathnames.h b/install/pathnames.h
new file mode 100644
index 0000000..7af9165
--- /dev/null
+++ b/install/pathnames.h
@@ -0,0 +1,38 @@
+/*	$NetBSD: pathnames.h,v 1.4 1997/12/30 22:31:17 thorpej Exp $	*/
+
+/*
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)pathnames.h	8.1 (Berkeley) 6/6/93
+ */
+
+#define	_PATH_STRIP	"/usr/bin/strip"
diff --git a/install/xinstall.c b/install/xinstall.c
new file mode 100644
index 0000000..fa51bab
--- /dev/null
+++ b/install/xinstall.c
@@ -0,0 +1,563 @@
+/*	$NetBSD: xinstall.c,v 1.27 1998/10/01 18:23:52 erh Exp $	*/
+
+/*
+ * Copyright (c) 1987, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1987, 1993\n\
+	The Regents of the University of California.  All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)xinstall.c	8.1 (Berkeley) 7/21/93";
+#else
+__RCSID("$NetBSD: xinstall.c,v 1.27 1998/10/01 18:23:52 erh Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <err.h>
+
+#include "pathnames.h"
+
+#define STRIP_ARGS_MAX 32
+
+struct passwd *pp;
+struct group *gp;
+int docopy=0, dodir=0, dostrip=0, dolink=0, dopreserve=0;
+int mode = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
+char pathbuf[MAXPATHLEN];
+uid_t uid;
+gid_t gid;
+char *stripArgs=NULL;
+
+#define LN_ABSOLUTE	0x01
+#define LN_RELATIVE	0x02
+#define LN_HARD		0x04
+#define LN_SYMBOLIC	0x08
+#define LN_MIXED	0x10
+
+#define	DIRECTORY	0x01		/* Tell install it's a directory. */
+#define	SETFLAGS	0x02		/* Tell install to set flags. */
+
+void	copy __P((int, char *, int, char *, off_t));
+void	makelink __P((char *, char *));
+void	install __P((char *, char *, u_long, u_int));
+void	install_dir __P((char *));
+u_long	string_to_flags __P((char **, u_long *, u_long *));
+void	strip __P((char *));
+void	usage __P((void));
+int	main __P((int, char *[]));
+
+int
+main(argc, argv)
+	int argc;
+	char *argv[];
+{
+	struct stat from_sb, to_sb;
+	mode_t *set;
+	u_long fset;
+	u_int iflags;
+	int ch, no_target;
+	char *p;
+	char *flags = NULL, *to_name, *group = NULL, *owner = NULL;
+
+	iflags = 0;
+	while ((ch = getopt(argc, argv, "cdf:g:l:m:o:psS:")) != -1)
+		switch((char)ch) {
+		case 'c':
+			docopy = 1;
+			break;
+		case 'd':
+			dodir = 1;
+			break;
+		case 'f':
+			flags = optarg;
+			if (string_to_flags(&flags, &fset, NULL))
+				errx(1, "%s: invalid flag", flags);
+			iflags |= SETFLAGS;
+			break;
+		case 'g':
+			group = optarg;
+			break;
+		case 'l':
+			for (p = optarg; *p; p++)
+				switch (*p) {
+				case 's':
+					dolink &= ~(LN_HARD|LN_MIXED);
+					dolink |= LN_SYMBOLIC;
+					break;
+				case 'h':
+					dolink &= ~(LN_SYMBOLIC|LN_MIXED);
+					dolink |= LN_HARD;
+					break;
+				case 'm':
+					dolink &= ~(LN_SYMBOLIC|LN_HARD);
+					dolink |= LN_MIXED;
+					break;
+				case 'a':
+					dolink &= ~LN_RELATIVE;
+					dolink |= LN_ABSOLUTE;
+					break;
+				case 'r':
+					dolink &= ~LN_ABSOLUTE;
+					dolink |= LN_RELATIVE;
+					break;
+				default:
+					errx(1, "%c: invalid link type", *p);
+					break;
+				}
+			break;
+		case 'm':
+			if (!(set = setmode(optarg)))
+				errx(1, "%s: invalid file mode", optarg);
+			mode = getmode(set, 0);
+			break;
+		case 'o':
+			owner = optarg;
+			break;
+		case 'p':
+			dopreserve = 1;
+			break;
+		case 'S':
+			stripArgs = (char*)malloc(sizeof(char)*(strlen(optarg)+1));
+			strcpy(stripArgs,optarg);
+			/* fall through; -S implies -s */
+		case 's':
+			dostrip = 1;
+			break;
+		case '?':
+		default:
+			usage();
+		}
+	argc -= optind;
+	argv += optind;
+
+	/* strip and link options make no sense when creating directories */
+	if ((dostrip || dolink) && dodir)
+		usage();
+
+	/* strip and flags make no sense with links */
+	if ((dostrip || flags) && dolink)
+		usage();
+
+	/* must have at least two arguments, except when creating directories */
+	if (argc < 2 && !dodir)
+		usage();
+
+	/* get group and owner id's */
+	if (group && !(gp = getgrnam(group)) && !isdigit(*group))
+		errx(1, "unknown group %s", group);
+	gid = (group) ? ((gp) ? gp->gr_gid : atoi(group)) : -1;
+	if (owner && !(pp = getpwnam(owner)) && !isdigit(*owner))
+		errx(1, "unknown user %s", owner);
+	uid = (owner) ? ((pp) ? pp->pw_uid : atoi(owner)) : -1;
+
+	if (dodir) {
+		for (; *argv != NULL; ++argv)
+			install_dir(*argv);
+		exit (0);
+	}
+
+	no_target = stat(to_name = argv[argc - 1], &to_sb);
+	if (!no_target && S_ISDIR(to_sb.st_mode)) {
+		for (; *argv != to_name; ++argv)
+			install(*argv, to_name, fset, iflags | DIRECTORY);
+		exit(0);
+	}
+
+	/* can't do file1 file2 directory/file */
+	if (argc != 2)
+		usage();
+
+	if (!no_target) {
+		if (stat(*argv, &from_sb))
+			err(1, "%s", *argv);
+		if (!S_ISREG(to_sb.st_mode))
+			errx(1, "%s: %s", to_name, strerror(EFTYPE));
+		if (!dolink && to_sb.st_dev == from_sb.st_dev &&
+		    to_sb.st_ino == from_sb.st_ino)
+			errx(1, "%s and %s are the same file", *argv, to_name);
+		/*
+		 * Unlink now... avoid ETXTBSY errors later.  Try and turn
+		 * off the append/immutable bits -- if we fail, go ahead,
+		 * it might work.
+		 */
+#define	NOCHANGEBITS	(UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND)
+		if (to_sb.st_flags & NOCHANGEBITS)
+			(void)chflags(to_name,
+			    to_sb.st_flags & ~(NOCHANGEBITS));
+		(void)unlink(to_name);
+	}
+	install(*argv, to_name, fset, iflags);
+	exit(0);
+}
+
+/*
+ * makelink --
+ *	make a link from source to destination
+ */
+void
+makelink(from_name, to_name)
+	char *from_name;
+	char *to_name;
+{
+	char src[MAXPATHLEN], dst[MAXPATHLEN], lnk[MAXPATHLEN];
+
+	/* Try hard links first */
+	if (dolink & (LN_HARD|LN_MIXED)) {
+		if (link(from_name, to_name) == -1) {
+			if ((dolink & LN_HARD) || errno != EXDEV)
+				err(1, "link %s -> %s", from_name, to_name);
+		}
+		else
+			return;
+	}
+
+	/* Symbolic links */
+	if (dolink & LN_ABSOLUTE) {
+		/* Convert source path to absolute */
+		if (realpath(from_name, src) == NULL)
+			err(1, "%s", src);
+		if (symlink(src, to_name) == -1)
+			err(1, "symlink %s -> %s", src, to_name);
+		return;
+	}
+
+	if (dolink & LN_RELATIVE) {
+		char *s, *d;
+
+		/* Resolve pathnames */
+		if (realpath(from_name, src) == NULL)
+			err(1, "%s", src);
+		if (realpath(to_name, dst) == NULL)
+			err(1, "%s", dst);
+
+		/* trim common path components */
+		for (s = src, d = dst; *s == *d; s++, d++)
+			continue;
+		while (*s != '/')
+			s--, d--;
+
+		/* count the number of directories we need to backtrack */
+		for (++d, lnk[0] = '\0'; *d; d++)
+			if (*d == '/')
+				(void) strcat(lnk, "../");
+
+		(void) strcat(lnk, ++s);
+
+		if (symlink(lnk, dst) == -1)
+			err(1, "symlink %s -> %s", lnk, dst);
+		return;
+	}
+
+	/*
+	 * If absolute or relative was not specified, 
+	 * try the names the user provided
+	 */
+	if (symlink(from_name, to_name) == -1)
+		err(1, "symlink %s -> %s", from_name, to_name);
+
+}
+
+/*
+ * install --
+ *	build a path name and install the file
+ */
+void
+install(from_name, to_name, fset, flags)
+	char *from_name, *to_name;
+	u_long fset;
+	u_int flags;
+{
+	struct stat from_sb, to_sb;
+	int devnull, from_fd, to_fd, serrno;
+	char *p;
+
+	/* If try to install NULL file to a directory, fails. */
+	if (flags & DIRECTORY || strcmp(from_name, _PATH_DEVNULL)) {
+		if (stat(from_name, &from_sb))
+			err(1, "%s", from_name);
+		if (!S_ISREG(from_sb.st_mode))
+			errx(1, "%s: %s", from_name, strerror(EFTYPE));
+		/* Build the target path. */
+		if (flags & DIRECTORY) {
+			(void)snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
+			    to_name,
+			    (p = strrchr(from_name, '/')) ? ++p : from_name);
+			to_name = pathbuf;
+		}
+		devnull = 0;
+	} else {
+		from_sb.st_flags = 0;	/* XXX */
+		devnull = 1;
+	}
+
+	/*
+	 * Unlink now... avoid ETXTBSY errors later.  Try and turn
+	 * off the append/immutable bits -- if we fail, go ahead,
+	 * it might work.
+	 */
+	if (stat(to_name, &to_sb) == 0 &&
+	    to_sb.st_flags & (NOCHANGEBITS))
+		(void)chflags(to_name, to_sb.st_flags & ~(NOCHANGEBITS));
+	(void)unlink(to_name);
+
+	if (dolink) {
+		makelink(from_name, to_name);
+		return;
+	}
+
+	/* Create target. */
+	if ((to_fd = open(to_name,
+	    O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR)) < 0)
+		err(1, "%s", to_name);
+	if (!devnull) {
+		if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) {
+			(void)unlink(to_name);
+			err(1, "%s", from_name);
+		}
+		copy(from_fd, from_name, to_fd, to_name, from_sb.st_size);
+		(void)close(from_fd);
+	}
+
+	if (dostrip) {
+		strip(to_name);
+
+		/*
+		 * Re-open our fd on the target, in case we used a strip
+		 *  that does not work in-place -- like gnu binutils strip.
+		 */
+		close(to_fd);
+		if ((to_fd = open(to_name, O_RDONLY, S_IRUSR | S_IWUSR)) < 0)
+		  err(1, "stripping %s", to_name);
+	}
+
+	/*
+	 * Set owner, group, mode for target; do the chown first,
+	 * chown may lose the setuid bits.
+	 */
+	if ((gid != -1 || uid != -1) && fchown(to_fd, uid, gid)) {
+		serrno = errno;
+		(void)unlink(to_name);
+		errx(1, "%s: chown/chgrp: %s", to_name, strerror(serrno));
+	}
+	if (fchmod(to_fd, mode)) {
+		serrno = errno;
+		(void)unlink(to_name);
+		errx(1, "%s: chmod: %s", to_name, strerror(serrno));
+	}
+
+	/*
+	 * If provided a set of flags, set them, otherwise, preserve the
+	 * flags, except for the dump flag.
+	 */
+	if (fchflags(to_fd,
+	    flags & SETFLAGS ? fset : from_sb.st_flags & ~UF_NODUMP)) {
+		if (errno != EOPNOTSUPP || (from_sb.st_flags & ~UF_NODUMP) != 0)
+			warn("%s: chflags", to_name);
+	}
+
+	/*
+	 * Preserve the date of the source file.
+	 */
+	if (dopreserve) {
+		struct timeval tv[2];
+
+		TIMESPEC_TO_TIMEVAL(&tv[0], &from_sb.st_atimespec);
+		TIMESPEC_TO_TIMEVAL(&tv[1], &from_sb.st_mtimespec);
+#ifndef __APPLE__
+		if (futimes(to_fd, tv) == -1)
+			warn("%s: futimes", to_name);
+#else
+		if (utimes(to_name, tv) == -1)
+			warn("%s: utimes", to_name);
+#endif
+	}
+
+	(void)close(to_fd);
+	if (!docopy && !devnull && unlink(from_name))
+		err(1, "%s", from_name);
+}
+
+/*
+ * copy --
+ *	copy from one file to another
+ */
+void
+copy(from_fd, from_name, to_fd, to_name, size)
+	int from_fd, to_fd;
+	char *from_name, *to_name;
+	off_t size;
+{
+	int nr, nw;
+	int serrno;
+	char *p;
+	char buf[MAXBSIZE];
+
+	/*
+	 * There's no reason to do anything other than close the file
+	 * now if it's empty, so let's not bother.
+	 */
+	if (size > 0) {
+		/*
+		 * Mmap and write if less than 8M (the limit is so we don't totally
+		 * trash memory on big files).  This is really a minor hack, but it
+		 * wins some CPU back.
+		 */
+		if (size <= 8 * 1048576) {
+			if ((p = mmap(NULL, (size_t)size, PROT_READ,
+			    MAP_FILE|MAP_SHARED, from_fd, (off_t)0)) == (char *)-1)
+				err(1, "%s", from_name);
+			if (write(to_fd, p, size) != size)
+				err(1, "%s", to_name);
+		} else {
+			while ((nr = read(from_fd, buf, sizeof(buf))) > 0)
+				if ((nw = write(to_fd, buf, nr)) != nr) {
+					serrno = errno;
+					(void)unlink(to_name);
+					errx(1, "%s: %s",
+					    to_name, strerror(nw > 0 ? EIO : serrno));
+				}
+			if (nr != 0) {
+				serrno = errno;
+				(void)unlink(to_name);
+				errx(1, "%s: %s", from_name, strerror(serrno));
+			}
+		}
+	}
+}
+
+/*
+ * strip --
+ *	use strip(1) to strip the target file
+ */
+void
+strip(to_name)
+	char *to_name;
+{
+	int serrno, status;
+	char *stripprog;
+
+	switch (vfork()) {
+	case -1:
+		serrno = errno;
+		(void)unlink(to_name);
+		errx(1, "vfork: %s", strerror(serrno));
+	case 0:
+		stripprog = getenv("STRIP");
+		if (stripprog == NULL)
+			stripprog = _PATH_STRIP;
+
+		if (stripArgs) {
+			/* build up a command line and let /bin/sh parse the arguments */
+			char* cmd = (char*)malloc(sizeof(char)*
+						  (3+strlen(stripprog)+
+						     strlen(stripArgs)+
+						     strlen(to_name)));
+
+			sprintf(cmd, "%s %s %s", stripprog, stripArgs, to_name);
+
+			execl(_PATH_BSHELL, "sh", "-c", cmd, NULL);
+		} else
+			execl(stripprog, "strip", to_name, NULL);
+
+		warn("%s", stripprog);
+		_exit(1);
+	default:
+		if (wait(&status) == -1 || status)
+			(void)unlink(to_name);
+	}
+}
+
+/*
+ * install_dir --
+ *	build directory heirarchy
+ */
+void
+install_dir(path)
+        char *path;
+{
+        char *p;
+        struct stat sb;
+        int ch;
+
+        for (p = path;; ++p)
+                if (!*p || (p != path && *p  == '/')) {
+                        ch = *p;
+                        *p = '\0';
+                        if (stat(path, &sb)) {
+                                if (errno != ENOENT || mkdir(path, 0777) < 0) {
+					err(1, "%s", path);
+					/* NOTREACHED */
+                                }
+                        }
+                        if (!(*p = ch))
+				break;
+                }
+
+	if (((gid != -1 || uid != -1) && chown(path, uid, gid)) ||
+            chmod(path, mode)) {
+                warn("%s", path);
+        }
+}
+
+/*
+ * usage --
+ *	print a usage message and die
+ */
+void
+usage()
+{
+	(void)fprintf(stderr, "\
+usage: install [-cps] [-f flags] [-m mode] [-o owner] [-g group] [-l linkflags] [-S stripflags] file1 file2\n\
+       install [-cps] [-f flags] [-m mode] [-o owner] [-g group] [-l linkflags] [-S stripflags] file1 ... fileN directory\n\
+       install -pd [-m mode] [-o owner] [-g group] directory ...\n");
+	exit(1);
+}
diff --git a/ln/Makefile b/ln/Makefile
new file mode 100644
index 0000000..15d04bd
--- /dev/null
+++ b/ln/Makefile
@@ -0,0 +1,49 @@
+#
+# Generated by the NeXT Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = ln
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+CFILES = ln.c
+
+OTHERSRCS = Makefile Makefile.preamble Makefile.postamble ln.1\
+            symlink.7
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /bin
+LIBS = 
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+
+
+NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/$(NAME)/Build
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
diff --git a/ln/Makefile.postamble b/ln/Makefile.postamble
new file mode 100644
index 0000000..013b558
--- /dev/null
+++ b/ln/Makefile.postamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
diff --git a/ln/Makefile.preamble b/ln/Makefile.preamble
new file mode 100644
index 0000000..9e10e90
--- /dev/null
+++ b/ln/Makefile.preamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
diff --git a/ln/PB.project b/ln/PB.project
new file mode 100644
index 0000000..fe1d0a7
--- /dev/null
+++ b/ln/PB.project
@@ -0,0 +1,25 @@
+{
+    DYNAMIC_CODE_GEN = YES; 
+    FILESTABLE = {
+        FRAMEWORKS = (); 
+        OTHER_LINKED = (ln.c); 
+        OTHER_SOURCES = (Makefile, Makefile.preamble, Makefile.postamble, ln.1, symlink.7); 
+    }; 
+    LANGUAGE = English; 
+    LOCALIZABLE_FILES = {}; 
+    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
+    NEXTSTEP_BUILDDIR = "/tmp/$(NAME)/Build"; 
+    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
+    NEXTSTEP_INSTALLDIR = /bin; 
+    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
+    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
+    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
+    PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; 
+    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
+    PROJECTNAME = ln; 
+    PROJECTTYPE = Tool; 
+    PROJECTVERSION = 2.8; 
+    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
+    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
+    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
+}
diff --git a/ln/ln.1 b/ln/ln.1
new file mode 100644
index 0000000..0d1a2b9
--- /dev/null
+++ b/ln/ln.1
@@ -0,0 +1,147 @@
+.\"	$NetBSD: ln.1,v 1.13 1997/10/20 08:52:19 enami Exp $
+.\"
+.\" Copyright (c) 1980, 1990, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)ln.1	8.2 (Berkeley) 12/30/93
+.\"
+.Dd December 30, 1993
+.Dt LN 1
+.Os BSD 4
+.Sh NAME
+.Nm ln
+.Nd make links
+.Sh SYNOPSIS
+.Nm
+.Op Fl fhns
+.Ar source_file
+.Op target_file
+.Nm ""
+.Op Fl fhns
+.Ar source_file ...
+.Op target_dir
+.Sh DESCRIPTION
+The
+.Nm
+utility creates a new directory entry (linked file) which has the
+same modes as the original file.
+It is useful for maintaining multiple copies of a file in many places
+at once without using up storage for the
+.Dq copies ;
+instead, a link
+.Dq points
+to the original copy.
+There are two types of links; hard links and symbolic links.
+How a link
+.Dq points
+to a file is one of the differences between a hard or symbolic link.
+.Pp
+The options are as follows:
+.Bl -tag -width flag
+.It Fl f
+Unlink any already existing file, permitting the link to occur.
+.It Fl h
+If the
+.Ar target_file
+or
+.Ar target_dir
+is a symbolic link, do not follow it.  This is most useful with the
+.Fl f
+option, to replace a symlink which may point to a directory.
+.It Fl n
+Same as
+.Fl h ,
+for compatibility with other
+.Nm
+implementations.
+.It Fl s
+Create a symbolic link.
+.El
+.Pp
+By default
+.Nm
+makes
+.Em hard
+links.
+A hard link to a file is indistinguishable from the original directory entry;
+any changes to a file are effective independent of the name used to reference
+the file.
+Hard links may not normally refer to directories and may not span file systems.
+.Pp
+A symbolic link contains the name of the file to
+which it is linked.  The referenced file is used when an
+.Xr open  2
+operation is performed on the link.
+A
+.Xr stat  2
+on a symbolic link will return the linked-to file; an
+.Xr lstat  2
+must be done to obtain information about the link.
+The
+.Xr readlink  2
+call may be used to read the contents of a symbolic link.
+Symbolic links may span file systems and may refer to directories.
+.Pp
+Given one or two arguments,
+.Nm
+creates a link to an existing file
+.Ar source_file  .
+If
+.Ar target_file
+is given, the link has that name;
+.Ar target_file
+may also be a directory in which to place the link;
+otherwise it is placed in the current directory.
+If only the directory is specified, the link will be made
+to the last component of
+.Ar source_file  .
+.Pp
+Given more than two arguments,
+.Nm
+makes links in
+.Ar target_dir
+to all the named source files.
+The links made will have the same name as the files being linked to.
+.Sh SEE ALSO
+.Xr link 2 ,
+.Xr lstat 2 ,
+.Xr readlink 2 ,
+.Xr stat 2 ,
+.Xr symlink 2 ,
+.Xr symlink 7
+.Sh HISTORY
+A
+.Nm
+utility appeared in
+.At v6 .
diff --git a/ln/ln.c b/ln/ln.c
new file mode 100644
index 0000000..f8bbce3
--- /dev/null
+++ b/ln/ln.c
@@ -0,0 +1,182 @@
+/*	$NetBSD: ln.c,v 1.15 1998/07/28 05:31:25 mycroft Exp $	*/
+
+/*
+ * Copyright (c) 1987, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1987, 1993, 1994\n\
+	The Regents of the University of California.  All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)ln.c	8.2 (Berkeley) 3/31/94";
+#else
+__RCSID("$NetBSD: ln.c,v 1.15 1998/07/28 05:31:25 mycroft Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int	fflag;				/* Unlink existing files. */
+int	hflag;				/* Check new name for symlink first. */
+int	sflag;				/* Symbolic, not hard, link. */
+					/* System link call. */
+int (*linkf) __P((const char *, const char *));
+
+int	linkit __P((char *, char *, int));
+void	usage __P((void));
+int	main __P((int, char *[]));
+
+int
+main(argc, argv)
+	int argc;
+	char *argv[];
+{
+	struct stat sb;
+	int ch, exitval;
+	char *sourcedir;
+
+	while ((ch = getopt(argc, argv, "fhns")) != -1)
+		switch (ch) {
+		case 'f':
+			fflag = 1;
+			break;
+		case 'h':
+		case 'n':
+			hflag = 1;
+			break;
+		case 's':
+			sflag = 1;
+			break;
+		case '?':
+		default:
+			usage();
+		}
+
+	argv += optind;
+	argc -= optind;
+
+	linkf = sflag ? symlink : link;
+
+	switch(argc) {
+	case 0:
+		usage();
+		/* NOTREACHED */
+	case 1:				/* ln target */
+		exit(linkit(argv[0], ".", 1));
+		/* NOTREACHED */
+	case 2:				/* ln target source */
+		exit(linkit(argv[0], argv[1], 0));
+		/* NOTREACHED */
+	}
+					/* ln target1 target2 directory */
+	sourcedir = argv[argc - 1];
+	if (hflag && lstat(sourcedir, &sb) == 0 && S_ISLNK(sb.st_mode)) {
+		/* we were asked not to follow symlinks, but found one at
+		   the target--simulate "not a directory" error */
+		errno = ENOTDIR;
+		err(1, "%s", sourcedir);
+	}
+	if (stat(sourcedir, &sb))
+		err(1, "%s", sourcedir);
+	if (!S_ISDIR(sb.st_mode))
+		usage();
+	for (exitval = 0; *argv != sourcedir; ++argv)
+		exitval |= linkit(*argv, sourcedir, 1);
+	exit(exitval);
+	/* NOTREACHED */
+}
+
+int
+linkit(target, source, isdir)
+	char *target, *source;
+	int isdir;
+{
+	struct stat sb;
+	char *p, path[MAXPATHLEN];
+
+	if (!sflag) {
+		/* If target doesn't exist, quit now. */
+		if (stat(target, &sb)) {
+			warn("%s", target);
+			return (1);
+		}
+	}
+
+	/* If the source is a directory (and not a symlink if hflag),
+	   append the target's name. */
+	if (isdir ||
+	    (!lstat(source, &sb) && S_ISDIR(sb.st_mode)) ||
+	    (!hflag && !stat(source, &sb) && S_ISDIR(sb.st_mode))) {
+		if ((p = strrchr(target, '/')) == NULL)
+			p = target;
+		else
+			++p;
+		(void)snprintf(path, sizeof(path), "%s/%s", source, p);
+		source = path;
+	}
+
+	/*
+	 * If the file exists, and -f was specified, unlink it.
+	 * Attempt the link.
+	 */
+	if ((fflag && unlink(source) < 0 && errno != ENOENT) ||
+	    (*linkf)(target, source)) {
+		warn("%s", source);
+		return (1);
+	}
+
+	return (0);
+}
+
+void
+usage()
+{
+
+	extern char *__progname;
+	(void)fprintf(stderr,
+	    "Usage:\t%s [-fhns] file1 file2\n\t%s [-fhns] file ... directory\n",
+	    __progname, __progname);
+	exit(1);
+	/* NOTREACHED */
+}
diff --git a/ln/symlink.7 b/ln/symlink.7
new file mode 100644
index 0000000..7e6e68a
--- /dev/null
+++ b/ln/symlink.7
@@ -0,0 +1,427 @@
+.\"	$NetBSD: symlink.7,v 1.7 1998/02/06 05:39:47 perry Exp $
+.\"
+.\" Copyright (c) 1992, 1993, 1994
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)symlink.7	8.3 (Berkeley) 3/31/94
+.\"
+.Dd March 31, 1994
+.Dt SYMLINK 7
+.Os BSD 4
+.Sh NAME
+.Nm symlink
+.Nd symbolic link handling
+.Sh SYMBOLIC LINK HANDLING
+Symbolic links are files that act as pointers to other files.
+To understand their behavior, you must first understand how hard links
+work.
+A hard link to a file is indistinguishable from the original file because
+it is a reference to the object underlying the original file name.
+Changes to a file are independent of the name used to reference the
+file.
+Hard links may not refer to directories and may not reference files
+on different file systems.
+A symbolic link contains the name of the file to which it is linked,
+i.e. it is a pointer to another name, and not to an underlying object.
+For this reason, symbolic links may reference directories and may span
+file systems.
+.Pp
+Because a symbolic link and its referenced object coexist in the filesystem
+name space, confusion can arise in distinguishing between the link itself
+and the referenced object.
+Historically, commands and system calls have adopted their own link
+following conventions in a somewhat ad-hoc fashion.
+Rules for more a uniform approach, as they are implemented in this system,
+are outlined here.
+It is important that local applications conform to these rules, too,
+so that the user interface can be as consistent as possible.
+.Pp
+Symbolic links are handled either by operating on the link itself,
+or by operating on the object referenced by the link.
+In the latter case,
+an application or system call is said to
+.Dq follow
+the link.
+Symbolic links may reference other symbolic links,
+in which case the links are dereferenced until an object that is
+not a symbolic link is found,
+a symbolic link which references a file which doesn't exist is found,
+or a loop is detected.
+(Loop detection is done by placing an upper limit on the number of
+links that may be followed, and an error results if this limit is
+exceeded.)
+.Pp
+There are three separate areas that need to be discussed.
+They are as follows:
+.sp
+.Bl -enum -compact -offset indent
+.It
+Symbolic links used as file name arguments for system calls.
+.It
+Symbolic links specified as command line arguments to utilities that
+are not traversing a file tree.
+.It
+Symbolic links encountered by utilities that are traversing a file tree
+(either specified on the command line or encountered as part of the
+file hierarchy walk).
+.El
+.Ss System calls.
+The first area is symbolic links used as file name arguments for
+system calls.
+.Pp
+Except as noted below, all system calls follow symbolic links.
+For example, if there were a symbolic link
+.Dq Li slink
+which pointed to a file named
+.Dq Li afile ,
+the system call
+.Dq Li open("slink" ...)
+would return a file descriptor to the file
+.Dq afile .
+.Pp
+There are four system calls that do not follow links, and which operate
+on the symbolic link itself.
+They are:
+.Xr lstat 2 ,
+.Xr readlink 2 ,
+.Xr rename 2 ,
+and
+.Xr unlink 2 .
+Because
+.Xr remove 3
+is an alias for
+.Xr unlink 2 ,
+it also does not follow symbolic links.
+.Pp
+The
+.Bx 4.4
+system differs from historical 
+.Bx 4
+systems in that the system call
+.Xr chown 2
+has been changed to follow symbolic links.
+.Ss Commands not traversing a file tree.
+The second area is symbolic links, specified as command line file
+name arguments, to commands which are not traversing a file tree.
+.Pp
+Except as noted below, commands follow symbolic links named as command
+line arguments.
+For example, if there were a symbolic link 
+.Dq Li slink
+which pointed to a file named
+.Dq Li afile ,
+the command
+.Dq Li cat slink
+would display the contents of the file
+.Dq Li afile .
+.Pp
+It is important to realize that this rule includes commands which may
+optionally traverse file trees, e.g. the command
+.Dq Li "chown file"
+is included in this rule, while the command
+.Dq Li "chown -R file"
+is not.
+(The latter is described in the third area, below.)
+.Pp
+If it is explicitly intended that the command operate on the symbolic
+link instead of following the symbolic link, e.g., it is desired that
+.Dq Li "file slink"
+display the type of file that
+.Dq Li slink
+is, whether it is a symbolic link or not, the
+.Fl h
+option should be used.
+In the above example,
+.Dq Li "file slink"
+would report the type of the file referenced by
+.Dq Li slink ,
+while
+.Dq Li "file -h slink"
+would report that
+.Dq Li slink
+was a symbolic link.
+.Pp
+There are three exceptions to this rule.
+The
+.Xr mv 1
+and
+.Xr rm 1
+commands do not follow symbolic links named as arguments,
+but respectively attempt to rename and delete them.
+(Note, if the symbolic link references a file via a relative path,
+moving it to another directory may very well cause it to stop working,
+since the path may no longer be correct.)
+.Pp
+The
+.Xr ls 1
+command is also an exception to this rule.
+For compatibility with historic systems (when
+.Nm ls
+is not doing a tree walk, i.e. the
+.Fl R
+option is not specified),
+the
+.Nm ls
+command follows symbolic links named as arguments if the
+.Fl L
+option is specified,
+or if the
+.Fl F ,
+.Fl d
+or
+.Fl l
+options are not specified.
+(If the
+.Fl L
+option is specified,
+.Nm ls
+always follows symbolic links.
+.Nm ls
+is the only command where the
+.Fl L
+option affects its behavior even though it is not doing a walk of
+a file tree.)
+.Pp
+The
+.Bx 4.4
+system differs from historical
+.Bx 4
+systems in that the
+.Nm chown ,
+.Nm chgrp
+and
+.Nm file
+commands follow symbolic links specified on the command line.
+.Ss Commands traversing a file tree.
+The following commands either optionally or always traverse file trees:
+.Xr chflags 1 ,
+.Xr chgrp 1 ,
+.Xr chmod 1 ,
+.Xr cp 1 ,
+.Xr du 1 ,
+.Xr find 1 ,
+.Xr ls 1 ,
+.Xr pax 1 ,
+.Xr rm 1 ,
+.Xr tar 1
+and
+.Xr chown 8 .
+.Pp
+It is important to realize that the following rules apply equally to
+symbolic links encountered during the file tree traversal and symbolic
+links listed as command line arguments.
+.Pp
+The first rule applies to symbolic links that reference files that are
+not of type directory.
+Operations that apply to symbolic links are performed on the links
+themselves, but otherwise the links are ignored.
+.Pp
+For example, the command
+.Dq Li "chown -R user slink directory"
+will ignore
+.Dq Li slink ,
+because symbolic links in this system do not have owners.
+Any symbolic links encountered during the tree traversal will also be
+ignored.
+The command
+.Dq Li "rm -r slink directory"
+will remove
+.Dq Li slink ,
+as well as any symbolic links encountered in the tree traversal of
+.Dq Li directory ,
+because symbolic links may be removed.
+In no case will either
+.Nm chown
+or
+.Nm rm
+affect the file which
+.Dq Li slink
+references in any way.
+.Pp
+The second rule applies to symbolic links that reference files of type
+directory.
+Symbolic links which reference files of type directory are never
+.Dq followed
+by default.
+This is often referred to as a
+.Dq physical
+walk, as opposed to a
+.Dq logical
+walk (where symbolic links referencing directories are followed).
+.Pp
+As consistently as possible, you can make commands doing a file tree
+walk follow any symbolic links named on the command line, regardless
+of the type of file they reference, by specifying the
+.Fl H 
+(for
+.Dq half\-logical )
+flag.
+This flag is intended to make the command line name space look
+like the logical name space.
+(Note, for commands that do not always do file tree traversals, the
+.Fl H
+flag will be ignored if the
+.Fl R
+flag is not also specified.)
+.Pp
+For example, the command
+.Dq Li "chown -HR user slink"
+will traverse the file hierarchy rooted in the file pointed to by
+.Dq Li slink .
+Note, the
+.Fl H
+is not the same as the previously discussed
+.Fl h
+flag.
+The
+.Fl H
+flag causes symbolic links specified on the command line to be
+dereferenced both for the purposes of the action to be performed
+and the tree walk, and it is as if the user had specified the
+name of the file to which the symbolic link pointed.
+.Pp
+As consistently as possible, you can make commands doing a file tree
+walk follow any symbolic links named on the command line, as well as
+any symbolic links encountered during the traversal, regardless of
+the type of file they reference, by specifying the
+.Fl L
+(for
+.Dq logical )
+flag.
+This flag is intended to make the entire name space look like
+the logical name space.
+(Note, for commands that do not always do file tree traversals, the
+.Fl L
+flag will be ignored if the
+.Fl R
+flag is not also specified.)
+.Pp
+For example, the command
+.Dq Li "chown -LR user slink"
+will change the owner of the file referenced by
+.Dq Li slink .
+If
+.Dq Li slink
+references a directory,
+.Nm chown
+will traverse the file hierarchy rooted in the directory that it
+references.
+In addition, if any symbolic links are encountered in any file tree that
+.Nm chown
+traverses, they will be treated in the same fashion as
+.Dq Li slink .
+.Pp
+As consistently as possible, you can specify the default behavior by
+specifying the
+.Fl P
+(for
+.Dq physical )
+flag.
+This flag is intended to make the entire name space look like the
+physical name space.
+.Pp
+For commands that do not by default do file tree traversals, the
+.Fl H ,
+.Fl L
+and
+.Fl P
+flags are ignored if the
+.Fl R
+flag is not also specified.
+In addition, you may specify the
+.Fl H ,
+.Fl L
+and
+.Fl P
+options more than once; the last one specified determines the
+command's behavior.
+This is intended to permit you to alias commands to behave one way
+or the other, and then override that behavior on the command line.
+.Pp
+The
+.Xr ls 1
+and
+.Xr rm 1
+commands have exceptions to these rules.
+The
+.Nm rm
+command operates on the symbolic link, and not the file it references,
+and therefore never follows a symbolic link.
+The
+.Nm rm
+command does not support the
+.Fl H ,
+.Fl L
+or
+.Fl P
+options.
+.Pp
+To maintain compatibility with historic systems,
+the
+.Nm ls
+command never follows symbolic links unless the
+.Fl L
+flag is specified.
+If the
+.Fl L
+flag is specified,
+.Nm ls
+follows all symbolic links,
+regardless of their type,
+whether specified on the command line or encountered in the tree walk.
+The
+.Nm ls
+command does not support the
+.Fl H
+or
+.Fl P
+options.
+.Sh SEE ALSO
+.Xr chflags 1 ,
+.Xr chgrp 1 ,
+.Xr chmod 1 ,
+.Xr cp 1 ,
+.Xr du 1 ,
+.Xr find 1 ,
+.Xr ln 1 ,
+.Xr ls 1 ,
+.Xr mv 1 ,
+.Xr pax 1 ,
+.Xr rm 1 ,
+.Xr tar 1 ,
+.Xr lstat 2 ,
+.Xr readlink 2 ,
+.Xr rename 2 ,
+.Xr symlink 2 ,
+.Xr unlink 2 ,
+.Xr fts 3 ,
+.Xr remove 3 ,
+.Xr chown 8
diff --git a/ls/Makefile b/ls/Makefile
new file mode 100644
index 0000000..f29efd4
--- /dev/null
+++ b/ls/Makefile
@@ -0,0 +1,50 @@
+#
+# Generated by the NeXT Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = ls
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+HFILES = extern.h ls.h
+
+CFILES = cmp.c ls.c print.c stat_flags.c util.c
+
+OTHERSRCS = Makefile Makefile.preamble Makefile.postamble ls.1
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /bin
+LIBS = 
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+
+
+NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/$(NAME)/Build
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
diff --git a/ls/Makefile.postamble b/ls/Makefile.postamble
new file mode 100644
index 0000000..013b558
--- /dev/null
+++ b/ls/Makefile.postamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
diff --git a/ls/Makefile.preamble b/ls/Makefile.preamble
new file mode 100644
index 0000000..9e10e90
--- /dev/null
+++ b/ls/Makefile.preamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
diff --git a/ls/PB.project b/ls/PB.project
new file mode 100644
index 0000000..32e2a56
--- /dev/null
+++ b/ls/PB.project
@@ -0,0 +1,26 @@
+{
+    DYNAMIC_CODE_GEN = YES; 
+    FILESTABLE = {
+        FRAMEWORKS = (); 
+        H_FILES = (extern.h, ls.h); 
+        OTHER_LINKED = (cmp.c, ls.c, print.c, stat_flags.c, util.c); 
+        OTHER_SOURCES = (Makefile, Makefile.preamble, Makefile.postamble, ls.1); 
+    }; 
+    LANGUAGE = English; 
+    LOCALIZABLE_FILES = {}; 
+    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
+    NEXTSTEP_BUILDDIR = "/tmp/$(NAME)/Build"; 
+    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
+    NEXTSTEP_INSTALLDIR = /bin; 
+    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
+    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
+    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
+    PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; 
+    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
+    PROJECTNAME = ls; 
+    PROJECTTYPE = Tool; 
+    PROJECTVERSION = 2.8; 
+    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
+    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
+    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
+}
diff --git a/ls/cmp.c b/ls/cmp.c
new file mode 100644
index 0000000..31b7565
--- /dev/null
+++ b/ls/cmp.c
@@ -0,0 +1,203 @@
+/*	$NetBSD: cmp.c,v 1.14 1998/10/09 02:00:39 enami Exp $	*/
+
+/*
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Michael Fischbein.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)cmp.c	8.1 (Berkeley) 5/31/93";
+#else
+__RCSID("$NetBSD: cmp.c,v 1.14 1998/10/09 02:00:39 enami Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fts.h>
+#include <string.h>
+
+#include "ls.h"
+#include "extern.h"
+
+#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || \
+    defined(_XOPEN_SOURCE) || defined(__NetBSD__)
+#define ATIMENSEC_CMP(x, op, y) ((x)->st_atimensec op (y)->st_atimensec)
+#define CTIMENSEC_CMP(x, op, y) ((x)->st_ctimensec op (y)->st_ctimensec)
+#define MTIMENSEC_CMP(x, op, y) ((x)->st_mtimensec op (y)->st_mtimensec)
+#else
+#define ATIMENSEC_CMP(x, op, y) \
+	((x)->st_atimespec.tv_nsec op (y)->st_atimespec.tv_nsec)
+#define CTIMENSEC_CMP(x, op, y) \
+	((x)->st_ctimespec.tv_nsec op (y)->st_ctimespec.tv_nsec)
+#define MTIMENSEC_CMP(x, op, y) \
+	((x)->st_mtimespec.tv_nsec op (y)->st_mtimespec.tv_nsec)
+#endif
+
+int
+namecmp(a, b)
+	const FTSENT *a, *b;
+{
+	return (strcmp(a->fts_name, b->fts_name));
+}
+
+int
+revnamecmp(a, b)
+	const FTSENT *a, *b;
+{
+	return (strcmp(b->fts_name, a->fts_name));
+}
+
+int
+modcmp(a, b)
+	const FTSENT *a, *b;
+{
+	if (b->fts_statp->st_mtime > a->fts_statp->st_mtime)
+		return (1);
+	else if (b->fts_statp->st_mtime < a->fts_statp->st_mtime)
+		return (-1);
+	else if (MTIMENSEC_CMP(b->fts_statp, >, a->fts_statp))
+		return (1);
+	else if (MTIMENSEC_CMP(b->fts_statp, <, a->fts_statp))
+		return (-1);
+	else
+		return (namecmp(a, b));
+}
+
+int
+revmodcmp(a, b)
+	const FTSENT *a, *b;
+{
+	if (b->fts_statp->st_mtime > a->fts_statp->st_mtime)
+		return (-1);
+	else if (b->fts_statp->st_mtime < a->fts_statp->st_mtime)
+		return (1);
+	else if (MTIMENSEC_CMP(b->fts_statp, >, a->fts_statp))
+		return (-1);
+	else if (MTIMENSEC_CMP(b->fts_statp, <, a->fts_statp))
+		return (1);
+	else
+		return (revnamecmp(a, b));
+}
+
+int
+acccmp(a, b)
+	const FTSENT *a, *b;
+{
+	if (b->fts_statp->st_atime > a->fts_statp->st_atime)
+		return (1);
+	else if (b->fts_statp->st_atime < a->fts_statp->st_atime)
+		return (-1);
+	else if (ATIMENSEC_CMP(b->fts_statp, >, a->fts_statp))
+		return (1);
+	else if (ATIMENSEC_CMP(b->fts_statp, <, a->fts_statp))
+		return (-1);
+	else
+		return (namecmp(a, b));
+}
+
+int
+revacccmp(a, b)
+	const FTSENT *a, *b;
+{
+	if (b->fts_statp->st_atime > a->fts_statp->st_atime)
+		return (-1);
+	else if (b->fts_statp->st_atime < a->fts_statp->st_atime)
+		return (1);
+	else if (ATIMENSEC_CMP(b->fts_statp, >, a->fts_statp))
+		return (-1);
+	else if (ATIMENSEC_CMP(b->fts_statp, <, a->fts_statp))
+		return (1);
+	else
+		return (revnamecmp(a, b));
+}
+
+int
+statcmp(a, b)
+	const FTSENT *a, *b;
+{
+	if (b->fts_statp->st_ctime > a->fts_statp->st_ctime)
+		return (1);
+	else if (b->fts_statp->st_ctime < a->fts_statp->st_ctime)
+		return (-1);
+	else if (CTIMENSEC_CMP(b->fts_statp, >, a->fts_statp))
+		return (1);
+	else if (CTIMENSEC_CMP(b->fts_statp, <, a->fts_statp))
+		return (-1);
+	else
+		return (namecmp(a, b));
+}
+
+int
+revstatcmp(a, b)
+	const FTSENT *a, *b;
+{
+	if (b->fts_statp->st_ctime > a->fts_statp->st_ctime)
+		return (-1);
+	else if (b->fts_statp->st_ctime < a->fts_statp->st_ctime)
+		return (1);
+	else if (CTIMENSEC_CMP(b->fts_statp, >, a->fts_statp))
+		return (-1);
+	else if (CTIMENSEC_CMP(b->fts_statp, <, a->fts_statp))
+		return (1);
+	else
+		return (revnamecmp(a, b));
+}
+
+int
+sizecmp(a, b)
+	const FTSENT *a, *b;
+{
+	if (b->fts_statp->st_size > a->fts_statp->st_size)
+		return (1);
+	if (b->fts_statp->st_size < a->fts_statp->st_size)
+		return (-1);
+	else
+		return (namecmp(a, b));
+}
+
+int
+revsizecmp(a, b)
+	const FTSENT *a, *b;
+{
+	if (b->fts_statp->st_size > a->fts_statp->st_size)
+		return (-1);
+	if (b->fts_statp->st_size < a->fts_statp->st_size)
+		return (1);
+	else
+		return (revnamecmp(a, b));
+}
diff --git a/ls/extern.h b/ls/extern.h
new file mode 100644
index 0000000..a42d48f
--- /dev/null
+++ b/ls/extern.h
@@ -0,0 +1,56 @@
+/*	$NetBSD: extern.h,v 1.7 1998/01/18 13:30:03 lukem Exp $	*/
+
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)extern.h	8.1 (Berkeley) 5/31/93
+ */
+
+int	 acccmp __P((const FTSENT *, const FTSENT *));
+int	 revacccmp __P((const FTSENT *, const FTSENT *));
+int	 modcmp __P((const FTSENT *, const FTSENT *));
+int	 revmodcmp __P((const FTSENT *, const FTSENT *));
+int	 namecmp __P((const FTSENT *, const FTSENT *));
+int	 revnamecmp __P((const FTSENT *, const FTSENT *));
+int	 statcmp __P((const FTSENT *, const FTSENT *));
+int	 revstatcmp __P((const FTSENT *, const FTSENT *));
+int	 sizecmp __P((const FTSENT *, const FTSENT *));
+int	 revsizecmp __P((const FTSENT *, const FTSENT *));
+
+char	*flags_to_string __P((u_long, char *));
+int	 string_to_flags __P((char **, u_long *, u_long *));
+void	 prcopy __P((char *, char *, int));
+void	 printacol __P((DISPLAY *));
+void	 printcol __P((DISPLAY *));
+void	 printlong __P((DISPLAY *));
+void	 printscol __P((DISPLAY *));
+void	 usage __P((void));
diff --git a/ls/ls.1 b/ls/ls.1
new file mode 100644
index 0000000..6181998
--- /dev/null
+++ b/ls/ls.1
@@ -0,0 +1,367 @@
+.\"	$NetBSD: ls.1,v 1.19 1998/06/01 21:11:28 hubertf Exp $
+.\"
+.\" Copyright (c) 1980, 1990, 1991, 1993, 1994
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     @(#)ls.1	8.7 (Berkeley) 7/29/94
+.\"
+.Dd July 29, 1994
+.Dt LS 1
+.Os
+.Sh NAME
+.Nm ls
+.Nd list directory contents
+.Sh SYNOPSIS
+.Nm
+.Op Fl ACFLRSTWacdfgiklnoqrstux1
+.Op Ar file ...
+.Sh DESCRIPTION
+For each operand that names a
+.Ar file
+of a type other than
+directory,
+.Nm
+displays its name as well as any requested,
+associated information.
+For each operand that names a
+.Ar file
+of type directory,
+.Nm
+displays the names of files contained
+within that directory, as well as any requested, associated
+information.
+.Pp
+If no operands are given, the contents of the current
+directory are displayed.
+If more than one operand is given,
+non-directory operands are displayed first; directory
+and non-directory operands are sorted separately and in
+lexicographical order.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl A
+List all entries except for
+.Ql \&.
+and
+.Ql \&.. .
+Always set for the super-user.
+.It Fl C
+Force multi-column output; this is the default when output is to a terminal.
+.It Fl F
+Display a slash (/) immediately after each pathname that is a directory,
+an asterisk (*) after each that is executable,
+an at sign (@) after each symbolic link,
+a percent sign (%) after each whiteout,
+an equal sign (=) after each socket,
+and a vertical bar (|) after each that is a
+.Tn FIFO . 
+.It Fl L
+If argument is a symbolic link, list the file or directory the link references
+rather than the link itself.
+.It Fl R
+Recursively list subdirectories encountered.
+.It Fl S
+Sort by size, largest file first.
+.It Fl T
+Display complete time information for the file, including
+month, day, hour, minute, second, and year.
+.It Fl W
+Display whiteouts when scanning directories.
+.It Fl a
+Include directory entries whose names begin with a
+dot (.).
+.It Fl c
+Use time when file status was last changed for sorting or printing.
+.It Fl d
+Directories are listed as plain files (not searched recursively) and
+symbolic links in the argument list are not indirected through.
+.It Fl f
+Output is not sorted.
+.It Fl g
+Does nothing; kept for compatibility with older versions of
+.Xr ls 1 .
+.It Fl i
+For each file, print the file's file serial number (inode number).
+.It Fl k
+Modifies the
+.Fl s
+option, causing the sizes to be reported in kilobytes.
+.It Fl l
+(The lowercase letter ``ell.'')  List in long format. (See below.)
+If the output is to a terminal, a total sum for all the file
+sizes is output on a line before the long listing.
+.It Fl n
+Display the user and group IDs numerically rather than converting
+to a user or group name in a long
+.Pq Fl l
+output.
+.It Fl o
+Include the file flags in a long
+.Pq Fl l
+output.
+.It Fl q
+Force printing of non-graphic characters in file names as
+the character `?'; this is the default when output is to a terminal.
+.It Fl r
+Reverse the order of the sort to get reverse
+lexicographical order or the smallest or oldest entries first.
+.It Fl s
+Display the number of file system blocks actually used by each file, in units
+of 512 bytes, where partial units are rounded up to the next integer value.
+If the output is to a terminal, a total sum for all the file
+sizes is output on a line before the listing.
+.It Fl t
+Sort by time modified (most recently modified
+first) before sorting the operands by lexicographical
+order.
+.It Fl u
+Use time of last access,
+instead of last modification
+of the file for sorting
+.Pq Fl t
+or printing
+.Pq Fl l .
+.It Fl x
+Multi-column output sorted across the page rather than down the page.
+.It Fl v
+Force unedited printing of non-graphic characters; this is the default when
+output is not to a terminal.
+.It Fl \&1
+(The numeric digit ``one.'')  Force output to be
+one entry per line.
+This is the default when
+output is not to a terminal.
+.El
+.Pp
+The
+.Fl 1 ,
+.Fl C ,
+.Fl l ,
+and
+.Fl x
+options all override each other; the last one specified determines
+the format used.
+.Pp
+The
+.Fl c ,
+and
+.Fl u
+options override each other; the last one specified determines
+the file time used.
+.Pp
+By default,
+.Nm
+lists one entry per line to standard
+output; the exceptions are to terminals or when the
+.Fl C
+option is specified.
+.Pp
+File information is displayed with one or more
+<blank>s separating the information associated with the
+.Fl i ,
+.Fl s ,
+and
+.Fl l
+options.
+.Ss The Long Format
+If the
+.Fl l
+option is given, the following information
+is displayed for each file:
+file mode,
+number of links, owner name, group name,
+number of bytes in the file, abbreviated
+month, day-of-month file was last modified,
+hour file last modified, minute file last
+modified, and the pathname.
+In addition, for each directory whose contents are displayed, the total
+number of 512-byte blocks used by the files in the directory is displayed
+on a line by itself immediately before the information for the files in the
+directory.
+.Pp
+If the owner or group names are not a known user or group name,
+or the
+.Fl n
+option is given,
+the numeric ID's are displayed.
+.Pp
+If the file is a character special or block special file,
+the major and minor device numbers for the file are displayed
+in the size field. If the file is a symbolic link the pathname of the
+linked-to file is preceded by
+.Dq \-> .
+.Pp
+The file mode printed under the
+.Fl l
+option consists of the
+entry type, owner permissions, and group permissions.
+The entry type character describes the type of file, as
+follows:
+.Pp
+.Bl -tag -width 4n -offset indent -compact
+.It Sy b
+Block special file.
+.It Sy c
+Character special file.
+.It Sy d
+Directory.
+.It Sy l
+Symbolic link.
+.It Sy s
+Socket link.
+.\" .It Sy p
+.\" .Tn FIFO .
+.It Sy w
+Whiteout.
+.It Sy \-
+Regular file.
+.El
+.Pp
+The next three fields
+are three characters each:
+owner permissions,
+group permissions, and
+other permissions.
+Each field has three character positions:
+.Bl -enum -offset indent
+.It
+If
+.Sy r ,
+the file is readable; if
+.Sy \- ,
+it is not readable.
+.It
+If
+.Sy w ,
+the file is writable; if
+.Sy \- ,
+it is not writable.
+.It
+The first of the following that applies:
+.Bl -tag -width 4n -offset indent
+.It Sy S
+If in the owner permissions, the file is not executable and
+set-user-ID mode is set.
+If in the group permissions, the file is not executable
+and set-group-ID mode is set.
+.It Sy s
+If in the owner permissions, the file is executable
+and set-user-ID mode is set.
+If in the group permissions, the file is executable
+and setgroup-ID mode is set.
+.It Sy x
+The file is executable or the directory is
+searchable.
+.It Sy \-
+The file is neither readable, writable, executable,
+nor set-user-ID nor set-group-ID mode, nor sticky. (See below.)
+.El
+.Pp
+These next two apply only to the third character in the last group
+(other permissions).
+.Bl -tag -width 4n -offset indent
+.It Sy T
+The sticky bit is set
+(mode
+.Li 1000 ) ,
+but not execute or search permission. (See
+.Xr chmod 1
+or
+.Xr sticky 8 . )
+.It Sy t
+The sticky bit is set (mode
+.Li 1000 ) ,
+and is searchable or executable.
+(See
+.Xr chmod 1
+or
+.Xr sticky 8 . )
+.El
+.El
+.Pp
+The
+.Nm
+utility exits 0 on success, and >0 if an error occurs.
+.Sh ENVIRONMENT VARIABLES
+The following environment variables affect the execution of
+.Nm "" :
+.Bl -tag -width BLOCKSIZE
+.It Ev BLOCKSIZE
+If the environment variable
+.Ev BLOCKSIZE
+is set, and the
+.Fl k
+option is not specified, the block counts
+(see
+.Fl s )
+will be displayed in units of that size block.
+.It COLUMNS
+If this variable contains a string representing a
+decimal integer, it is used as the
+column position width for displaying
+multiple-text-column output.
+The
+.Nm
+utility calculates how
+many pathname text columns to display
+based on the width provided.
+(See
+.Fl C . )
+.It Ev TZ
+The timezone to use when displaying dates.
+See
+.Xr environ 7
+for more information.
+.El
+.Sh COMPATIBILITY
+The group field is now automatically included in the long listing for
+files in order to be compatible with the
+.St -p1003.2
+specification.
+.Sh SEE ALSO
+.Xr chmod 1 ,
+.Xr symlink 7 ,
+.Xr sticky 8
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be a superset of the
+.St -p1003.2
+specification.
+.Sh HISTORY
+An
+.Nm
+utility appeared in
+.At v5 .
diff --git a/ls/ls.c b/ls/ls.c
new file mode 100644
index 0000000..c943b9c
--- /dev/null
+++ b/ls/ls.c
@@ -0,0 +1,616 @@
+/*	$NetBSD: ls.c,v 1.31 1998/08/19 01:44:19 thorpej Exp $	*/
+
+/*
+ * Copyright (c) 1989, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Michael Fischbein.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1989, 1993, 1994\n\
+	The Regents of the University of California.  All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)ls.c	8.7 (Berkeley) 8/5/94";
+#else
+__RCSID("$NetBSD: ls.c,v 1.31 1998/08/19 01:44:19 thorpej Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include "ls.h"
+#include "extern.h"
+
+int	main __P((int, char *[]));
+
+static void	 display __P((FTSENT *, FTSENT *));
+static int	 mastercmp __P((const FTSENT **, const FTSENT **));
+static void	 traverse __P((int, char **, int));
+
+static void (*printfcn) __P((DISPLAY *));
+static int (*sortfcn) __P((const FTSENT *, const FTSENT *));
+
+#define	BY_NAME 0
+#define	BY_SIZE 1
+#define	BY_TIME	2
+
+long blocksize;			/* block size units */
+int termwidth = 80;		/* default terminal width */
+int sortkey = BY_NAME;
+
+/* flags */
+int f_accesstime;		/* use time of last access */
+int f_column;			/* columnated format */
+int f_columnacross;		/* columnated format, sorted across */
+int f_flags;			/* show flags associated with a file */
+int f_inode;			/* print inode */
+int f_listdir;			/* list actual directory, not contents */
+int f_listdot;			/* list files beginning with . */
+int f_longform;			/* long listing format */
+int f_nonprint;			/* show unprintables as ? */
+int f_nosort;			/* don't sort output */
+int f_numericonly;		/* don't convert uid/gid to name */
+int f_recursive;		/* ls subdirectories also */
+int f_reversesort;		/* reverse whatever sort is used */
+int f_sectime;			/* print the real time for all files */
+int f_singlecol;		/* use single column output */
+int f_size;			/* list size in short listing */
+int f_statustime;		/* use time of last mode change */
+int f_type;			/* add type character for non-regular files */
+int f_whiteout;			/* show whiteout entries */
+
+int
+main(argc, argv)
+	int argc;
+	char *argv[];
+{
+	static char dot[] = ".", *dotav[] = { dot, NULL };
+	struct winsize win;
+	int ch, fts_options, notused;
+	int kflag = 0;
+	const char *p;
+
+	/* Terminal defaults to -Cq, non-terminal defaults to -1. */
+	if (isatty(STDOUT_FILENO)) {
+		if ((p = getenv("COLUMNS")) != NULL)
+			termwidth = atoi(p);
+		else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 &&
+		    win.ws_col > 0)
+			termwidth = win.ws_col;
+		f_column = f_nonprint = 1;
+	} else
+		f_singlecol = 1;
+
+	/* Root is -A automatically. */
+	if (!getuid())
+		f_listdot = 1;
+
+	fts_options = FTS_PHYSICAL;
+	while ((ch = getopt(argc, argv, "1ACFLRSTWacdfgiklnoqrstuxv")) != -1) {
+		switch (ch) {
+		/*
+		 * The -1, -C, -l and -x options all override each other so
+		 * shell aliasing works correctly.
+		 */
+		case '1':
+			f_singlecol = 1;
+			f_column = f_columnacross = f_longform = 0;
+			break;
+		case 'C':
+			f_column = 1;
+			f_columnacross = f_longform = f_singlecol = 0;
+			break;
+		case 'l':
+			f_longform = 1;
+			f_column = f_columnacross = f_singlecol = 0;
+			break;
+		case 'x':
+			f_columnacross = 1;
+			f_column = f_longform = f_singlecol = 0;
+			break;
+		/* The -c and -u options override each other. */
+		case 'c':
+			f_statustime = 1;
+			f_accesstime = 0;
+			break;
+		case 'u':
+			f_accesstime = 1;
+			f_statustime = 0;
+			break;
+		case 'F':
+			f_type = 1;
+			break;
+		case 'L':
+			fts_options &= ~FTS_PHYSICAL;
+			fts_options |= FTS_LOGICAL;
+			break;
+		case 'R':
+			f_recursive = 1;
+			break;
+		case 'a':
+			fts_options |= FTS_SEEDOT;
+			/* FALLTHROUGH */
+		case 'A':
+			f_listdot = 1;
+			break;
+		/* The -d option turns off the -R option. */
+		case 'd':
+			f_listdir = 1;
+			f_recursive = 0;
+			break;
+		case 'f':
+			f_nosort = 1;
+			break;
+		case 'g':		/* Compatibility with 4.3BSD. */
+			break;
+		case 'i':
+			f_inode = 1;
+			break;
+		case 'k':
+			blocksize = 1024;
+			kflag = 1;
+			break;
+		case 'n':
+			f_numericonly = 1;
+			break;
+		case 'o':
+			f_flags = 1;
+			break;
+		case 'q':
+			f_nonprint = 1;
+			break;
+		case 'r':
+			f_reversesort = 1;
+			break;
+		case 'S':
+			sortkey = BY_SIZE;
+			break;
+		case 's':
+			f_size = 1;
+			break;
+		case 'T':
+			f_sectime = 1;
+			break;
+		case 't':
+			sortkey = BY_TIME;
+			break;
+		case 'W':
+			f_whiteout = 1;
+			break;
+		case 'v':
+			f_nonprint = 0;
+			break;
+		default:
+		case '?':
+			usage();
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	/*
+	 * If not -F, -i, -l, -S, -s or -t options, don't require stat
+	 * information.
+	 */
+	if (!f_inode && !f_longform && !f_size && !f_type &&
+	    sortkey == BY_NAME)
+		fts_options |= FTS_NOSTAT;
+
+	/*
+	 * If not -F, -d or -l options, follow any symbolic links listed on
+	 * the command line.
+	 */
+	if (!f_longform && !f_listdir && !f_type)
+		fts_options |= FTS_COMFOLLOW;
+
+	/*
+	 * If -W, show whiteout entries
+	 */
+#ifdef FTS_WHITEOUT
+	if (f_whiteout)
+		fts_options |= FTS_WHITEOUT;
+#endif
+
+	/* If -l or -s, figure out block size. */
+	if (f_longform || f_size) {
+		if (!kflag)
+			(void)getbsize(&notused, &blocksize);
+		blocksize /= 512;
+	}
+
+	/* Select a sort function. */
+	if (f_reversesort) {
+		switch (sortkey) {
+		case BY_NAME:
+			sortfcn = revnamecmp;
+			break;
+		case BY_SIZE:
+			sortfcn = revsizecmp;
+			break;
+		case BY_TIME:
+			if (f_accesstime)
+				sortfcn = revacccmp;
+			else if (f_statustime)
+				sortfcn = revstatcmp;
+			else /* Use modification time. */
+				sortfcn = revmodcmp;
+			break;
+		}
+	} else {
+		switch (sortkey) {
+		case BY_NAME:
+			sortfcn = namecmp;
+			break;
+		case BY_SIZE:
+			sortfcn = sizecmp;
+			break;
+		case BY_TIME:
+			if (f_accesstime)
+				sortfcn = acccmp;
+			else if (f_statustime)
+				sortfcn = statcmp;
+			else /* Use modification time. */
+				sortfcn = modcmp;
+			break;
+		}
+	}
+
+	/* Select a print function. */
+	if (f_singlecol)
+		printfcn = printscol;
+	else if (f_columnacross)
+		printfcn = printacol;
+	else if (f_longform)
+		printfcn = printlong;
+	else
+		printfcn = printcol;
+
+	if (argc)
+		traverse(argc, argv, fts_options);
+	else
+		traverse(1, dotav, fts_options);
+	exit(0);
+	/* NOTREACHED */
+}
+
+static int output;			/* If anything output. */
+
+/*
+ * Traverse() walks the logical directory structure specified by the argv list
+ * in the order specified by the mastercmp() comparison function.  During the
+ * traversal it passes linked lists of structures to display() which represent
+ * a superset (may be exact set) of the files to be displayed.
+ */
+static void
+traverse(argc, argv, options)
+	int argc, options;
+	char *argv[];
+{
+	FTS *ftsp;
+	FTSENT *p, *chp;
+	int ch_options;
+	char pbuf[MAXPATHLEN + 1], *path;
+
+	if ((ftsp =
+	    fts_open(argv, options, f_nosort ? NULL : mastercmp)) == NULL)
+		err(1, "%s", "");
+
+	display(NULL, fts_children(ftsp, 0));
+	if (f_listdir)
+		return;
+
+	/*
+	 * If not recursing down this tree and don't need stat info, just get
+	 * the names.
+	 */
+	ch_options = !f_recursive && options & FTS_NOSTAT ? FTS_NAMEONLY : 0;
+
+	while ((p = fts_read(ftsp)) != NULL)
+		switch (p->fts_info) {
+		case FTS_DC:
+			warnx("%s: directory causes a cycle", p->fts_name);
+			break;
+		case FTS_DNR:
+		case FTS_ERR:
+			warnx("%s: %s", p->fts_name, strerror(p->fts_errno));
+			break;
+		case FTS_D:
+			if (p->fts_level != FTS_ROOTLEVEL &&
+			    p->fts_name[0] == '.' && !f_listdot)
+				break;
+
+			/*
+			 * If already output something, put out a newline as
+			 * a separator.  If multiple arguments, precede each
+			 * directory with its name.
+			 */
+			if (f_nonprint) {
+				prcopy(p->fts_path, pbuf, p->fts_pathlen+1);
+				path = pbuf;
+			} else
+				path = p->fts_path;
+
+			if (output)
+				(void)printf("\n%s:\n", path);
+			else if (argc > 1) {
+				(void)printf("%s:\n", path);
+				output = 1;
+			}
+
+			chp = fts_children(ftsp, ch_options);
+			display(p, chp);
+
+			if (!f_recursive && chp != NULL)
+				(void)fts_set(ftsp, p, FTS_SKIP);
+			break;
+		}
+	if (errno)
+		err(1, "fts_read");
+}
+
+/*
+ * Display() takes a linked list of FTSENT structures and passes the list
+ * along with any other necessary information to the print function.  P
+ * points to the parent directory of the display list.
+ */
+static void
+display(p, list)
+	FTSENT *p, *list;
+{
+	struct stat *sp;
+	DISPLAY d;
+	FTSENT *cur;
+	NAMES *np;
+	u_int64_t btotal, maxblock, maxsize;
+	int maxinode, maxnlink, maxmajor, maxminor;
+	int bcfile, entries, flen, glen, ulen, maxflags, maxgroup, maxlen;
+	int maxuser, needstats;
+	const char *user, *group;
+	char ubuf[21]="", gbuf[21]="", buf[21];	/* 64 bits == 20 digits, +1 for NUL */
+	char nuser[12], ngroup[12];
+	char *flags = NULL;
+
+#ifdef __GNUC__
+	/* This outrageous construct just to shut up a GCC warning. */
+	(void) &maxsize;
+#endif
+
+	/*
+	 * If list is NULL there are two possibilities: that the parent
+	 * directory p has no children, or that fts_children() returned an
+	 * error.  We ignore the error case since it will be replicated
+	 * on the next call to fts_read() on the post-order visit to the
+	 * directory p, and will be signalled in traverse().
+	 */
+	if (list == NULL)
+		return;
+
+	needstats = f_inode || f_longform || f_size;
+	flen = 0;
+	maxinode = maxnlink = 0;
+	bcfile = 0;
+	maxuser = maxgroup = maxflags = maxlen = 0;
+	btotal = maxblock = maxsize = 0;
+	maxmajor = maxminor = 0;
+	for (cur = list, entries = 0; cur; cur = cur->fts_link) {
+		if (cur->fts_info == FTS_ERR || cur->fts_info == FTS_NS) {
+			warnx("%s: %s",
+			    cur->fts_name, strerror(cur->fts_errno));
+			cur->fts_number = NO_PRINT;
+			continue;
+		}
+
+		/*
+		 * P is NULL if list is the argv list, to which different rules
+		 * apply.
+		 */
+		if (p == NULL) {
+			/* Directories will be displayed later. */
+			if (cur->fts_info == FTS_D && !f_listdir) {
+				cur->fts_number = NO_PRINT;
+				continue;
+			}
+		} else {
+			/* Only display dot file if -a/-A set. */
+			if (cur->fts_name[0] == '.' && !f_listdot) {
+				cur->fts_number = NO_PRINT;
+				continue;
+			}
+		}
+		if (cur->fts_namelen > maxlen)
+			maxlen = cur->fts_namelen;
+		if (needstats) {
+			sp = cur->fts_statp;
+			if (sp->st_blocks > maxblock)
+				maxblock = sp->st_blocks;
+			if (sp->st_ino > maxinode)
+				maxinode = sp->st_ino;
+			if (sp->st_nlink > maxnlink)
+				maxnlink = sp->st_nlink;
+			if (sp->st_size > maxsize)
+				maxsize = sp->st_size;
+			if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode)) {
+				bcfile = 1;
+				if (major(sp->st_rdev) > maxmajor)
+					maxmajor = major(sp->st_rdev);
+				if (minor(sp->st_rdev) > maxminor)
+					maxminor = minor(sp->st_rdev);
+			}
+
+			btotal += sp->st_blocks;
+			if (f_longform) {
+				if (f_numericonly) {
+					(void)snprintf(nuser, sizeof(nuser),
+					    "%u", sp->st_uid);
+					(void)snprintf(ngroup, sizeof(ngroup),
+					    "%u", sp->st_gid);
+					user = nuser;
+					group = ngroup;
+				} else {
+					if ((user = user_from_uid(sp->st_uid, 0)) == NULL) {
+						(void)snprintf(ubuf, sizeof(ubuf), "%d", (int)sp->st_uid);
+						user = ubuf;
+					}
+					if ((group = group_from_gid(sp->st_gid, 0)) == NULL) {
+						(void)snprintf(gbuf, sizeof(gbuf), "%d", (int)sp->st_gid);
+						group = gbuf;
+					}
+				}
+				if ((ulen = strlen(user)) > maxuser)
+					maxuser = ulen;
+				if ((glen = strlen(group)) > maxgroup)
+					maxgroup = glen;
+				if (f_flags) {
+					flags =
+					    flags_to_string(sp->st_flags, "-");
+					if ((flen = strlen(flags)) > maxflags)
+						maxflags = flen;
+				} else
+					flen = 0;
+
+				if ((np = malloc(sizeof(NAMES) +
+				    ulen + glen + flen + 3)) == NULL)
+					err(1, "%s", "");
+
+				np->user = &np->data[0];
+				(void)strcpy(np->user, user);
+				np->group = &np->data[ulen + 1];
+				(void)strcpy(np->group, group);
+
+				if (f_flags) {
+					np->flags = &np->data[ulen + glen + 2];
+				  	(void)strcpy(np->flags, flags);
+				}
+				cur->fts_pointer = np;
+			}
+		}
+		++entries;
+	}
+
+	if (!entries)
+		return;
+
+	d.list = list;
+	d.entries = entries;
+	d.maxlen = maxlen;
+	if (needstats) {
+		d.btotal = btotal;
+		(void)snprintf(buf, sizeof(buf), "%qu", (long long)maxblock);
+		d.s_block = strlen(buf);
+		d.s_flags = maxflags;
+		d.s_group = maxgroup;
+		(void)snprintf(buf, sizeof(buf), "%u", maxinode);
+		d.s_inode = strlen(buf);
+		(void)snprintf(buf, sizeof(buf), "%u", maxnlink);
+		d.s_nlink = strlen(buf);
+		(void)snprintf(buf, sizeof(buf), "%qu", (long long)maxsize);
+		d.s_size = strlen(buf);
+		d.s_user = maxuser;
+		if (bcfile) {
+			(void)snprintf(buf, sizeof(buf), "%u", maxmajor);
+			d.s_major = strlen(buf);
+			(void)snprintf(buf, sizeof(buf), "%u", maxminor);
+			d.s_minor = strlen(buf);
+			if (d.s_major + d.s_minor + 2 > d.s_size)
+				d.s_size = d.s_major + d.s_minor + 2;
+			else if (d.s_size - d.s_minor - 2 > d.s_major)
+				d.s_major = d.s_size - d.s_minor - 2;
+		} else {
+			d.s_major = 0;
+			d.s_minor = 0;
+		}
+	}
+
+	printfcn(&d);
+	output = 1;
+
+	if (f_longform)
+		for (cur = list; cur; cur = cur->fts_link)
+			free(cur->fts_pointer);
+}
+
+/*
+ * Ordering for mastercmp:
+ * If ordering the argv (fts_level = FTS_ROOTLEVEL) return non-directories
+ * as larger than directories.  Within either group, use the sort function.
+ * All other levels use the sort function.  Error entries remain unsorted.
+ */
+static int
+mastercmp(a, b)
+	const FTSENT **a, **b;
+{
+	int a_info, b_info;
+
+	a_info = (*a)->fts_info;
+	if (a_info == FTS_ERR)
+		return (0);
+	b_info = (*b)->fts_info;
+	if (b_info == FTS_ERR)
+		return (0);
+
+	if (a_info == FTS_NS || b_info == FTS_NS) {
+		if (b_info != FTS_NS)
+			return (1);
+		else if (a_info != FTS_NS)
+			return (-1);
+		else
+			return (namecmp(*a, *b));
+	}
+
+	if (a_info != b_info && !f_listdir &&
+	    (*a)->fts_level == FTS_ROOTLEVEL) {
+		if (a_info == FTS_D)
+			return (1);
+		else if (b_info == FTS_D)
+			return (-1);
+	}
+	return (sortfcn(*a, *b));
+}
diff --git a/ls/ls.h b/ls/ls.h
new file mode 100644
index 0000000..733a7bb
--- /dev/null
+++ b/ls/ls.h
@@ -0,0 +1,76 @@
+/*	$NetBSD: ls.h,v 1.9 1998/05/16 15:12:26 lukem Exp $	*/
+
+/*
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Michael Fischbein.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)ls.h	8.1 (Berkeley) 5/31/93
+ */
+
+#define NO_PRINT	1
+
+extern long blocksize;		/* block size units */
+
+extern int f_accesstime;	/* use time of last access */
+extern int f_flags;		/* show flags associated with a file */
+extern int f_inode;		/* print inode */
+extern int f_longform;		/* long listing format */
+extern int f_nonprint;		/* show unprintables as ? */
+extern int f_sectime;		/* print the real time for all files */
+extern int f_size;		/* list size in short listing */
+extern int f_statustime;	/* use time of last mode change */
+extern int f_type;		/* add type character for non-regular files */
+
+typedef struct {
+	FTSENT *list;
+	u_int64_t btotal;
+	int entries;
+	int maxlen;
+	int s_block;
+	int s_flags;
+	int s_group;
+	int s_inode;
+	int s_nlink;
+	int s_size;
+	int s_user;
+	int s_major;
+	int s_minor;
+} DISPLAY;
+
+typedef struct {
+	char *user;
+	char *group;
+	char *flags;
+	char data[1];
+} NAMES;
diff --git a/ls/print.c b/ls/print.c
new file mode 100644
index 0000000..240f221
--- /dev/null
+++ b/ls/print.c
@@ -0,0 +1,363 @@
+/*	$NetBSD: print.c,v 1.22 1998/07/28 05:15:47 mycroft Exp $	*/
+
+/*
+ * Copyright (c) 1989, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Michael Fischbein.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)print.c	8.5 (Berkeley) 7/28/94";
+#else
+__RCSID("$NetBSD: print.c,v 1.22 1998/07/28 05:15:47 mycroft Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <tzfile.h>
+#include <unistd.h>
+#include <utmp.h>
+
+#include "ls.h"
+#include "extern.h"
+
+static int	printaname __P((FTSENT *, int, int));
+static void	printlink __P((FTSENT *));
+static void	printtime __P((time_t));
+static int	printtype __P((u_int));
+
+static time_t	now;
+
+#define	IS_NOPRINT(p)	((p)->fts_number == NO_PRINT)
+
+void
+printscol(dp)
+	DISPLAY *dp;
+{
+	FTSENT *p;
+
+	for (p = dp->list; p; p = p->fts_link) {
+		if (IS_NOPRINT(p))
+			continue;
+		(void)printaname(p, dp->s_inode, dp->s_block);
+		(void)putchar('\n');
+	}
+}
+
+void
+printlong(dp)
+	DISPLAY *dp;
+{
+	struct stat *sp;
+	FTSENT *p;
+	NAMES *np;
+	char buf[20];
+	char nbuf[MAXPATHLEN + 1], *name;
+
+	now = time(NULL);
+
+	if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
+		(void)printf("total %qu\n",
+		    (long long)(howmany(dp->btotal, blocksize)));
+
+	for (p = dp->list; p; p = p->fts_link) {
+		if (IS_NOPRINT(p))
+			continue;
+		sp = p->fts_statp;
+		if (f_inode)
+			(void)printf("%*u ", dp->s_inode, sp->st_ino);
+		if (f_size)
+			(void)printf("%*qu ", dp->s_block,
+			    (long long)howmany(sp->st_blocks, blocksize));
+		(void)strmode(sp->st_mode, buf);
+		np = p->fts_pointer;
+		(void)printf("%s %*u %-*s  %-*s  ", buf, dp->s_nlink,
+		    sp->st_nlink, dp->s_user, np->user, dp->s_group,
+		    np->group);
+		if (f_flags)
+			(void)printf("%-*s ", dp->s_flags, np->flags);
+		if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode))
+			(void)printf("%*u, %*u ",
+			    dp->s_major, major(sp->st_rdev), dp->s_minor,
+			    minor(sp->st_rdev));
+		else
+			(void)printf("%*qu ", dp->s_size,
+			    (long long)sp->st_size);
+		if (f_accesstime)
+			printtime(sp->st_atime);
+		else if (f_statustime)
+			printtime(sp->st_ctime);
+		else
+			printtime(sp->st_mtime);
+		if (f_nonprint) {
+			prcopy(p->fts_name, nbuf, p->fts_namelen+1);
+			name = nbuf;
+		} else
+			name = p->fts_name;
+		(void)printf("%s", name);
+		if (f_type)
+			(void)printtype(sp->st_mode);
+		if (S_ISLNK(sp->st_mode))
+			printlink(p);
+		(void)putchar('\n');
+	}
+}
+
+void
+printcol(dp)
+	DISPLAY *dp;
+{
+	extern int termwidth;
+	static FTSENT **array;
+	static int lastentries = -1;
+	FTSENT *p;
+	int base, chcnt, col, colwidth, num;
+	int numcols, numrows, row;
+
+	colwidth = dp->maxlen;
+	if (f_inode)
+		colwidth += dp->s_inode + 1;
+	if (f_size)
+		colwidth += dp->s_block + 1;
+	if (f_type)
+		colwidth += 1;
+
+	colwidth += 1;
+
+	if (termwidth < 2 * colwidth) {
+		printscol(dp);
+		return;
+	}
+
+	/*
+	 * Have to do random access in the linked list -- build a table
+	 * of pointers.
+	 */
+	if (dp->entries > lastentries) {
+		lastentries = dp->entries;
+		if ((array =
+		    realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) {
+			warn("%s", "");
+			printscol(dp);
+		}
+	}
+	for (p = dp->list, num = 0; p; p = p->fts_link)
+		if (p->fts_number != NO_PRINT)
+			array[num++] = p;
+
+	numcols = termwidth / colwidth;
+	colwidth = termwidth / numcols;		/* spread out if possible */
+	numrows = num / numcols;
+	if (num % numcols)
+		++numrows;
+
+	if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
+		(void)printf("total %qu\n",
+		    (long long)(howmany(dp->btotal, blocksize)));
+	for (row = 0; row < numrows; ++row) {
+		for (base = row, chcnt = col = 0; col < numcols; ++col) {
+			chcnt = printaname(array[base], dp->s_inode,
+			    dp->s_block);
+			if ((base += numrows) >= num)
+				break;
+			while (chcnt++ < colwidth)
+				(void)putchar(' ');
+		}
+		(void)putchar('\n');
+	}
+}
+
+void
+printacol(dp)
+	DISPLAY *dp;
+{
+	extern int termwidth;
+	FTSENT *p;
+	int chcnt, col, colwidth;
+	int numcols;
+
+	colwidth = dp->maxlen;
+	if (f_inode)
+		colwidth += dp->s_inode + 1;
+	if (f_size)
+		colwidth += dp->s_block + 1;
+	if (f_type)
+		colwidth += 1;
+
+	colwidth += 1;
+
+	if (termwidth < 2 * colwidth) {
+		printscol(dp);
+		return;
+	}
+
+	numcols = termwidth / colwidth;
+	colwidth = termwidth / numcols;		/* spread out if possible */
+
+	if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
+		(void)printf("total %qu\n", 
+		    (long long)(howmany(dp->btotal, blocksize)));
+	chcnt = col = 0;
+	for (p = dp->list; p; p = p->fts_link) {
+		if (IS_NOPRINT(p))
+			continue;
+		if (col >= numcols) {
+			chcnt = col = 0;
+			(void)putchar('\n');
+		}
+		chcnt = printaname(p, dp->s_inode, dp->s_block);
+		while (chcnt++ < colwidth)
+			(void)putchar(' ');
+		col++;
+	}
+	(void)putchar('\n');
+}
+
+/*
+ * print [inode] [size] name
+ * return # of characters printed, no trailing characters.
+ */
+static int
+printaname(p, inodefield, sizefield)
+	FTSENT *p;
+	int sizefield, inodefield;
+{
+	struct stat *sp;
+	int chcnt;
+	char nbuf[MAXPATHLEN + 1], *name;
+
+	sp = p->fts_statp;
+	chcnt = 0;
+	if (f_inode)
+		chcnt += printf("%*u ", inodefield, sp->st_ino);
+	if (f_size)
+		chcnt += printf("%*qu ", sizefield,
+		    (long long)howmany(sp->st_blocks, blocksize));
+	if (f_nonprint) {
+		prcopy(p->fts_name, nbuf, p->fts_namelen+1);
+		name = nbuf;
+	} else
+		name = p->fts_name;
+	chcnt += printf("%s", name);
+	if (f_type)
+		chcnt += printtype(sp->st_mode);
+	return (chcnt);
+}
+
+static void
+printtime(ftime)
+	time_t ftime;
+{
+	int i;
+	char *longstring;
+
+	longstring = ctime(&ftime);
+	for (i = 4; i < 11; ++i)
+		(void)putchar(longstring[i]);
+
+#define	SIXMONTHS	((DAYSPERNYEAR / 2) * SECSPERDAY)
+	if (f_sectime)
+		for (i = 11; i < 24; i++)
+			(void)putchar(longstring[i]);
+	else if (ftime + SIXMONTHS > now && ftime - SIXMONTHS < now)
+		for (i = 11; i < 16; ++i)
+			(void)putchar(longstring[i]);
+	else {
+		(void)putchar(' ');
+		for (i = 20; i < 24; ++i)
+			(void)putchar(longstring[i]);
+	}
+	(void)putchar(' ');
+}
+
+static int
+printtype(mode)
+	u_int mode;
+{
+	switch (mode & S_IFMT) {
+	case S_IFDIR:
+		(void)putchar('/');
+		return (1);
+	case S_IFIFO:
+		(void)putchar('|');
+		return (1);
+	case S_IFLNK:
+		(void)putchar('@');
+		return (1);
+	case S_IFSOCK:
+		(void)putchar('=');
+		return (1);
+	case S_IFWHT:
+		(void)putchar('%');
+		return (1);
+	}
+	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
+		(void)putchar('*');
+		return (1);
+	}
+	return (0);
+}
+
+static void
+printlink(p)
+	FTSENT *p;
+{
+	int lnklen;
+	char name[MAXPATHLEN + 1], path[MAXPATHLEN + 1];
+
+	if (p->fts_level == FTS_ROOTLEVEL)
+		(void)snprintf(name, sizeof(name), "%s", p->fts_name);
+	else 
+		(void)snprintf(name, sizeof(name),
+		    "%s/%s", p->fts_parent->fts_accpath, p->fts_name);
+	prcopy(name, name, strlen(name));
+	if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) {
+		(void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno));
+		return;
+	}
+	path[lnklen] = '\0';
+	(void)printf(" -> %s", path);
+}
diff --git a/ls/stat_flags.c b/ls/stat_flags.c
new file mode 100644
index 0000000..e46a3e8
--- /dev/null
+++ b/ls/stat_flags.c
@@ -0,0 +1,164 @@
+/*	$NetBSD: stat_flags.c,v 1.6 1997/07/20 18:53:12 christos Exp $	*/
+
+/*-
+ * Copyright (c) 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)stat_flags.c	8.2 (Berkeley) 7/28/94";
+#else
+__RCSID("$NetBSD: stat_flags.c,v 1.6 1997/07/20 18:53:12 christos Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <stddef.h>
+#include <string.h>
+#include <fts.h>
+
+#include "ls.h"
+#include "extern.h"
+
+#define	SAPPEND(s) {							\
+	if (prefix != NULL)						\
+		(void)strcat(string, prefix);				\
+	(void)strcat(string, s);					\
+	prefix = ",";							\
+}
+
+/*
+ * flags_to_string --
+ *	Convert stat flags to a comma-separated string.  If no flags
+ *	are set, return the default string.
+ */
+char *
+flags_to_string(flags, def)
+	u_long flags;
+	char *def;
+{
+	static char string[128];
+	char *prefix;
+
+	string[0] = '\0';
+	prefix = NULL;
+	if (flags & UF_APPEND)
+		SAPPEND("uappnd");
+	if (flags & UF_IMMUTABLE)
+		SAPPEND("uchg");
+	if (flags & UF_NODUMP)
+		SAPPEND("nodump");
+	if (flags & UF_OPAQUE)
+		SAPPEND("opaque");
+	if (flags & SF_APPEND)
+		SAPPEND("sappnd");
+	if (flags & SF_ARCHIVED)
+		SAPPEND("arch");
+	if (flags & SF_IMMUTABLE)
+		SAPPEND("schg");
+	return (prefix == NULL && def != NULL ? def : string);
+}
+
+#define	TEST(a, b, f) {							\
+	if (!memcmp(a, b, sizeof(b))) {					\
+		if (clear) {						\
+			if (clrp)					\
+				*clrp |= (f);				\
+		} else if (setp)					\
+			*setp |= (f);					\
+		break;							\
+	}								\
+}
+
+/*
+ * string_to_flags --
+ *	Take string of arguments and return stat flags.  Return 0 on
+ *	success, 1 on failure.  On failure, stringp is set to point
+ *	to the offending token.
+ */
+int
+string_to_flags(stringp, setp, clrp)
+	char **stringp;
+	u_long *setp, *clrp;
+{
+	int clear;
+	char *string, *p;
+
+	clear = 0;
+	if (setp)
+		*setp = 0;
+	if (clrp)
+		*clrp = 0;
+	string = *stringp;
+	while ((p = strsep(&string, "\t ,")) != NULL) {
+		*stringp = p;
+		if (*p == '\0')
+			continue;
+		if (p[0] == 'n' && p[1] == 'o') {
+			clear = 1;
+			p += 2;
+		}
+		switch (p[0]) {
+		case 'a':
+			TEST(p, "arch", SF_ARCHIVED);
+			TEST(p, "archived", SF_ARCHIVED);
+			return (1);
+		case 'd':
+			clear = !clear;
+			TEST(p, "dump", UF_NODUMP);
+			return (1);
+		case 'o':
+			TEST(p, "opaque", UF_OPAQUE);
+			return (1);
+		case 's':
+			TEST(p, "sappnd", SF_APPEND);
+			TEST(p, "sappend", SF_APPEND);
+			TEST(p, "schg", SF_IMMUTABLE);
+			TEST(p, "schange", SF_IMMUTABLE);
+			TEST(p, "simmutable", SF_IMMUTABLE);
+			return (1);
+		case 'u':
+			TEST(p, "uappnd", UF_APPEND);
+			TEST(p, "uappend", UF_APPEND);
+			TEST(p, "uchg", UF_IMMUTABLE);
+			TEST(p, "uchange", UF_IMMUTABLE);
+			TEST(p, "uimmutable", UF_IMMUTABLE);
+			/* FALLTHROUGH */
+		default:
+			return (1);
+		}
+	}
+	return (0);
+}
diff --git a/ls/util.c b/ls/util.c
new file mode 100644
index 0000000..fee0027
--- /dev/null
+++ b/ls/util.c
@@ -0,0 +1,80 @@
+/*	$NetBSD: util.c,v 1.15 1998/07/28 05:31:25 mycroft Exp $	*/
+
+/*
+ * Copyright (c) 1989, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Michael Fischbein.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)util.c	8.5 (Berkeley) 4/28/95";
+#else
+__RCSID("$NetBSD: util.c,v 1.15 1998/07/28 05:31:25 mycroft Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <fts.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ls.h"
+#include "extern.h"
+
+void
+prcopy(src, dest, len)
+	char *src, *dest;
+	int len;
+{
+	int ch;
+
+	while (len--) {
+		ch = *src++;
+		*dest++ = (isprint(ch) || ch == '\0') ? ch : '?';
+	}
+}
+
+void
+usage()
+{
+	(void)fprintf(stderr, 
+	    "usage: ls [-1ACFLRSTWacdfgiklnoqrstux] [file ...]\n");
+	exit(1);
+	/* NOTREACHED */
+}
diff --git a/mkdir/Makefile b/mkdir/Makefile
new file mode 100644
index 0000000..d26e5ad
--- /dev/null
+++ b/mkdir/Makefile
@@ -0,0 +1,48 @@
+#
+# Generated by the NeXT Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = mkdir
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+CFILES = mkdir.c
+
+OTHERSRCS = Makefile Makefile.preamble Makefile.postamble mkdir.1
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /bin
+LIBS = 
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+
+
+NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/$(NAME)/Build
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
diff --git a/mkdir/Makefile.postamble b/mkdir/Makefile.postamble
new file mode 100644
index 0000000..013b558
--- /dev/null
+++ b/mkdir/Makefile.postamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
diff --git a/mkdir/Makefile.preamble b/mkdir/Makefile.preamble
new file mode 100644
index 0000000..9e10e90
--- /dev/null
+++ b/mkdir/Makefile.preamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
diff --git a/mkdir/PB.project b/mkdir/PB.project
new file mode 100644
index 0000000..0d6316a
--- /dev/null
+++ b/mkdir/PB.project
@@ -0,0 +1,25 @@
+{
+    DYNAMIC_CODE_GEN = YES; 
+    FILESTABLE = {
+        FRAMEWORKS = (); 
+        OTHER_LINKED = (mkdir.c); 
+        OTHER_SOURCES = (Makefile, Makefile.preamble, Makefile.postamble, mkdir.1); 
+    }; 
+    LANGUAGE = English; 
+    LOCALIZABLE_FILES = {}; 
+    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
+    NEXTSTEP_BUILDDIR = "/tmp/$(NAME)/Build"; 
+    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
+    NEXTSTEP_INSTALLDIR = /bin; 
+    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
+    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
+    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
+    PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; 
+    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
+    PROJECTNAME = mkdir; 
+    PROJECTTYPE = Tool; 
+    PROJECTVERSION = 2.8; 
+    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
+    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
+    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
+}
diff --git a/mkdir/mkdir.1 b/mkdir/mkdir.1
new file mode 100644
index 0000000..83b87a4
--- /dev/null
+++ b/mkdir/mkdir.1
@@ -0,0 +1,97 @@
+.\"	$NetBSD: mkdir.1,v 1.10 1997/10/20 08:52:35 enami Exp $
+.\"
+.\" Copyright (c) 1989, 1990, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)mkdir.1	8.2 (Berkeley) 1/25/94
+.\"
+.Dd January 25, 1994
+.Dt MKDIR 1
+.Os
+.Sh NAME
+.Nm mkdir
+.Nd make directories
+.Sh SYNOPSIS
+.Nm
+.Op Fl p
+.Op Fl m Ar mode
+.Ar directory_name  ...
+.Sh DESCRIPTION
+.Nm
+creates the directories named as operands, in the order specified,
+using mode
+.Li rwxrwxrwx (\&0777)
+as modified by the current
+.Xr umask  2  .
+.Pp
+The options are as follows:
+.Pp
+.Bl -tag -width indent
+.It Fl m
+Set the file permission bits of the final created directory to
+the specified mode.
+The mode argument can be in any of the formats specified to the
+.Xr chmod 1
+utility.
+If a symbolic mode is specified, the operation characters
+.Dq +
+and
+.Dq -
+are interpreted relative to an initial mode of
+.Dq a=rwx .
+.It Fl p
+Create intermediate directories as required.
+If this option is not specified, the full path prefix of each
+operand must already exist.
+Intermediate directories are created with permission bits of
+.Li rwxrwxrwx (\&0777)
+as modified by the current umask, plus write and search
+permission for the owner.  Do not consider it an error if the
+argument directory already exists.
+.El
+.Pp
+The user must have write permission in the parent directory.
+.Pp
+.Nm
+exits 0 if successful, and >0 if an error occurred.
+.Sh SEE ALSO
+.Xr chmod 1 ,
+.Xr rmdir 1 ,
+.Xr umask 2
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be
+.St -p1003.2
+compatible.
diff --git a/mkdir/mkdir.c b/mkdir/mkdir.c
new file mode 100644
index 0000000..2dcd1cf
--- /dev/null
+++ b/mkdir/mkdir.c
@@ -0,0 +1,195 @@
+/*	$NetBSD: mkdir.c,v 1.19 1998/07/28 05:31:25 mycroft Exp $	*/
+
+/*
+ * Copyright (c) 1983, 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1983, 1992, 1993\n\
+	The Regents of the University of California.  All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)mkdir.c	8.2 (Berkeley) 1/25/94";
+#else
+__RCSID("$NetBSD: mkdir.c,v 1.19 1998/07/28 05:31:25 mycroft Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int	mkpath __P((char *, mode_t, mode_t));
+void	usage __P((void));
+int	main __P((int, char *[]));
+
+int
+main(argc, argv)
+	int argc;
+	char *argv[];
+{
+	int ch, exitval, pflag;
+	mode_t *set;
+	mode_t mode, dir_mode;
+
+	(void)setlocale(LC_ALL, "");
+
+	/*
+	 * The default file mode is a=rwx (0777) with selected permissions
+	 * removed in accordance with the file mode creation mask.  For
+	 * intermediate path name components, the mode is the default modified
+	 * by u+wx so that the subdirectories can always be created.
+	 */
+	mode = 0777 & ~umask(0);
+	dir_mode = mode | S_IWUSR | S_IXUSR;
+
+	pflag = 0;
+	while ((ch = getopt(argc, argv, "m:p")) != -1)
+		switch(ch) {
+		case 'p':
+			pflag = 1;
+			break;
+		case 'm':
+			if ((set = setmode(optarg)) == NULL)
+				errx(1, "invalid file mode: %s", optarg);
+			mode = getmode(set, S_IRWXU | S_IRWXG | S_IRWXO);
+			break;
+		case '?':
+		default:
+			usage();
+		}
+	argc -= optind;
+	argv += optind;
+
+	if (*argv == NULL)
+		usage();
+	
+	for (exitval = 0; *argv != NULL; ++argv) {
+		char *slash;
+
+		/* Remove trailing slashes, per POSIX. */
+		slash = strrchr(*argv, '\0');
+		while (--slash > *argv && *slash == '/')
+			*slash = '\0';
+
+		if (pflag) {
+			if (mkpath(*argv, mode, dir_mode) < 0)
+				exitval = 1;
+		} else {
+			if (mkdir(*argv, mode) < 0) {
+				warn("%s", *argv);
+				exitval = 1;
+			}
+                	/*
+                         * The mkdir() and umask() calls both honor only the low
+                	 * nine bits, so if you try to set a mode including the
+                    	 * sticky, setuid, setgid bits you lose them. So chmod().
+                         */
+                    	else if (chmod(*argv, mode) == -1) {
+				warn("%s", *argv);
+				exitval = 1;
+                        }
+		}
+	}
+	exit(exitval);
+	/* NOTREACHED */
+}
+
+/*
+ * mkpath -- create directories.  
+ *	path     - path
+ *	mode     - file mode of terminal directory
+ *	dir_mode - file mode of intermediate directories
+ */
+int
+mkpath(path, mode, dir_mode)
+	char *path;
+	mode_t mode;
+	mode_t dir_mode;
+{
+	struct stat sb;
+	char *slash;
+	int done = 0;
+
+	slash = path;
+
+	while (!done) {
+		slash += strspn(slash, "/");
+		slash += strcspn(slash, "/");
+
+		done = (*slash == '\0');
+		*slash = '\0';
+
+		if (stat(path, &sb)) {
+			if (errno != ENOENT
+			    || mkdir(path, done ? mode : dir_mode)) {
+				warn("%s", path);
+				return (-1);
+			}
+                	/*
+                         * The mkdir() and umask() calls both honor only the low
+                	 * nine bits, so if you try to set a mode including the
+                    	 * sticky, setuid, setgid bits you lose them. So chmod().
+                         */
+                    	if (chmod(path, done ? mode : dir_mode) == -1) {
+                            	warn("%s", path);
+                            	return (-1);
+                        }
+		} else if (!S_ISDIR(sb.st_mode)) {
+		        warnx("%s: %s", path, strerror(ENOTDIR));
+			return (-1);
+		}
+		    
+		*slash = '/';
+	}
+
+	return (0);
+}
+
+void
+usage()
+{
+
+	(void)fprintf(stderr, "usage: mkdir [-p] [-m mode] dirname ...\n");
+	exit(1);
+	/* NOTREACHED */
+}
diff --git a/mkfifo/Makefile b/mkfifo/Makefile
new file mode 100644
index 0000000..ed49dbe
--- /dev/null
+++ b/mkfifo/Makefile
@@ -0,0 +1,48 @@
+#
+# Generated by the NeXT Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = mkfifo
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+CFILES = mkfifo.c
+
+OTHERSRCS = Makefile Makefile.preamble Makefile.postamble mkfifo.1
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /usr/bin
+LIBS = 
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+
+
+NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/developer_cmds/Build
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
diff --git a/mkfifo/Makefile.postamble b/mkfifo/Makefile.postamble
new file mode 100644
index 0000000..013b558
--- /dev/null
+++ b/mkfifo/Makefile.postamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
diff --git a/mkfifo/Makefile.preamble b/mkfifo/Makefile.preamble
new file mode 100644
index 0000000..9e10e90
--- /dev/null
+++ b/mkfifo/Makefile.preamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
diff --git a/mkfifo/PB.project b/mkfifo/PB.project
new file mode 100644
index 0000000..b348276
--- /dev/null
+++ b/mkfifo/PB.project
@@ -0,0 +1,25 @@
+{
+    DYNAMIC_CODE_GEN = YES; 
+    FILESTABLE = {
+        FRAMEWORKS = (); 
+        OTHER_LINKED = (mkfifo.c); 
+        OTHER_SOURCES = (Makefile, Makefile.preamble, Makefile.postamble, mkfifo.1); 
+    }; 
+    LANGUAGE = English; 
+    LOCALIZABLE_FILES = {}; 
+    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
+    NEXTSTEP_BUILDDIR = /tmp/developer_cmds/Build; 
+    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
+    NEXTSTEP_INSTALLDIR = /usr/bin; 
+    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
+    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
+    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
+    PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; 
+    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
+    PROJECTNAME = mkfifo; 
+    PROJECTTYPE = Tool; 
+    PROJECTVERSION = 2.8; 
+    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
+    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
+    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
+}
diff --git a/mkfifo/mkfifo.1 b/mkfifo/mkfifo.1
new file mode 100644
index 0000000..f8a0e16
--- /dev/null
+++ b/mkfifo/mkfifo.1
@@ -0,0 +1,91 @@
+.\"	$NetBSD: mkfifo.1,v 1.6 1997/10/19 05:11:52 lukem Exp $
+.\"
+.\" Copyright (c) 1990, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     @(#)mkfifo.1	8.2 (Berkeley) 1/5/94
+.\"
+.Dd January 5, 1994
+.Dt MKFIFO 1
+.Os BSD 4.4
+.Sh NAME
+.Nm mkfifo
+.Nd make fifos
+.Sh SYNOPSIS
+.Nm
+.Op Fl m Ar mode
+.Ar fifo_name  ...
+.Sh DESCRIPTION
+.Nm
+creates the fifos requested, in the order specified,
+using mode
+.Li \&0666 
+modified by the current
+.Xr umask 2 .
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl m
+Set the file permission bits of newly-created directories to
+.Ar mode .
+The mode is specified as in 
+.Xr chmod 1 .
+In symbolic mode strings, the 
+.Dq + 
+and 
+.Dq -
+operators are interpreted relative to an assumed initial mode of 
+.Dq a=rw
+.El
+.Pp
+.Nm
+requires write permission in the parent directory.
+.Pp
+.Nm
+exits 0 if successful, and >0 if an error occurred.
+.Sh SEE ALSO
+.Xr mkdir 1 ,
+.Xr rm 1 ,
+.Xr mkfifo 2 ,
+.Xr mknod 8
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be
+.St -p1003.2-92
+compliant.
+.Sh HISTORY
+.Nm
+command appeared in
+.Bx 4.4 .
diff --git a/mkfifo/mkfifo.c b/mkfifo/mkfifo.c
new file mode 100644
index 0000000..6bd45b0
--- /dev/null
+++ b/mkfifo/mkfifo.c
@@ -0,0 +1,113 @@
+/*	$NetBSD: mkfifo.c,v 1.8 1997/10/19 05:11:54 lukem Exp $	*/
+
+/*
+ * Copyright (c) 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1990, 1993\n\
+	The Regents of the University of California.  All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)mkfifo.c	8.2 (Berkeley) 1/5/94";
+#endif
+__RCSID("$NetBSD: mkfifo.c,v 1.8 1997/10/19 05:11:54 lukem Exp $");
+#endif /* not lint */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <err.h>
+
+int	main __P((int, char **));
+static void usage __P((void));
+
+int
+main(argc, argv)
+	int argc;
+	char *argv[];
+{
+	int ch, exitval;
+	void * set;
+	mode_t mode;
+
+	setlocale (LC_ALL, "");
+
+	/* The default mode is the value of the bitwise inclusive or of
+	   S_IRUSR, S_IWUSR, S_IRGRP, S_IWGRP, S_IROTH, and S_IWOTH
+	   modified by the file creation mask */
+	mode = 0666 & ~umask(0);
+
+	while ((ch = getopt(argc, argv, "m:")) != -1)
+		switch(ch) {
+		case 'm':
+			if (!(set = setmode(optarg))) {
+				errx(1, "invalid file mode.");
+				/* NOTREACHED */
+			}
+			/* In symbolic mode strings, the + and - operators are
+			   interpreted relative to an assumed initial mode of
+			   a=rw. */
+			mode = getmode (set, 0666);
+			break;
+		case '?':
+		default:
+			usage();
+		}
+	argc -= optind;
+	argv += optind;
+	if (argv[0] == NULL)
+		usage();
+
+	for (exitval = 0; *argv; ++argv) {
+		if (mkfifo(*argv, mode) < 0) {
+			warn("%s", *argv);
+			exitval = 1;
+		}
+	}
+	exit(exitval);
+}
+
+void
+usage()
+{
+	(void)fprintf(stderr, "usage: mkfifo [-m mode] fifoname ...\n");
+	exit(1);
+}
diff --git a/mknod/Makefile b/mknod/Makefile
new file mode 100644
index 0000000..b91bcdc
--- /dev/null
+++ b/mknod/Makefile
@@ -0,0 +1,48 @@
+#
+# Generated by the NeXT Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = mknod
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+CFILES = mknod.c
+
+OTHERSRCS = Makefile Makefile.preamble Makefile.postamble mknod.8
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /sbin
+LIBS = 
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+
+
+NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/$(NAME)/Build
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
diff --git a/mknod/Makefile.postamble b/mknod/Makefile.postamble
new file mode 100644
index 0000000..013b558
--- /dev/null
+++ b/mknod/Makefile.postamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
diff --git a/mknod/Makefile.preamble b/mknod/Makefile.preamble
new file mode 100644
index 0000000..9e10e90
--- /dev/null
+++ b/mknod/Makefile.preamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
diff --git a/mknod/PB.project b/mknod/PB.project
new file mode 100644
index 0000000..db5f15a
--- /dev/null
+++ b/mknod/PB.project
@@ -0,0 +1,25 @@
+{
+    DYNAMIC_CODE_GEN = YES; 
+    FILESTABLE = {
+        FRAMEWORKS = (); 
+        OTHER_LINKED = (mknod.c); 
+        OTHER_SOURCES = (Makefile, Makefile.preamble, Makefile.postamble, mknod.8); 
+    }; 
+    LANGUAGE = English; 
+    LOCALIZABLE_FILES = {}; 
+    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
+    NEXTSTEP_BUILDDIR = "/tmp/$(NAME)/Build"; 
+    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
+    NEXTSTEP_INSTALLDIR = /sbin; 
+    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
+    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
+    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
+    PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; 
+    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
+    PROJECTNAME = mknod; 
+    PROJECTTYPE = Tool; 
+    PROJECTVERSION = 2.8; 
+    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
+    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
+    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
+}
diff --git a/mknod/mknod.8 b/mknod/mknod.8
new file mode 100644
index 0000000..7a1517d
--- /dev/null
+++ b/mknod/mknod.8
@@ -0,0 +1,149 @@
+.\"	$NetBSD: mknod.8,v 1.15 1998/09/11 07:20:48 mycroft Exp $
+.\"
+.\" Copyright (c) 1980, 1991, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     @(#)mknod.8	8.2 (Berkeley) 12/11/93
+.\"
+.Dd September 11, 1998
+.Dt MKNOD 8
+.Os NetBSD 1.4
+.Sh NAME
+.Nm mknod
+.Nd make device special file
+.Sh SYNOPSIS
+.Nm
+.Op Fl F Ar format
+.Ar name
+.Op Cm c | Cm b
+.Ar major minor
+.Nm ""
+.Op Fl F Ar format
+.Ar name
+.Op Cm c | Cm b
+.Ar major unit subunit
+.Nm ""
+.Ar name
+.Op Cm c | Cm b
+.Ar number
+.Sh DESCRIPTION
+The
+.Nm
+command creates device special files.
+Normally the shell script
+.Pa /dev/MAKEDEV
+is used to create special files for commonly known devices; it executes
+.Nm
+with the appropriate arguments and can make all the files required for the
+device.
+.Pp
+To make nodes manually, the required arguments are:
+.Pp
+.Bl -tag -width majorx
+.It Ar name
+Device name, for example
+.Dq sd
+for a SCSI disk on an HP300 or a
+.Dq pty
+for pseudo-devices.
+.It Cm b | Cm c
+Type of device. If the
+device is a block type device such as a tape or disk drive which needs
+both cooked and raw special files,
+the type is
+.Cm b .
+All other devices are character type devices, such as terminal
+and pseudo devices, and are type
+.Cm c .
+.It Ar major
+The major device number is an integer number which tells the kernel
+which device driver entry point to use.  To learn what
+major device number to use for a particular device, check the file
+.Pa /dev/MAKEDEV
+to see if the device is known, or check
+the system dependent device configuration file:
+.Bd -filled -offset indent
+.Dq Pa /usr/src/sys/conf/device. Ns Em architecture
+.Ed
+.Pp
+(for example
+.Pa device.hp300 ) .
+.It Ar minor
+The minor device number tells the kernel which one of several similar
+devices the node corresponds to; for example, it may be a specific serial
+port or pty.
+.It Ar unit and subunit
+The unit and subunit numbers select a subset of a device; for example, the
+unit may specify a particular SCSI disk, and the subunit a partition on
+that disk.  (Currently this form of specification is only supported by the
+.Ar bsdos
+format, for compatibility with the
+.Bsx
+.Xr mknod 8 .)
+.El
+.Pp
+Device numbers for different operating systems may be packed in a different
+format.  To create device nodes that may be used by such an operating system
+(e.g. in an exported file system used for netbooting), the
+.Fl F
+option is used.  The following formats are recognized:
+native,
+386bsd,
+4bsd,
+bsdos,
+freebsd,
+hpux,
+isc,
+linux,
+netbsd,
+osf1,
+sco,
+solaris,
+sunos,
+svr3,
+svr4 and
+ultrix.
+.Pp
+Alternatively, a single opaque device number may be specified.
+.Sh SEE ALSO
+.Xr mkfifo 1 ,
+.Xr mkfifo 2 ,
+.Xr mknod 2 ,
+.Xr MAKEDEV 8
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v6 .
+The
+.Fl F
+option appeared in
+.Nx 1.4 .
diff --git a/mknod/mknod.c b/mknod/mknod.c
new file mode 100644
index 0000000..c45abd5
--- /dev/null
+++ b/mknod/mknod.c
@@ -0,0 +1,396 @@
+/*	$NetBSD: mknod.c,v 1.15 1998/09/11 07:22:13 mycroft Exp $	*/
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Charles M. Hannum.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1998 The NetBSD Foundation, Inc.  All rights reserved.\n");
+__RCSID("$NetBSD: mknod.c,v 1.15 1998/09/11 07:22:13 mycroft Exp $");
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int main __P((int, char *[]));
+static void usage __P((void));
+typedef	dev_t pack_t __P((int, u_long []));
+
+
+pack_t pack_native;
+
+dev_t
+pack_native(n, numbers)
+	int n;
+	u_long numbers[];
+{
+	dev_t dev=0; /* Quiet -Wall */
+
+	if (n == 2) {
+		dev = makedev(numbers[0], numbers[1]);
+		if (major(dev) != numbers[0])
+			errx(1, "invalid major number");
+		if (minor(dev) != numbers[1])
+			errx(1, "invalid minor number");
+	} else
+		errx(1, "too many fields for format");
+	return (dev);
+}
+
+
+#define	major_netbsd(x)		((int32_t)((((x) & 0x000fff00) >>  8)))
+#define	minor_netbsd(x)		((int32_t)((((x) & 0xfff00000) >> 12) | \
+					   (((x) & 0x000000ff) >>  0)))
+#define	makedev_netbsd(x,y)	((dev_t)((((x) <<  8) & 0x000fff00) | \
+					 (((y) << 12) & 0xfff00000) | \
+					 (((y) <<  0) & 0x000000ff)))
+
+pack_t pack_netbsd;
+
+dev_t
+pack_netbsd(n, numbers)
+	int n;
+	u_long numbers[];
+{
+	dev_t dev=0; /* Quiet -Wall */
+
+	if (n == 2) {
+		dev = makedev_netbsd(numbers[0], numbers[1]);
+		if (major_netbsd(dev) != numbers[0])
+			errx(1, "invalid major number");
+		if (minor_netbsd(dev) != numbers[1])
+			errx(1, "invalid minor number");
+	} else
+		errx(1, "too many fields for format");
+	return (dev);
+}
+
+
+#define	major_freebsd(x)	((int32_t)(((x) & 0x0000ff00) >> 8))
+#define	minor_freebsd(x)	((int32_t)(((x) & 0xffff00ff) >> 0))
+#define	makedev_freebsd(x,y)	((dev_t)((((x) << 8) & 0x0000ff00) | \
+					 (((y) << 0) & 0xffff00ff)))
+
+pack_t pack_freebsd;
+
+dev_t
+pack_freebsd(n, numbers)
+	int n;
+	u_long numbers[];
+{
+	dev_t dev=0; /* Quiet -Wall */
+
+	if (n == 2) {
+		dev = makedev_freebsd(numbers[0], numbers[1]);
+		if (major_freebsd(dev) != numbers[0])
+			errx(1, "invalid major number");
+		if (minor_freebsd(dev) != numbers[1])
+			errx(1, "invalid minor number");
+	} else
+		errx(1, "too many fields for format");
+	return (dev);
+}
+
+
+#define	major_8_8(x)		((int32_t)(((x) & 0x0000ff00) >> 8))
+#define	minor_8_8(x)		((int32_t)(((x) & 0x000000ff) >> 0))
+#define	makedev_8_8(x,y)	((dev_t)((((x) << 8) & 0x0000ff00) | \
+					 (((y) << 0) & 0x000000ff)))
+
+pack_t pack_8_8;
+
+dev_t
+pack_8_8(n, numbers)
+	int n;
+	u_long numbers[];
+{
+	dev_t dev=0; /* Quiet -Wall */
+
+	if (n == 2) {
+		dev = makedev_8_8(numbers[0], numbers[1]);
+		if (major_8_8(dev) != numbers[0])
+			errx(1, "invalid major number");
+		if (minor_8_8(dev) != numbers[1])
+			errx(1, "invalid minor number");
+	} else
+		errx(1, "too many fields for format");
+	return (dev);
+}
+
+
+#define	major_12_20(x)		((int32_t)(((x) & 0xfff00000) >> 20))
+#define	minor_12_20(x)		((int32_t)(((x) & 0x000fffff) >>  0))
+#define	makedev_12_20(x,y)	((dev_t)((((x) << 20) & 0xfff00000) | \
+					 (((y) <<  0) & 0x000fffff)))
+
+pack_t pack_12_20;
+
+dev_t
+pack_12_20(n, numbers)
+	int n;
+	u_long numbers[];
+{
+	dev_t dev=0; /* Quiet -Wall */
+
+	if (n == 2) {
+		dev = makedev_12_20(numbers[0], numbers[1]);
+		if (major_12_20(dev) != numbers[0])
+			errx(1, "invalid major number");
+		if (minor_12_20(dev) != numbers[1])
+			errx(1, "invalid minor number");
+	} else
+		errx(1, "too many fields for format");
+	return (dev);
+}
+
+
+#define	major_14_18(x)		((int32_t)(((x) & 0xfffc0000) >> 18))
+#define	minor_14_18(x)		((int32_t)(((x) & 0x0003ffff) >>  0))
+#define	makedev_14_18(x,y)	((dev_t)((((x) << 18) & 0xfffc0000) | \
+					 (((y) <<  0) & 0x0003ffff)))
+
+pack_t pack_14_18;
+
+dev_t
+pack_14_18(n, numbers)
+	int n;
+	u_long numbers[];
+{
+	dev_t dev=0; /* Quiet -Wall */
+
+	if (n == 2) {
+		dev = makedev_14_18(numbers[0], numbers[1]);
+		if (major_14_18(dev) != numbers[0])
+			errx(1, "invalid major number");
+		if (minor_14_18(dev) != numbers[1])
+			errx(1, "invalid minor number");
+	} else
+		errx(1, "too many fields for format");
+	return (dev);
+}
+
+
+#define	major_8_24(x)		((int32_t)(((x) & 0xff000000) >> 24))
+#define	minor_8_24(x)		((int32_t)(((x) & 0x00ffffff) >>  0))
+#define	makedev_8_24(x,y)	((dev_t)((((x) << 24) & 0xff000000) | \
+					 (((y) <<  0) & 0x00ffffff)))
+
+pack_t pack_8_24;
+
+dev_t
+pack_8_24(n, numbers)
+	int n;
+	u_long numbers[];
+{
+	dev_t dev=0; /* Quiet -Wall */
+
+	if (n == 2) {
+		dev = makedev_8_24(numbers[0], numbers[1]);
+		if (major_8_24(dev) != numbers[0])
+			errx(1, "invalid major number");
+		if (minor_8_24(dev) != numbers[1])
+			errx(1, "invalid minor number");
+	} else
+		errx(1, "too many fields for format");
+	return (dev);
+}
+
+
+#define	major_12_12_8(x)	((int32_t)(((x) & 0xfff00000) >> 20))
+#define	unit_12_12_8(x)		((int32_t)(((x) & 0x000fff00) >>  8))
+#define	subunit_12_12_8(x)	((int32_t)(((x) & 0x000000ff) >>  0))
+#define	makedev_12_12_8(x,y,z)	((dev_t)((((x) << 20) & 0xfff00000) | \
+					 (((y) <<  8) & 0x000fff00) | \
+					 (((z) <<  0) & 0x000000ff)))
+
+pack_t pack_bsdos;
+
+dev_t
+pack_bsdos(n, numbers)
+	int n;
+	u_long numbers[];
+{
+	dev_t dev=0; /* Quiet -Wall */
+
+	if (n == 2) {
+		dev = makedev_12_20(numbers[0], numbers[1]);
+		if (major_12_20(dev) != numbers[0])
+			errx(1, "invalid major number");
+		if (minor_12_20(dev) != numbers[1])
+			errx(1, "invalid minor number");
+	} else if (n == 3) {
+		dev = makedev_12_12_8(numbers[0], numbers[1], numbers[2]);
+		if (major_12_12_8(dev) != numbers[0])
+			errx(1, "invalid major number");
+		if (unit_12_12_8(dev) != numbers[1])
+			errx(1, "invalid unit number");
+		if (subunit_12_12_8(dev) != numbers[2])
+			errx(1, "invalid subunit number");
+	} else
+		errx(1, "too many fields for format");
+	return (dev);
+}
+
+
+struct format {
+	char	*name;
+	pack_t	*pack;
+} formats[] = {
+	{"386bsd",  pack_8_8},
+	{"4bsd",    pack_8_8},
+	{"bsdos",   pack_bsdos},
+	{"freebsd", pack_freebsd},
+	{"hpux",    pack_8_24},
+	{"isc",     pack_8_8},
+	{"linux",   pack_8_8},
+	{"native",  pack_native},
+	{"netbsd",  pack_netbsd},
+	{"osf1",    pack_12_20},
+	{"sco",     pack_8_8},
+	{"solaris", pack_14_18},
+	{"sunos",   pack_8_8},
+	{"svr3",    pack_8_8},
+	{"svr4",    pack_14_18},
+	{"ultrix",  pack_8_8},
+};
+
+int compare_format __P((const void *, const void *));
+
+int
+compare_format(key, element)
+	const void *key;
+	const void *element;
+{
+	const char *name;
+	const struct format *format;
+
+	name = key;
+	format = element;
+
+	return (strcmp(name, format->name));
+}
+
+
+int
+main(argc, argv)
+	int argc;
+	char **argv;
+{
+	char *name;
+	mode_t mode;
+	dev_t dev;
+	pack_t *pack;
+	u_long numbers[8];
+	struct format *format;
+	char *p;
+	int n;
+	int ch;
+
+	pack = pack_native;
+
+	while ((ch = getopt(argc, argv, "F:")) != -1) {
+		switch (ch) {
+		case 'F':
+			format = bsearch(optarg, formats,
+			    sizeof(formats)/sizeof(formats[0]),
+			    sizeof(formats[0]), compare_format);
+			if (format == 0)
+				errx(1, "invalid format: %s", optarg);
+			pack = format->pack;
+			break;
+
+		default:
+		case '?':
+			usage();
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	if (argc < 3 || argc > 10)
+		usage();
+
+	name = *argv;
+	argc--;
+	argv++;
+
+	mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
+	if (*argv[0] == 'c')
+		mode |= S_IFCHR;
+	else if (*argv[0] == 'b')
+		mode |= S_IFBLK;
+	else
+		errx(1, "node type must be 'b' or 'c'.");
+	argc--;
+	argv++;
+
+	for (n = 0; n < argc; n++) {
+		numbers[n] = strtoul(argv[n], &p, 0);
+		if ((p && *p != '\0') || (numbers[n] == ULONG_MAX && errno == ERANGE))
+			errx(1, "invalid number: %s", argv[n]);
+	}
+
+	if (argc == 1)
+		dev = numbers[0];
+	else
+		dev = (*pack)(argc, numbers);
+
+#if 0
+	printf("name: %s\nmode: %05o\ndev:  %08x\n", name, mode, dev);
+#else
+	if (mknod(name, mode, dev) < 0)
+		err(1, "%s", argv[0]);
+#endif
+
+	exit(0);
+}
+
+void
+usage()
+{
+
+	fprintf(stderr, "usage: mknod [-F format] name [b | c] major minor\n");
+	fprintf(stderr, "       mknod [-F format] name [b | c] major unit subunit\n");
+	fprintf(stderr, "       mknod name [b | c] number\n");
+	exit(1);
+}
diff --git a/mtree/Makefile b/mtree/Makefile
new file mode 100644
index 0000000..01d374a
--- /dev/null
+++ b/mtree/Makefile
@@ -0,0 +1,50 @@
+#
+# Generated by the NeXT Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = mtree
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+HFILES = extern.h mtree.h
+
+CFILES = compare.c create.c misc.c mtree.c spec.c verify.c
+
+OTHERSRCS = Makefile Makefile.preamble Makefile.postamble mtree.8
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /usr/sbin
+LIBS = 
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+
+
+NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/$(NAME)/Build
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
diff --git a/mtree/Makefile.postamble b/mtree/Makefile.postamble
new file mode 100644
index 0000000..013b558
--- /dev/null
+++ b/mtree/Makefile.postamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
diff --git a/mtree/Makefile.preamble b/mtree/Makefile.preamble
new file mode 100644
index 0000000..65868da
--- /dev/null
+++ b/mtree/Makefile.preamble
@@ -0,0 +1,5 @@
+vpath crc.c ../cksum
+
+CFILES += crc.c
+
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
diff --git a/mtree/PB.project b/mtree/PB.project
new file mode 100644
index 0000000..22cc839
--- /dev/null
+++ b/mtree/PB.project
@@ -0,0 +1,26 @@
+{
+    DYNAMIC_CODE_GEN = YES; 
+    FILESTABLE = {
+        FRAMEWORKS = (); 
+        H_FILES = (extern.h, mtree.h); 
+        OTHER_LINKED = (compare.c, create.c, misc.c, mtree.c, spec.c, verify.c); 
+        OTHER_SOURCES = (Makefile, Makefile.preamble, Makefile.postamble, mtree.8); 
+    }; 
+    LANGUAGE = English; 
+    LOCALIZABLE_FILES = {}; 
+    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
+    NEXTSTEP_BUILDDIR = "/tmp/$(NAME)/Build"; 
+    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
+    NEXTSTEP_INSTALLDIR = /usr/sbin; 
+    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
+    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
+    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
+    PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; 
+    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
+    PROJECTNAME = mtree; 
+    PROJECTTYPE = Tool; 
+    PROJECTVERSION = 2.8; 
+    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
+    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
+    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
+}
diff --git a/mtree/compare.c b/mtree/compare.c
new file mode 100644
index 0000000..596f9de
--- /dev/null
+++ b/mtree/compare.c
@@ -0,0 +1,298 @@
+/*	$NetBSD: compare.c,v 1.15 1998/08/27 18:03:45 ross Exp $	*/
+
+/*-
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)compare.c	8.1 (Berkeley) 6/6/93";
+#else
+__RCSID("$NetBSD: compare.c,v 1.15 1998/08/27 18:03:45 ross Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <errno.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include "mtree.h"
+#include "extern.h"
+
+extern int tflag, uflag;
+
+static char *ftype __P((u_int));
+
+#define	INDENTNAMELEN	8
+#define	LABEL \
+	if (!label++) { \
+		len = printf("%s: ", RP(p)); \
+		if (len > INDENTNAMELEN) { \
+			tab = "\t"; \
+			(void)printf("\n"); \
+		} else { \
+			tab = ""; \
+			(void)printf("%*s", INDENTNAMELEN - (int)len, ""); \
+		} \
+	}
+
+int
+compare(name, s, p)
+	char *name;
+	NODE *s;
+	FTSENT *p;
+{
+	u_int32_t len, val;
+	int fd, label;
+	char *cp, *tab;
+
+	tab = NULL;
+	label = 0;
+	switch(s->type) {
+	case F_BLOCK:
+		if (!S_ISBLK(p->fts_statp->st_mode))
+			goto typeerr;
+		break;
+	case F_CHAR:
+		if (!S_ISCHR(p->fts_statp->st_mode))
+			goto typeerr;
+		break;
+	case F_DIR:
+		if (!S_ISDIR(p->fts_statp->st_mode))
+			goto typeerr;
+		break;
+	case F_FIFO:
+		if (!S_ISFIFO(p->fts_statp->st_mode))
+			goto typeerr;
+		break;
+	case F_FILE:
+		if (!S_ISREG(p->fts_statp->st_mode))
+			goto typeerr;
+		break;
+	case F_LINK:
+		if (!S_ISLNK(p->fts_statp->st_mode))
+			goto typeerr;
+		break;
+	case F_SOCK:
+		if (!S_ISSOCK(p->fts_statp->st_mode)) {
+typeerr:		LABEL;
+			(void)printf("\ttype (%s, %s)\n",
+			    ftype(s->type), inotype(p->fts_statp->st_mode));
+		}
+		break;
+	}
+	/* Set the uid/gid first, then set the mode. */
+	if (s->flags & (F_UID | F_UNAME) && s->st_uid != p->fts_statp->st_uid) {
+		LABEL;
+		(void)printf("%suser (%u, %u",
+		    tab, s->st_uid, p->fts_statp->st_uid);
+		if (uflag)
+			if (chown(p->fts_accpath, s->st_uid, -1))
+				(void)printf(", not modified: %s)\n",
+				    strerror(errno));
+			else
+				(void)printf(", modified)\n");
+		else
+			(void)printf(")\n");
+		tab = "\t";
+	}
+	if (s->flags & (F_GID | F_GNAME) && s->st_gid != p->fts_statp->st_gid) {
+		LABEL;
+		(void)printf("%sgid (%u, %u",
+		    tab, s->st_gid, p->fts_statp->st_gid);
+		if (uflag)
+			if (chown(p->fts_accpath, -1, s->st_gid))
+				(void)printf(", not modified: %s)\n",
+				    strerror(errno));
+			else
+				(void)printf(", modified)\n");
+		else
+			(void)printf(")\n");
+		tab = "\t";
+	}
+	if (s->flags & F_MODE &&
+	    s->st_mode != (p->fts_statp->st_mode & MBITS)) {
+		LABEL;
+		(void)printf("%spermissions (%#o, %#o",
+		    tab, s->st_mode, p->fts_statp->st_mode & MBITS);
+		if (uflag)
+			if (chmod(p->fts_accpath, s->st_mode))
+				(void)printf(", not modified: %s)\n",
+				    strerror(errno));
+			else
+				(void)printf(", modified)\n");
+		else
+			(void)printf(")\n");
+		tab = "\t";
+	}
+	if (s->flags & F_NLINK && s->type != F_DIR &&
+	    s->st_nlink != p->fts_statp->st_nlink) {
+		LABEL;
+		(void)printf("%slink count (%u, %u)\n",
+		    tab, s->st_nlink, p->fts_statp->st_nlink);
+		tab = "\t";
+	}
+	if (s->flags & F_SIZE && s->st_size != p->fts_statp->st_size) {
+		LABEL;
+		(void)printf("%ssize (%qd, %qd)\n",
+		    tab, (long long)s->st_size,
+		    (long long)p->fts_statp->st_size);
+		tab = "\t";
+	}
+	/*
+	 * XXX
+	 * Since utimes(2) only takes a timeval, there's no point in
+	 * comparing the low bits of the timespec nanosecond field.  This
+	 * will only result in mismatches that we can never fix.
+	 *
+	 * Doesn't display microsecond differences.
+	 */
+	if (s->flags & F_TIME) {
+		struct timeval tv[2];
+
+		TIMESPEC_TO_TIMEVAL(&tv[0], &s->st_mtimespec);
+		TIMESPEC_TO_TIMEVAL(&tv[1], &p->fts_statp->st_mtimespec);
+		if (tv[0].tv_sec != tv[1].tv_sec ||
+		    tv[0].tv_usec != tv[1].tv_usec) {
+			LABEL;
+			(void)printf("%smodification time (%.24s, ",
+			    tab, ctime(&s->st_mtimespec.tv_sec));
+			(void)printf("%.24s",
+			    ctime(&p->fts_statp->st_mtimespec.tv_sec));
+			if (tflag) {
+				tv[1] = tv[0];
+				if (utimes(p->fts_accpath, tv))
+					(void)printf(", not modified: %s)\n",
+					    strerror(errno));
+				else
+					(void)printf(", modified)\n");
+			} else
+				(void)printf(")\n");
+			tab = "\t";
+		}
+	}
+	if (s->flags & F_CKSUM) {
+		if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0) {
+			LABEL;
+			(void)printf("%scksum: %s: %s\n",
+			    tab, p->fts_accpath, strerror(errno));
+			tab = "\t";
+		} else if (crc(fd, &val, &len)) {
+			(void)close(fd);
+			LABEL;
+			(void)printf("%scksum: %s: %s\n",
+			    tab, p->fts_accpath, strerror(errno));
+			tab = "\t";
+		} else {
+			(void)close(fd);
+			if (s->cksum != val) {
+				LABEL;
+				(void)printf("%scksum (%lu, %lu)\n", 
+				    tab, s->cksum, (unsigned long)val);
+			}
+			tab = "\t";
+		}
+	}
+	if (s->flags & F_SLINK && strcmp(cp = rlink(name), s->slink)) {
+		LABEL;
+		(void)printf("%slink ref (%s, %s)\n", tab, cp, s->slink);
+	}
+	return (label);
+}
+
+char *
+inotype(type)
+	u_int type;
+{
+	switch(type & S_IFMT) {
+	case S_IFBLK:
+		return ("block");
+	case S_IFCHR:
+		return ("char");
+	case S_IFDIR:
+		return ("dir");
+	case S_IFIFO:
+		return ("fifo");
+	case S_IFREG:
+		return ("file");
+	case S_IFLNK:
+		return ("link");
+	case S_IFSOCK:
+		return ("socket");
+	default:
+		return ("unknown");
+	}
+	/* NOTREACHED */
+}
+
+static char *
+ftype(type)
+	u_int type;
+{
+	switch(type) {
+	case F_BLOCK:
+		return ("block");
+	case F_CHAR:
+		return ("char");
+	case F_DIR:
+		return ("dir");
+	case F_FIFO:
+		return ("fifo");
+	case F_FILE:
+		return ("file");
+	case F_LINK:
+		return ("link");
+	case F_SOCK:
+		return ("socket");
+	default:
+		return ("unknown");
+	}
+	/* NOTREACHED */
+}
+
+char *
+rlink(name)
+	char *name;
+{
+	static char lbuf[MAXPATHLEN];
+	int len;
+
+	if ((len = readlink(name, lbuf, sizeof(lbuf))) == -1)
+		mtree_err("%s: %s", name, strerror(errno));
+	lbuf[len] = '\0';
+	return (lbuf);
+}
diff --git a/mtree/create.c b/mtree/create.c
new file mode 100644
index 0000000..7487de1
--- /dev/null
+++ b/mtree/create.c
@@ -0,0 +1,306 @@
+/*	$NetBSD: create.c,v 1.16 1998/08/30 03:20:09 nathanw Exp $	*/
+
+/*-
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)create.c	8.1 (Berkeley) 6/6/93";
+#else
+__RCSID("$NetBSD: create.c,v 1.16 1998/08/30 03:20:09 nathanw Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include "mtree.h"
+#include "extern.h"
+
+#define	INDENTNAMELEN	15
+#define	MAXLINELEN	80
+
+extern int crc_total, ftsoptions;
+extern int dflag, sflag;
+extern u_short keys;
+extern char fullpath[MAXPATHLEN];
+
+static gid_t gid;
+static uid_t uid;
+static mode_t mode;
+
+static int	dsort __P((const FTSENT **, const FTSENT **));
+static void	output __P((int *, const char *, ...));
+static int	statd __P((FTS *, FTSENT *, uid_t *, gid_t *, mode_t *));
+static void	statf __P((FTSENT *));
+
+void
+cwalk()
+{
+	FTS *t;
+	FTSENT *p;
+	time_t clock;
+	char *argv[2], host[MAXHOSTNAMELEN + 1];
+
+	(void)time(&clock);
+	(void)gethostname(host, sizeof(host));
+	host[sizeof(host) - 1] = '\0';
+	(void)printf(
+	    "#\t   user: %s\n#\tmachine: %s\n#\t   tree: %s\n#\t   date: %s",
+	    getlogin(), host, fullpath, ctime(&clock));
+
+	argv[0] = ".";
+	argv[1] = NULL;
+	if ((t = fts_open(argv, ftsoptions, dsort)) == NULL)
+		mtree_err("fts_open: %s", strerror(errno));
+	while ((p = fts_read(t)) != NULL)
+		switch(p->fts_info) {
+		case FTS_D:
+			(void)printf("\n# %s\n", p->fts_path);
+			statd(t, p, &uid, &gid, &mode);
+			statf(p);
+			break;
+		case FTS_DP:
+			if (p->fts_level > 0)
+				(void)printf("# %s\n..\n\n", p->fts_path);
+			break;
+		case FTS_DNR:
+		case FTS_ERR:
+		case FTS_NS:
+			(void)fprintf(stderr,
+			    "mtree: %s: %s\n", p->fts_path, strerror(errno));
+			break;
+		default:
+			if (!dflag)
+				statf(p);
+			break;
+			
+		}
+	(void)fts_close(t);
+	if (sflag && keys & F_CKSUM)
+		(void)fprintf(stderr,
+		    "mtree: %s checksum: %u\n", fullpath, crc_total);
+}
+
+static void
+statf(p)
+	FTSENT *p;
+{
+	struct group *gr;
+	struct passwd *pw;
+	u_int32_t len, val;
+	int fd, indent;
+
+	if (S_ISDIR(p->fts_statp->st_mode))
+		indent = printf("%s", p->fts_name); 
+	else
+		indent = printf("    %s", p->fts_name);
+
+	if (indent > INDENTNAMELEN)
+		indent = MAXLINELEN;
+	else
+		indent += printf("%*s", INDENTNAMELEN - indent, "");
+
+	if (!S_ISREG(p->fts_statp->st_mode))
+		output(&indent, "type=%s", inotype(p->fts_statp->st_mode));
+	if (keys & (F_UID | F_UNAME) && p->fts_statp->st_uid != uid) {
+		if (keys & F_UNAME && (pw = getpwuid(p->fts_statp->st_uid)))
+			output(&indent, "uname=%s", pw->pw_name);
+		else /* if (keys & F_UID) */
+			output(&indent, "uid=%u", p->fts_statp->st_uid);
+	}
+	if (keys & (F_GID | F_GNAME) && p->fts_statp->st_gid != gid) {
+		if (keys & F_GNAME && (gr = getgrgid(p->fts_statp->st_gid)))
+			output(&indent, "gname=%s", gr->gr_name);
+		else /* if (keys & F_GID) */
+			output(&indent, "gid=%u", p->fts_statp->st_gid);
+	}
+	if (keys & F_MODE && (p->fts_statp->st_mode & MBITS) != mode)
+		output(&indent, "mode=%#o", p->fts_statp->st_mode & MBITS);
+	if (keys & F_NLINK && p->fts_statp->st_nlink != 1)
+		output(&indent, "nlink=%u", p->fts_statp->st_nlink);
+	if (keys & F_SIZE && S_ISREG(p->fts_statp->st_mode))
+		output(&indent, "size=%qd", p->fts_statp->st_size);
+	if (keys & F_TIME)
+		output(&indent, "time=%ld.%ld",
+		    p->fts_statp->st_mtimespec.tv_sec,
+		    p->fts_statp->st_mtimespec.tv_nsec);
+	if (keys & F_CKSUM && S_ISREG(p->fts_statp->st_mode)) {
+		if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0 ||
+		    crc(fd, &val, &len))
+			mtree_err("%s: %s", p->fts_accpath, strerror(errno));
+		(void)close(fd);
+		output(&indent, "cksum=%lu", val);
+	}
+	if (keys & F_SLINK &&
+	    (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE))
+		output(&indent, "link=%s", rlink(p->fts_accpath));
+	(void)putchar('\n');
+}
+
+#define	MAXGID	5000
+#define	MAXUID	5000
+#define	MAXMODE	MBITS + 1
+
+static int
+statd(t, parent, puid, pgid, pmode)
+	FTS *t;
+	FTSENT *parent;
+	uid_t *puid;
+	gid_t *pgid;
+	mode_t *pmode;
+{
+	FTSENT *p;
+	gid_t sgid;
+	uid_t suid;
+	mode_t smode;
+	struct group *gr;
+	struct passwd *pw;
+	gid_t savegid;
+	uid_t saveuid;
+	mode_t savemode;
+	u_short maxgid, maxuid, maxmode, g[MAXGID], u[MAXUID], m[MAXMODE];
+
+	savegid = 0;
+	saveuid = 0;
+	savemode = 0;
+	if ((p = fts_children(t, 0)) == NULL) {
+		if (errno)
+			mtree_err("%s: %s", RP(parent), strerror(errno));
+		return (1);
+	}
+
+	memset(g, 0, sizeof(g));
+	memset(u, 0, sizeof(u));
+	memset(m, 0, sizeof(m));
+
+	maxuid = maxgid = maxmode = 0;
+	for (; p; p = p->fts_link) {
+		smode = p->fts_statp->st_mode & MBITS;
+		if (smode < MAXMODE && ++m[smode] > maxmode) {
+			savemode = smode;
+			maxmode = m[smode];
+		}
+		sgid = p->fts_statp->st_gid;
+		if (sgid < MAXGID && ++g[sgid] > maxgid) {
+			savegid = sgid;
+			maxgid = g[sgid];
+		}
+		suid = p->fts_statp->st_uid;
+		if (suid < MAXUID && ++u[suid] > maxuid) {
+			saveuid = suid;
+			maxuid = u[suid];
+		}
+	}
+	(void)printf("/set type=file");
+	if (keys & F_GID)
+		(void)printf(" gid=%u", savegid);
+	if (keys & F_GNAME) {
+		if ((gr = getgrgid(savegid)) != NULL)
+			(void)printf(" gname=%s", gr->gr_name);
+		else
+			(void)printf(" gid=%u", savegid);
+	}
+	if (keys & F_UNAME) {
+		if ((pw = getpwuid(saveuid)) != NULL)
+			(void)printf(" uname=%s", pw->pw_name);
+		else
+			(void)printf(" uid=%u", saveuid);
+	}
+	if (keys & F_UID)
+		(void)printf(" uid=%u", saveuid);
+	if (keys & F_MODE)
+		(void)printf(" mode=%#o", savemode);
+	if (keys & F_NLINK)
+		(void)printf(" nlink=1");
+	(void)printf("\n");
+	*puid = saveuid;
+	*pgid = savegid;
+	*pmode = savemode;
+	return (0);
+}
+
+static int
+dsort(a, b)
+	const FTSENT **a, **b;
+{
+	if (S_ISDIR((*a)->fts_statp->st_mode)) {
+		if (!S_ISDIR((*b)->fts_statp->st_mode))
+			return (1);
+	} else if (S_ISDIR((*b)->fts_statp->st_mode))
+		return (-1);
+	return (strcmp((*a)->fts_name, (*b)->fts_name));
+}
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#if __STDC__
+output(int *offset, const char *fmt, ...)
+#else
+output(offset, fmt, va_alist)
+	int *offset;
+	char *fmt;
+        va_dcl
+#endif
+{
+	va_list ap;
+	char buf[1024];
+#if __STDC__
+	va_start(ap, fmt);
+#else
+	va_start(ap);
+#endif
+	(void)vsnprintf(buf, sizeof(buf), fmt, ap);
+	va_end(ap);
+
+	if (*offset + strlen(buf) > MAXLINELEN - 3) {
+		(void)printf(" \\\n%*s", INDENTNAMELEN, "");
+		*offset = INDENTNAMELEN;
+	}
+	*offset += printf(" %s", buf) + 1;
+}
diff --git a/mtree/extern.h b/mtree/extern.h
new file mode 100644
index 0000000..4b09f62
--- /dev/null
+++ b/mtree/extern.h
@@ -0,0 +1,52 @@
+/*	$NetBSD: extern.h,v 1.3 1995/03/07 21:12:07 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)extern.h	8.1 (Berkeley) 6/6/93
+ */
+
+#include "mtree.h"
+
+#ifdef __APPLE__
+#include <fts.h>
+#endif
+
+int	 compare __P((char *, NODE *, FTSENT *));
+int	 crc __P((int, u_int32_t *, u_int32_t *));
+void	 cwalk __P((void));
+void	 mtree_err __P((const char *, ...));
+char	*inotype __P((u_int));
+u_int	 parsekey __P((char *, int *));
+char	*rlink __P((char *));
+NODE	*spec __P((void));
+int	 verify __P((void));
diff --git a/mtree/misc.c b/mtree/misc.c
new file mode 100644
index 0000000..4eeceef
--- /dev/null
+++ b/mtree/misc.c
@@ -0,0 +1,134 @@
+/*	$NetBSD: misc.c,v 1.5 1997/10/17 11:46:40 lukem Exp $	*/
+
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)misc.c	8.1 (Berkeley) 6/6/93
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: misc.c,v 1.5 1997/10/17 11:46:40 lukem Exp $");
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fts.h>
+#include <stdio.h>
+#include "mtree.h"
+#include "extern.h"
+
+extern int lineno;
+
+typedef struct _key {
+	char *name;			/* key name */
+	u_int val;			/* value */
+
+#define	NEEDVALUE	0x01
+	u_int flags;
+} KEY;
+
+/* NB: the following table must be sorted lexically. */
+static KEY keylist[] = {
+	{"cksum",	F_CKSUM,	NEEDVALUE},
+	{"gid",		F_GID,		NEEDVALUE},
+	{"gname",	F_GNAME,	NEEDVALUE},
+	{"ignore",	F_IGN,		0},
+	{"link",	F_SLINK,	NEEDVALUE},
+	{"mode",	F_MODE,		NEEDVALUE},
+	{"nlink",	F_NLINK,	NEEDVALUE},
+	{"optional",	F_OPT,		0},
+	{"size",	F_SIZE,		NEEDVALUE},
+	{"time",	F_TIME,		NEEDVALUE},
+	{"type",	F_TYPE,		NEEDVALUE},
+	{"uid",		F_UID,		NEEDVALUE},
+	{"uname",	F_UNAME,	NEEDVALUE}
+};
+
+int keycompare __P((const void *, const void *));
+
+u_int
+parsekey(name, needvaluep)
+	char *name;
+	int *needvaluep;
+{
+	KEY *k, tmp;
+
+	tmp.name = name;
+	k = (KEY *)bsearch(&tmp, keylist, sizeof(keylist) / sizeof(KEY),
+	    sizeof(KEY), keycompare);
+	if (k == NULL)
+		mtree_err("unknown keyword %s", name);
+
+	if (needvaluep)
+		*needvaluep = k->flags & NEEDVALUE ? 1 : 0;
+	return (k->val);
+}
+
+int
+keycompare(a, b)
+	const void *a, *b;
+{
+	return (strcmp(((KEY *)a)->name, ((KEY *)b)->name));
+}
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#if __STDC__
+mtree_err(const char *fmt, ...)
+#else
+mtree_err(fmt, va_alist)
+	char *fmt;
+        va_dcl
+#endif
+{
+	va_list ap;
+#if __STDC__
+	va_start(ap, fmt);
+#else
+	va_start(ap);
+#endif
+	(void)fprintf(stderr, "mtree: ");
+	(void)vfprintf(stderr, fmt, ap);
+	va_end(ap);
+	(void)fprintf(stderr, "\n");
+	if (lineno)
+		(void)fprintf(stderr,
+		    "mtree: failed at line %d of the specification\n", lineno);
+	exit(1);
+	/* NOTREACHED */
+}
diff --git a/mtree/mtree.8 b/mtree/mtree.8
new file mode 100644
index 0000000..cb89812
--- /dev/null
+++ b/mtree/mtree.8
@@ -0,0 +1,261 @@
+.\"	$NetBSD: mtree.8,v 1.7 1997/10/17 11:46:46 lukem Exp $
+.\"
+.\" Copyright (c) 1989, 1990, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     @(#)mtree.8	8.2 (Berkeley) 12/11/93
+.\"
+.Dd December 11, 1993
+.Dt MTREE 8
+.Os
+.Sh NAME
+.Nm mtree
+.Nd map a directory hierarchy
+.Sh SYNOPSIS
+.Nm
+.Op Fl cderux
+.Op Fl f Ar spec
+.Op Fl K Ar keywords
+.Op Fl k Ar keywords
+.Op Fl p Ar path
+.Op Fl s Ar seed
+.Sh DESCRIPTION
+The utility
+.Nm
+compares the file hierarchy rooted in the current directory against a
+specification read from the standard input.
+Messages are written to the standard output for any files whose
+characteristics do not match the specification, or which are
+missing from either the file hierarchy or the specification.
+.Pp
+The options are as follows:
+.Bl -tag -width flag
+.It Fl c
+Print a specification for the file hierarchy to the standard output.
+.It Fl d
+Ignore everything except directory type files.
+.It Fl e
+Don't complain about files that are in the file hierarchy, but not in the
+specification.
+.It Fl f
+Read the specification from
+.Ar file  ,
+instead of from the standard input.
+.It Fl K
+Add the specified (whitespace or comma separated) keywords to the current
+set of keywords.
+.It Fl k
+Use the ``type'' keyword plus the specified (whitespace or comma separated)
+keywords instead of the current set of keywords.
+.It Fl p
+Use the file hierarchy rooted in
+.Ar path  ,
+instead of the current directory.
+.It Fl r
+Remove any files in the file hierarchy that are not described in the
+specification.
+.It Fl s
+Display a single checksum to the standard error output that represents all
+of the files for which the keyword
+.Cm cksum
+was specified.
+The checksum is seeded with the specified value.
+.It Fl U
+Modify the owner, group, and permissions of existing files to match
+the specification and create any missing directories.
+User, group, and permissions must all be specified for missing directories
+to be created.
+Exit with a status of 0 on success, 1 if any error occurred;
+a mismatch is not considered to be an error if it was corrected.
+.It Fl u
+Same as
+.Fl U
+except a status of 2 is returned if the file hierarchy did not match 
+the specification.
+.It Fl x
+Don't descend below mount points in the file hierarchy.
+.El
+.Pp
+Specifications are mostly composed of ``keywords'', i.e. strings that
+that specify values relating to files.
+No keywords have default values, and if a keyword has no value set, no
+checks based on it are performed.
+.Pp
+Currently supported keywords are as follows:
+.Bl -tag -width Cm
+.It Cm cksum
+The checksum of the file using the default algorithm specified by
+the
+.Xr cksum 1
+utility.
+.It Cm ignore
+Ignore any file hierarchy below this file.
+.It Cm gid
+The file group as a numeric value.
+.It Cm gname
+The file group as a symbolic name.
+.It Cm link
+The file the symbolic link is expected to reference.
+.It Cm mode
+The current file's permissions as a numeric (octal) or symbolic
+value.
+.It Cm nlink
+The number of hard links the file is expected to have.
+.It Cm optional
+The file is optional; don't complain about the file if it's
+not in the file hierarchy.
+.It Cm uid
+The file owner as a numeric value.
+.It Cm uname
+The file owner as a symbolic name.
+.It Cm size
+The size, in bytes, of the file.
+.It Cm time
+The last modification time of the file.
+.It Cm type
+The type of the file; may be set to any one of the following:
+.sp
+.Bl -tag -width Cm -compact
+.It Cm block
+block special device
+.It Cm char
+character special device
+.It Cm dir
+directory
+.It Cm fifo
+fifo
+.It Cm file
+regular file
+.It Cm link
+symbolic link
+.It Cm socket
+socket
+.El
+.El
+.Pp
+The default set of keywords are
+.Cm gid ,
+.Cm link ,
+.Cm mode ,
+.Cm nlink ,
+.Cm size ,
+.Cm time ,
+and
+.Cm uid .
+.Pp
+There are four types of lines in a specification.
+.Pp
+The first type of line sets a global value for a keyword, and consists of
+the string ``/set'' followed by whitespace, followed by sets of keyword/value
+pairs, separated by whitespace.
+Keyword/value pairs consist of a keyword, followed by an equals sign
+(``=''), followed by a value, without whitespace characters.
+Once a keyword has been set, its value remains unchanged until either
+reset or unset.
+.Pp
+The second type of line unsets keywords and consists of the string
+``/unset'', followed by whitespace, followed by one or more keywords,
+separated by whitespace.
+.Pp
+The third type of line is a file specification and consists of a file
+name, followed by whitespace, followed by zero or more whitespace
+separated keyword/value pairs.
+The file name may be preceded by whitespace characters.
+The file name may contain any of the standard file name matching
+characters (``['', ``]'', ``?'' or ``*''), in which case files
+in the hierarchy will be associated with the first pattern that
+they match.
+.Pp
+Each of the keyword/value pairs consist of a keyword, followed by an
+equals sign (``=''), followed by the keyword's value, without
+whitespace characters.
+These values override, without changing, the global value of the
+corresponding keyword.
+.Pp
+All paths are relative.
+Specifying a directory will cause subsequent files to be searched
+for in that directory hierarchy.
+Which brings us to the last type of line in a specification: a line
+containing only the string
+.Dq Nm \&..
+causes the current directory
+path to ascend one level.
+.Pp
+Empty lines and lines whose first non-whitespace character is a hash
+mark (``#'') are ignored.
+.Pp
+The
+.Nm
+utility exits with a status of 0 on success, 1 if any error occurred,
+and 2 if the file hierarchy did not match the specification.
+.Sh EXAMPLES
+To detect system binaries that have been ``trojan horsed'', it is recommended
+that
+.Nm
+be run on the file systems, and a copy of the results stored on a different
+machine, or, at least, in encrypted form.
+The seed for the
+.Fl s
+option should not be an obvious value and the final checksum should not be
+stored on-line under any circumstances!
+Then, periodically,
+.Nm
+should be run against the on-line specifications and the final checksum
+compared with the previous value.
+While it is possible for the bad guys to change the on-line specifications
+to conform to their modified binaries, it shouldn't be possible for them
+to make it produce the same final checksum value.
+If the final checksum value changes, the off-line copies of the specification
+can be used to detect which of the binaries have actually been modified.
+.Pp
+The
+.Fl d
+and
+.Fl u
+options can be used in combination to create directory hierarchies
+for distributions and other such things.
+.Sh FILES
+.Bl -tag -width /etc/mtree -compact
+.It Pa /etc/mtree
+system specification directory
+.El
+.Sh SEE ALSO
+.Xr chmod 1 ,
+.Xr chgrp 1 ,
+.Xr cksum 1 ,
+.Xr stat 2 ,
+.Xr fts 3 ,
+.Xr chown 8
+.Sh HISTORY
+The
+.Nm
+utility appeared in
+.Bx 4.3 Reno .
diff --git a/mtree/mtree.c b/mtree/mtree.c
new file mode 100644
index 0000000..f51b372
--- /dev/null
+++ b/mtree/mtree.c
@@ -0,0 +1,162 @@
+/*	$NetBSD: mtree.c,v 1.9 1997/10/17 11:46:51 lukem Exp $	*/
+
+/*-
+ * Copyright (c) 1989, 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1989, 1990, 1993\n\
+	The Regents of the University of California.  All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)mtree.c	8.1 (Berkeley) 6/6/93";
+#else
+__RCSID("$NetBSD: mtree.c,v 1.9 1997/10/17 11:46:51 lukem Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fts.h>
+#include "mtree.h"
+#include "extern.h"
+
+extern int crc_total;
+
+int ftsoptions = FTS_PHYSICAL;
+int cflag, dflag, eflag, rflag, sflag, tflag, uflag, Uflag;
+u_short keys;
+char fullpath[MAXPATHLEN];
+
+	int	main __P((int, char **));
+static	void	usage __P((void));
+
+int
+main(argc, argv)
+	int argc;
+	char *argv[];
+{
+	int ch;
+	char *dir, *p;
+	int status;
+
+	dir = NULL;
+	keys = KEYDEFAULT;
+	while ((ch = getopt(argc, argv, "cdef:K:k:p:rs:tUux")) != -1)
+		switch((char)ch) {
+		case 'c':
+			cflag = 1;
+			break;
+		case 'd':
+			dflag = 1;
+			break;
+		case 'e':
+			eflag = 1;
+			break;
+		case 'f':
+			if (!(freopen(optarg, "r", stdin)))
+				mtree_err("%s: %s", optarg, strerror(errno));
+			break;
+		case 'K':
+			while ((p = strsep(&optarg, " \t,")) != NULL)
+				if (*p != '\0')
+					keys |= parsekey(p, NULL);
+			break;
+		case 'k':
+			keys = F_TYPE;
+			while ((p = strsep(&optarg, " \t,")) != NULL)
+				if (*p != '\0')
+					keys |= parsekey(p, NULL);
+			break;
+		case 'p':
+			dir = optarg;
+			break;
+		case 'r':
+			rflag = 1;
+			break;
+		case 's':
+			sflag = 1;
+			crc_total = ~strtol(optarg, &p, 0);
+			if (*p)
+				mtree_err("illegal seed value -- %s", optarg);
+			break;
+		case 't':
+			tflag = 1;
+			break;
+		case 'U':
+			Uflag = uflag = 1;
+			break;
+		case 'u':
+			uflag = 1;
+			break;
+		case 'x':
+			ftsoptions |= FTS_XDEV;
+			break;
+		case '?':
+		default:
+			usage();
+		}
+	argc -= optind;
+	argv += optind;
+
+	if (argc)
+		usage();
+
+	if (dir && chdir(dir))
+		mtree_err("%s: %s", dir, strerror(errno));
+
+	if ((cflag || sflag) && !getwd(fullpath))
+		mtree_err("%s", fullpath);
+
+	if (cflag) {
+		cwalk();
+		exit(0);
+	}
+	status = verify();
+	if (Uflag & (status == MISMATCHEXIT))
+		status = 0;
+	exit(status);
+}
+
+static void
+usage()
+{
+	(void)fprintf(stderr,
+"usage: mtree [-cderUux] [-f spec] [-K key] [-k key] [-p path] [-s seed]\n");
+	exit(1);
+}
diff --git a/mtree/mtree.h b/mtree/mtree.h
new file mode 100644
index 0000000..431fdd8
--- /dev/null
+++ b/mtree/mtree.h
@@ -0,0 +1,97 @@
+/*	$NetBSD: mtree.h,v 1.7 1995/03/07 21:26:27 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)mtree.h	8.1 (Berkeley) 6/6/93
+ */
+
+#ifndef _MTREE_H_
+#define _MTREE_H_
+
+#include <string.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+#define	KEYDEFAULT \
+	(F_GID | F_MODE | F_NLINK | F_SIZE | F_SLINK | F_TIME | F_UID)
+
+#define	MISMATCHEXIT	2
+
+typedef struct _node {
+	struct _node	*parent, *child;	/* up, down */
+	struct _node	*prev, *next;		/* left, right */
+	off_t	st_size;			/* size */
+	struct timespec	st_mtimespec;		/* last modification time */
+	u_long	cksum;				/* check sum */
+	char	*slink;				/* symbolic link reference */
+	uid_t	st_uid;				/* uid */
+	gid_t	st_gid;				/* gid */
+#define	MBITS	(S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO)
+	mode_t	st_mode;			/* mode */
+	nlink_t	st_nlink;			/* link count */
+
+#define	F_CKSUM	0x0001				/* check sum */
+#define	F_DONE	0x0002				/* directory done */
+#define	F_GID	0x0004				/* gid */
+#define	F_GNAME	0x0008				/* group name */
+#define	F_IGN	0x0010				/* ignore */
+#define	F_MAGIC	0x0020				/* name has magic chars */
+#define	F_MODE	0x0040				/* mode */
+#define	F_NLINK	0x0080				/* number of links */
+#define	F_OPT	0x0100				/* existence optional */
+#define	F_SIZE	0x0200				/* size */
+#define	F_SLINK	0x0400				/* link count */
+#define	F_TIME	0x0800				/* modification time */
+#define	F_TYPE	0x1000				/* file type */
+#define	F_UID	0x2000				/* uid */
+#define	F_UNAME	0x4000				/* user name */
+#define	F_VISIT	0x8000				/* file visited */
+	u_short	flags;				/* items set */
+
+#define	F_BLOCK	0x001				/* block special */
+#define	F_CHAR	0x002				/* char special */
+#define	F_DIR	0x004				/* directory */
+#define	F_FIFO	0x008				/* fifo */
+#define	F_FILE	0x010				/* regular file */
+#define	F_LINK	0x020				/* symbolic link */
+#define	F_SOCK	0x040				/* socket */
+	u_char	type;				/* file type */
+
+	char	name[1];			/* file name (must be last) */
+} NODE;
+
+#define	RP(p)	\
+	((p)->fts_path[0] == '.' && (p)->fts_path[1] == '/' ? \
+	    (p)->fts_path + 2 : (p)->fts_path)
+
+#endif /* _MTREE_H_ */
diff --git a/mtree/spec.c b/mtree/spec.c
new file mode 100644
index 0000000..88045ee
--- /dev/null
+++ b/mtree/spec.c
@@ -0,0 +1,293 @@
+/*	$NetBSD: spec.c,v 1.12 1998/09/23 19:46:00 itohy Exp $	*/
+
+/*-
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)spec.c	8.2 (Berkeley) 4/28/95";
+#else
+__RCSID("$NetBSD: spec.c,v 1.12 1998/09/23 19:46:00 itohy Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fts.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "mtree.h"
+#include "extern.h"
+
+int lineno;				/* Current spec line number. */
+
+static void	 set __P((char *, NODE *));
+static void	 unset __P((char *, NODE *));
+
+NODE *
+spec()
+{
+	NODE *centry, *last;
+	char *p;
+	NODE ginfo, *root;
+	int c_cur, c_next;
+	char buf[2048];
+
+	root = NULL;
+	centry = last = NULL;
+	memset(&ginfo, 0, sizeof(ginfo));
+	c_cur = c_next = 0;
+	for (lineno = 1; fgets(buf, sizeof(buf), stdin);
+	    ++lineno, c_cur = c_next, c_next = 0) {
+		/* Skip empty lines. */
+		if (buf[0] == '\n')
+			continue;
+
+		/* Find end of line. */
+		if ((p = strchr(buf, '\n')) == NULL)
+			mtree_err("line %d too long", lineno);
+
+		/* See if next line is continuation line. */
+		if (p[-1] == '\\') {
+			--p;
+			c_next = 1;
+		}
+
+		/* Null-terminate the line. */
+		*p = '\0';
+
+		/* Skip leading whitespace. */
+		for (p = buf; *p && isspace(*p); ++p);
+
+		/* If nothing but whitespace or comment char, continue. */
+		if (!*p || *p == '#')
+			continue;
+
+#ifdef DEBUG
+		(void)fprintf(stderr, "line %d: {%s}\n", lineno, p);
+#endif
+		if (c_cur) {
+			set(p, centry);
+			continue;
+		}
+			
+		/* Grab file name, "$", "set", or "unset". */
+		if ((p = strtok(p, "\n\t ")) == NULL)
+			mtree_err("missing field");
+
+		if (p[0] == '/')
+			switch(p[1]) {
+			case 's':
+				if (strcmp(p + 1, "set"))
+					break;
+				set(NULL, &ginfo);
+				continue;
+			case 'u':
+				if (strcmp(p + 1, "unset"))
+					break;
+				unset(NULL, &ginfo);
+				continue;
+			}
+
+		if (strchr(p, '/'))
+			mtree_err("slash character in file name");
+
+		if (!strcmp(p, "..")) {
+			/* Don't go up, if haven't gone down. */
+			if (!root)
+				goto noparent;
+			if (last->type != F_DIR || last->flags & F_DONE) {
+				if (last == root)
+					goto noparent;
+				last = last->parent;
+			}
+			last->flags |= F_DONE;
+			continue;
+
+noparent:		mtree_err("no parent node");
+		}
+
+		if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL)
+			mtree_err("%s", strerror(errno));
+		*centry = ginfo;
+		(void)strcpy(centry->name, p);
+#define	MAGIC	"?*["
+		if (strpbrk(p, MAGIC))
+			centry->flags |= F_MAGIC;
+		set(NULL, centry);
+
+		if (!root) {
+			last = root = centry;
+			root->parent = root;
+		} else if (last->type == F_DIR && !(last->flags & F_DONE)) {
+			centry->parent = last;
+			last = last->child = centry;
+		} else {
+			centry->parent = last->parent;
+			centry->prev = last;
+			last = last->next = centry;
+		}
+	}
+	return (root);
+}
+
+static void
+set(t, ip)
+	char *t;
+	NODE *ip;
+{
+	int type;
+	char *kw, *val;
+	struct group *gr;
+	struct passwd *pw;
+	mode_t *m;
+	int value;
+	char *ep;
+
+	val = NULL;
+	for (; (kw = strtok(t, "= \t\n")) != NULL; t = NULL) {
+		ip->flags |= type = parsekey(kw, &value);
+		if (value && (val = strtok(NULL, " \t\n")) == NULL)
+			mtree_err("missing value");
+		switch(type) {
+		case F_CKSUM:
+			ip->cksum = strtoul(val, &ep, 10);
+			if (*ep)
+				mtree_err("invalid checksum %s", val);
+			break;
+		case F_GID:
+			ip->st_gid = (gid_t)strtoul(val, &ep, 10);
+			if (*ep)
+				mtree_err("invalid gid %s", val);
+			break;
+		case F_GNAME:
+			if ((gr = getgrnam(val)) == NULL)
+			    mtree_err("unknown group %s", val);
+			ip->st_gid = gr->gr_gid;
+			break;
+		case F_IGN:
+			/* just set flag bit */
+			break;
+		case F_MODE:
+			if ((m = setmode(val)) == NULL)
+				mtree_err("invalid file mode %s", val);
+			ip->st_mode = getmode(m, 0);
+			free(m);
+			break;
+		case F_NLINK:
+			ip->st_nlink = (nlink_t)strtoul(val, &ep, 10);
+			if (*ep)
+				mtree_err("invalid link count %s", val);
+			break;
+		case F_SIZE:
+			ip->st_size = (off_t)strtoq(val, &ep, 10);
+			if (*ep)
+				mtree_err("invalid size %s", val);
+			break;
+		case F_SLINK:
+			if ((ip->slink = strdup(val)) == NULL)
+				mtree_err("%s", strerror(errno));
+			break;
+		case F_TIME:
+			ip->st_mtimespec.tv_sec =
+			    (time_t)strtoul(val, &ep, 10);
+			if (*ep != '.')
+				mtree_err("invalid time %s", val);
+			val = ep + 1;
+			ip->st_mtimespec.tv_nsec = strtol(val, &ep, 10);
+			if (*ep)
+				mtree_err("invalid time %s", val);
+			break;
+		case F_TYPE:
+			switch(*val) {
+			case 'b':
+				if (!strcmp(val, "block"))
+					ip->type = F_BLOCK;
+				break;
+			case 'c':
+				if (!strcmp(val, "char"))
+					ip->type = F_CHAR;
+				break;
+			case 'd':
+				if (!strcmp(val, "dir"))
+					ip->type = F_DIR;
+				break;
+			case 'f':
+				if (!strcmp(val, "file"))
+					ip->type = F_FILE;
+				if (!strcmp(val, "fifo"))
+					ip->type = F_FIFO;
+				break;
+			case 'l':
+				if (!strcmp(val, "link"))
+					ip->type = F_LINK;
+				break;
+			case 's':
+				if (!strcmp(val, "socket"))
+					ip->type = F_SOCK;
+				break;
+			default:
+				mtree_err("unknown file type %s", val);
+			}
+			break;
+		case F_UID:
+			ip->st_uid = (uid_t)strtoul(val, &ep, 10);
+			if (*ep)
+				mtree_err("invalid uid %s", val);
+			break;
+		case F_UNAME:
+			if ((pw = getpwnam(val)) == NULL)
+			    mtree_err("unknown user %s", val);
+			ip->st_uid = pw->pw_uid;
+			break;
+		}
+	}
+}
+
+static void
+unset(t, ip)
+	char *t;
+	NODE *ip;
+{
+	char *p;
+
+	while ((p = strtok(t, "\n\t ")) != NULL)
+		ip->flags &= ~parsekey(p, NULL);
+}
diff --git a/mtree/verify.c b/mtree/verify.c
new file mode 100644
index 0000000..057f240
--- /dev/null
+++ b/mtree/verify.c
@@ -0,0 +1,211 @@
+/*	$NetBSD: verify.c,v 1.14 1998/08/27 18:03:45 ross Exp $	*/
+
+/*-
+ * Copyright (c) 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)verify.c	8.1 (Berkeley) 6/6/93";
+#else
+__RCSID("$NetBSD: verify.c,v 1.14 1998/08/27 18:03:45 ross Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <fts.h>
+#include <fnmatch.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include "mtree.h"
+#include "extern.h"
+
+extern int crc_total, ftsoptions;
+extern int dflag, eflag, rflag, sflag, uflag;
+extern char fullpath[MAXPATHLEN];
+
+static NODE *root;
+static char path[MAXPATHLEN];
+
+static void	miss __P((NODE *, char *));
+static int	vwalk __P((void));
+
+int
+verify()
+{
+	int rval;
+
+	root = spec();
+	rval = vwalk();
+	miss(root, path);
+	return (rval);
+}
+
+static int
+vwalk()
+{
+	FTS *t;
+	FTSENT *p;
+	NODE *ep, *level;
+	int ftsdepth, specdepth, rval;
+	char *argv[2];
+
+	argv[0] = ".";
+	argv[1] = NULL;
+	if ((t = fts_open(argv, ftsoptions, NULL)) == NULL)
+		mtree_err("fts_open: %s", strerror(errno));
+	level = root;
+	ftsdepth = specdepth = rval = 0;
+	while ((p = fts_read(t)) != NULL) {
+		switch(p->fts_info) {
+		case FTS_D:
+			++ftsdepth; 
+			break;
+		case FTS_DP:
+			--ftsdepth; 
+			if (specdepth > ftsdepth) {
+				for (level = level->parent; level->prev;
+				      level = level->prev);  
+				--specdepth;
+			}
+			continue;
+		case FTS_DNR:
+		case FTS_ERR:
+		case FTS_NS:
+			(void)fprintf(stderr, "mtree: %s: %s\n",
+			    RP(p), strerror(errno));
+			continue;
+		default:
+			if (dflag)
+				continue;
+		}
+
+		for (ep = level; ep; ep = ep->next)
+			if ((ep->flags & F_MAGIC &&
+			    !fnmatch(ep->name, p->fts_name, FNM_PATHNAME)) ||
+			    !strcmp(ep->name, p->fts_name)) {
+				ep->flags |= F_VISIT;
+				if (compare(ep->name, ep, p))
+					rval = MISMATCHEXIT;
+				if (!(ep->flags & F_IGN) &&
+				    ep->child && ep->type == F_DIR &&
+				    p->fts_info == FTS_D) {
+					level = ep->child;
+					++specdepth;
+				} else
+					(void)fts_set(t, p, FTS_SKIP);
+				break;
+			}
+
+		if (ep)
+			continue;
+		if (!eflag) {
+			(void)printf("extra: %s", RP(p));
+			if (rflag) {
+				if (unlink(p->fts_accpath)) {
+					(void)printf(", not removed: %s",
+					    strerror(errno));
+				} else
+					(void)printf(", removed");
+			}
+			(void)putchar('\n');
+		}
+		(void)fts_set(t, p, FTS_SKIP);
+	}
+	(void)fts_close(t);
+	if (sflag)
+		(void)fprintf(stderr,
+		    "mtree: %s checksum: %u\n", fullpath, crc_total);
+	return (rval);
+}
+
+static void
+miss(p, tail)
+	NODE *p;
+	char *tail;
+{
+	int create;
+	char *tp;
+
+	for (; p; p = p->next) {
+		if (p->flags & F_OPT && !(p->flags & F_VISIT))
+			continue;
+		if (p->type != F_DIR && (dflag || p->flags & F_VISIT))
+			continue;
+		(void)strcpy(tail, p->name);
+		if (!(p->flags & F_VISIT))
+			(void)printf("missing: %s", path);
+		if (p->type != F_DIR) {
+			putchar('\n');
+			continue;
+		}
+
+		create = 0;
+		if (!(p->flags & F_VISIT) && uflag) {
+			if (!(p->flags & (F_UID | F_UNAME)))
+			    (void)printf(" (not created: user not specified)");
+			else if (!(p->flags & (F_GID | F_GNAME)))
+			    (void)printf(" (not created: group not specified)");
+			else if (!(p->flags & F_MODE))
+			    (void)printf(" (not created: mode not specified)");
+			else if (mkdir(path, S_IRWXU))
+				(void)printf(" (not created: %s)",
+				    strerror(errno));
+			else {
+				create = 1;
+				(void)printf(" (created)");
+			}
+		}
+		if (!(p->flags & F_VISIT))
+			(void)putchar('\n');
+
+		for (tp = tail; *tp; ++tp);
+		*tp = '/';
+		miss(p->child, tp + 1);
+		*tp = '\0';
+
+		if (!create)
+			continue;
+		if (chown(path, p->st_uid, p->st_gid)) {
+			(void)printf("%s: user/group/mode not modified: %s\n",
+			    path, strerror(errno));
+			continue;
+		}
+		if (chmod(path, p->st_mode))
+			(void)printf("%s: permissions not set: %s\n",
+			    path, strerror(errno));
+	}
+}
diff --git a/mv/Makefile b/mv/Makefile
new file mode 100644
index 0000000..52e16a4
--- /dev/null
+++ b/mv/Makefile
@@ -0,0 +1,50 @@
+#
+# Generated by the NeXT Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = mv
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+HFILES = pathnames.h
+
+CFILES = mv.c
+
+OTHERSRCS = Makefile Makefile.preamble Makefile.postamble mv.1
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /bin
+LIBS = 
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+
+
+NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/$(NAME)/Build
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
diff --git a/mv/Makefile.postamble b/mv/Makefile.postamble
new file mode 100644
index 0000000..013b558
--- /dev/null
+++ b/mv/Makefile.postamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
diff --git a/mv/Makefile.preamble b/mv/Makefile.preamble
new file mode 100644
index 0000000..9e10e90
--- /dev/null
+++ b/mv/Makefile.preamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
diff --git a/mv/PB.project b/mv/PB.project
new file mode 100644
index 0000000..626c69c
--- /dev/null
+++ b/mv/PB.project
@@ -0,0 +1,26 @@
+{
+    DYNAMIC_CODE_GEN = YES; 
+    FILESTABLE = {
+        FRAMEWORKS = (); 
+        H_FILES = (pathnames.h); 
+        OTHER_LINKED = (mv.c); 
+        OTHER_SOURCES = (Makefile, Makefile.preamble, Makefile.postamble, mv.1); 
+    }; 
+    LANGUAGE = English; 
+    LOCALIZABLE_FILES = {}; 
+    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
+    NEXTSTEP_BUILDDIR = "/tmp/$(NAME)/Build"; 
+    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
+    NEXTSTEP_INSTALLDIR = /bin; 
+    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
+    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
+    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
+    PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; 
+    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
+    PROJECTNAME = mv; 
+    PROJECTTYPE = Tool; 
+    PROJECTVERSION = 2.8; 
+    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
+    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
+    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
+}
diff --git a/mv/mv.1 b/mv/mv.1
new file mode 100644
index 0000000..f831399
--- /dev/null
+++ b/mv/mv.1
@@ -0,0 +1,133 @@
+.\"	$NetBSD: mv.1,v 1.11 1998/04/20 05:43:30 ross Exp $
+.\"
+.\" Copyright (c) 1989, 1990, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)mv.1	8.1 (Berkeley) 5/31/93
+.\"
+.Dd May 31, 1993
+.Dt MV 1
+.Os
+.Sh NAME
+.Nm mv
+.Nd move files
+.Sh SYNOPSIS
+.Nm
+.Op Fl fi
+.Ar source target
+.Nm ""
+.Op Fl fi
+.Ar source ... directory
+.Sh DESCRIPTION
+.Pp
+In its first form, the
+.Nm
+utility renames the file named by the
+.Ar source
+operand to the destination path named by the
+.Ar target
+operand.
+This form is assumed when the last operand does not name an already
+existing directory.
+.Pp
+In its second form,
+.Nm
+moves each file named by a
+.Ar source
+operand to a destination file in the existing directory named by the
+.Ar directory
+operand.
+The destination path for each operand is the pathname produced by the
+concatenation of the last operand, a slash, and the final pathname
+component of the named file.
+.Pp
+The following options are available:
+.Bl -tag -width flag
+.It Fl f
+Do not prompt for confirmation before overwriting the destination
+path.
+.It Fl i
+Causes
+.Nm
+to write a prompt to standard error before moving a file that would
+overwrite an existing file.
+If the response from the standard input begins with the character ``y'',
+the move is attempted.
+.El
+The last of any
+.Fl f
+or
+.Fl i
+options is the one which affects
+.Nm Ns 's
+behavior.
+.Pp
+It is an error for either the
+.Ar source
+operand or the destination path to specify a directory unless both do.
+.Pp
+If the destination path does not have a mode which permits writing,
+.Nm
+prompts the user for confirmation as specified for the
+.Fl i
+option.
+.Pp
+As the
+.Xr rename  2
+call does not work across file systems,
+.Nm
+uses
+.Xr cp 1
+and
+.Xr rm 1
+to accomplish the move.
+The effect is equivalent to:
+.Bd -literal -offset indent
+rm -f destination_path && \e
+\tcp -PRp source_file destination && \e
+\trm -rf source_file
+.Ed
+.Pp
+The
+.Nm
+utility exits 0 on success, and >0 if an error occurs.
+.Sh SEE ALSO
+.Xr cp 1 ,
+.Xr symlink 7
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be
+.St -p1003.2
+compatible.
diff --git a/mv/mv.c b/mv/mv.c
new file mode 100644
index 0000000..a8c08d0
--- /dev/null
+++ b/mv/mv.c
@@ -0,0 +1,361 @@
+/*	$NetBSD: mv.c,v 1.19 1998/07/28 11:41:49 mycroft Exp $	*/
+
+/*
+ * Copyright (c) 1989, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ken Smith of The State University of New York at Buffalo.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1989, 1993, 1994\n\
+	The Regents of the University of California.  All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)mv.c	8.2 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: mv.c,v 1.19 1998/07/28 11:41:49 mycroft Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include "pathnames.h"
+
+int fflg, iflg;
+int stdin_ok;
+
+int	copy __P((char *, char *));
+int	do_move __P((char *, char *));
+int	fastcopy __P((char *, char *, struct stat *));
+void	usage __P((void));
+int	main __P((int, char *[]));
+
+int
+main(argc, argv)
+	int argc;
+	char *argv[];
+{
+	int baselen, len, rval;
+	char *p, *endp;
+	struct stat sb;
+	int ch;
+	char path[MAXPATHLEN + 1];
+
+	(void)setlocale(LC_ALL, "");
+
+	while ((ch = getopt(argc, argv, "if")) != -1)
+		switch (ch) {
+		case 'i':
+			fflg = 0;
+			iflg = 1;
+			break;
+		case 'f':
+			iflg = 0;
+			fflg = 1;
+			break;
+		case '?':
+		default:
+			usage();
+		}
+	argc -= optind;
+	argv += optind;
+
+	if (argc < 2)
+		usage();
+
+	stdin_ok = isatty(STDIN_FILENO);
+
+	/*
+	 * If the stat on the target fails or the target isn't a directory,
+	 * try the move.  More than 2 arguments is an error in this case.
+	 */
+	if (stat(argv[argc - 1], &sb) || !S_ISDIR(sb.st_mode)) {
+		if (argc > 2)
+			usage();
+		exit(do_move(argv[0], argv[1]));
+	}
+
+	/* It's a directory, move each file into it. */
+	(void)strcpy(path, argv[argc - 1]);
+	baselen = strlen(path);
+	endp = &path[baselen];
+	*endp++ = '/';
+	++baselen;
+	for (rval = 0; --argc; ++argv) {
+		p = *argv + strlen(*argv) - 1;
+		while (*p == '/' && p != *argv)
+			*p-- = '\0';
+		if ((p = strrchr(*argv, '/')) == NULL)
+			p = *argv;
+		else
+			++p;
+
+		if ((baselen + (len = strlen(p))) >= MAXPATHLEN) {
+			warnx("%s: destination pathname too long", *argv);
+			rval = 1;
+		} else {
+			memmove(endp, p, len + 1);
+			if (do_move(*argv, path))
+				rval = 1;
+		}
+	}
+	exit(rval);
+	/* NOTREACHED */
+}
+
+int
+do_move(from, to)
+	char *from, *to;
+{
+	struct stat sb;
+	char modep[15];
+
+	/*
+	 * (1)	If the destination path exists, the -f option is not specified
+	 *	and either of the following conditions are true:
+	 *
+	 *	(a) The perimissions of the destination path do not permit
+	 *	    writing and the standard input is a terminal.
+	 *	(b) The -i option is specified.
+	 *
+	 *	the mv utility shall write a prompt to standard error and
+	 *	read a line from standard input.  If the response is not
+	 *	affirmative, mv shall do nothing more with the current
+	 *	source file...
+	 */
+	if (!fflg && !access(to, F_OK)) {
+		int ask = 1;
+		int ch;
+
+		if (iflg) {
+			(void)fprintf(stderr, "overwrite %s? ", to);
+		} else if (stdin_ok && access(to, W_OK) && !stat(to, &sb)) {
+			strmode(sb.st_mode, modep);
+			(void)fprintf(stderr, "override %s%s%s/%s for %s? ",
+			    modep + 1, modep[9] == ' ' ? "" : " ",
+			    user_from_uid(sb.st_uid, 0),
+			    group_from_gid(sb.st_gid, 0), to);
+		} else
+			ask = 0;
+		if (ask) {
+			if ((ch = getchar()) != EOF && ch != '\n')
+				while (getchar() != '\n');
+			if (ch != 'y' && ch != 'Y')
+				return (0);
+		}
+	}
+
+	/*
+	 * (2)	If rename() succeeds, mv shall do nothing more with the
+	 *	current source file.  If it fails for any other reason than
+	 *	EXDEV, mv shall write a diagnostic message to the standard
+	 *	error and do nothing more with the current source file.
+	 *
+	 * (3)	If the destination path exists, and it is a file of type
+	 *	directory and source_file is not a file of type directory,
+	 *	or it is a file not of type directory, and source file is
+	 *	a file of type directory, mv shall write a diagnostic
+	 *	message to standard error, and do nothing more with the
+	 *	current source file...
+	 */
+	if (!rename(from, to))
+		return (0);
+
+	if (errno != EXDEV) {
+		warn("rename %s to %s", from, to);
+		return (1);
+	}
+
+	/*
+	 * (4)	If the destination path exists, mv shall attempt to remove it.
+	 *	If this fails for any reason, mv shall write a diagnostic
+	 *	message to the standard error and do nothing more with the
+	 *	current source file...
+	 */
+	if (!lstat(to, &sb)) {
+		if ((S_ISDIR(sb.st_mode)) ? rmdir(to) : unlink(to)) {
+			warn("can't remove %s", to);
+			return (1);
+		}
+	}
+
+	/*
+	 * (5)	The file hierarchy rooted in source_file shall be duplicated
+	 *	as a file hierarchy rooted in the destination path...
+	 */
+	if (lstat(from, &sb)) {
+		warn("%s", from);
+		return (1);
+	}
+	return (S_ISREG(sb.st_mode) ?
+	    fastcopy(from, to, &sb) : copy(from, to));
+}
+
+int
+fastcopy(from, to, sbp)
+	char *from, *to;
+	struct stat *sbp;
+{
+	struct timeval tval[2];
+	static u_int blen;
+	static char *bp;
+	int nread, from_fd, to_fd;
+
+	if ((from_fd = open(from, O_RDONLY, 0)) < 0) {
+		warn("%s", from);
+		return (1);
+	}
+	if ((to_fd =
+	    open(to, O_CREAT | O_TRUNC | O_WRONLY, sbp->st_mode)) < 0) {
+		warn("%s", to);
+		(void)close(from_fd);
+		return (1);
+	}
+	if (!blen && !(bp = malloc(blen = sbp->st_blksize))) {
+		warn("%s", "");
+		return (1);
+	}
+	while ((nread = read(from_fd, bp, blen)) > 0)
+		if (write(to_fd, bp, nread) != nread) {
+			warn("%s", to);
+			goto err;
+		}
+	if (nread < 0) {
+		warn("%s", from);
+err:		if (unlink(to))
+			warn("%s: remove", to);
+		(void)close(from_fd);
+		(void)close(to_fd);
+		return (1);
+	}
+	(void)close(from_fd);
+
+	TIMESPEC_TO_TIMEVAL(&tval[0], &sbp->st_atimespec);
+	TIMESPEC_TO_TIMEVAL(&tval[1], &sbp->st_mtimespec);
+#ifndef __APPLE__
+	if (futimes(to_fd, tval))
+#else
+	if (utimes(to, tval))
+#endif
+		warn("%s: set times", to);
+	if (fchown(to_fd, sbp->st_uid, sbp->st_gid)) {
+		if (errno != EPERM)
+			warn("%s: set owner/group", to);
+		sbp->st_mode &= ~(S_ISUID | S_ISGID);
+	}
+	if (fchmod(to_fd, sbp->st_mode))
+		warn("%s: set mode", to);
+
+	if (close(to_fd)) {
+		warn("%s", to);
+		return (1);
+	}
+
+	if (unlink(from)) {
+		warn("%s: remove", from);
+		return (1);
+	}
+	return (0);
+}
+
+int
+copy(from, to)
+	char *from, *to;
+{
+	int pid, status;
+
+	if ((pid = vfork()) == 0) {
+		execl(_PATH_CP, "mv", "-PRp", from, to, NULL);
+		warn("%s", _PATH_CP);
+		_exit(1);
+	}
+	if (waitpid(pid, &status, 0) == -1) {
+		warn("%s: waitpid", _PATH_CP);
+		return (1);
+	}
+	if (!WIFEXITED(status)) {
+		warn("%s: did not terminate normally", _PATH_CP);
+		return (1);
+	}
+	if (WEXITSTATUS(status)) {
+		warn("%s: terminated with %d (non-zero) status",
+		    _PATH_CP, WEXITSTATUS(status));
+		return (1);
+	}
+	if (!(pid = vfork())) {
+		execl(_PATH_RM, "mv", "-rf", from, NULL);
+		warn("%s", _PATH_RM);
+		_exit(1);
+	}
+	if (waitpid(pid, &status, 0) == -1) {
+		warn("%s: waitpid", _PATH_RM);
+		return (1);
+	}
+	if (!WIFEXITED(status)) {
+		warn("%s: did not terminate normally", _PATH_RM);
+		return (1);
+	}
+	if (WEXITSTATUS(status)) {
+		warn("%s: terminated with %d (non-zero) status",
+		    _PATH_RM, WEXITSTATUS(status));
+		return (1);
+	}
+	return (0);
+}
+
+void
+usage()
+{
+
+	(void)fprintf(stderr, "usage: mv [-fi] source target\n");
+	(void)fprintf(stderr, "       mv [-fi] source ... directory\n");
+	exit(1);
+	/* NOTREACHED */
+}
diff --git a/mv/pathnames.h b/mv/pathnames.h
new file mode 100644
index 0000000..c612fd0
--- /dev/null
+++ b/mv/pathnames.h
@@ -0,0 +1,39 @@
+/*	$NetBSD: pathnames.h,v 1.6 1995/03/21 09:06:55 cgd Exp $	*/
+
+/*
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)pathnames.h	8.1 (Berkeley) 5/31/93
+ */
+
+#define	_PATH_RM	"/bin/rm"
+#define	_PATH_CP	"/bin/cp"
diff --git a/pax/Makefile b/pax/Makefile
new file mode 100644
index 0000000..ebe65d9
--- /dev/null
+++ b/pax/Makefile
@@ -0,0 +1,54 @@
+#
+# Generated by the NeXT Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = pax
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+HFILES = cache.h cpio.h extern.h ftree.h options.h pat_rep.h pax.h\
+         sel_subs.h tables.h tar.h
+
+CFILES = ar_io.c ar_subs.c buf_subs.c cache.c cpio.c file_subs.c\
+         ftree.c gen_subs.c getoldopt.c options.c pat_rep.c pax.c\
+         sel_subs.c tables.c tar.c tty_subs.c
+
+OTHERSRCS = Makefile Makefile.preamble Makefile.postamble pax.1 cpio.1\
+            tar.1
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /bin
+LIBS = 
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+
+
+NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/$(NAME)/Build
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
diff --git a/pax/Makefile.postamble b/pax/Makefile.postamble
new file mode 100644
index 0000000..3879a87
--- /dev/null
+++ b/pax/Makefile.postamble
@@ -0,0 +1,5 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
+
+after_install::
+	$(LINKPRODUCT) $(DSTROOT)$(USRBINDIR)/cpio
+	$(LINKPRODUCT) $(DSTROOT)$(USRBINDIR)/tar
diff --git a/pax/Makefile.preamble b/pax/Makefile.preamble
new file mode 100644
index 0000000..9e10e90
--- /dev/null
+++ b/pax/Makefile.preamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
diff --git a/pax/PB.project b/pax/PB.project
new file mode 100644
index 0000000..11107f6
--- /dev/null
+++ b/pax/PB.project
@@ -0,0 +1,54 @@
+{
+    DYNAMIC_CODE_GEN = YES; 
+    FILESTABLE = {
+        FRAMEWORKS = (); 
+        H_FILES = (
+            cache.h, 
+            cpio.h, 
+            extern.h, 
+            ftree.h, 
+            options.h, 
+            pat_rep.h, 
+            pax.h, 
+            sel_subs.h, 
+            tables.h, 
+            tar.h
+        ); 
+        OTHER_LINKED = (
+            ar_io.c, 
+            ar_subs.c, 
+            buf_subs.c, 
+            cache.c, 
+            cpio.c, 
+            file_subs.c, 
+            ftree.c, 
+            gen_subs.c, 
+            getoldopt.c, 
+            options.c, 
+            pat_rep.c, 
+            pax.c, 
+            sel_subs.c, 
+            tables.c, 
+            tar.c, 
+            tty_subs.c
+        ); 
+        OTHER_SOURCES = (Makefile, Makefile.preamble, Makefile.postamble, pax.1, cpio.1, tar.1); 
+    }; 
+    LANGUAGE = English; 
+    LOCALIZABLE_FILES = {}; 
+    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
+    NEXTSTEP_BUILDDIR = "/tmp/$(NAME)/Build"; 
+    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
+    NEXTSTEP_INSTALLDIR = /bin; 
+    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
+    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
+    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
+    PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; 
+    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
+    PROJECTNAME = pax; 
+    PROJECTTYPE = Tool; 
+    PROJECTVERSION = 2.8; 
+    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
+    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
+    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
+}
diff --git a/pax/ar_io.c b/pax/ar_io.c
new file mode 100644
index 0000000..9fd7346
--- /dev/null
+++ b/pax/ar_io.c
@@ -0,0 +1,1372 @@
+/*	$OpenBSD: ar_io.c,v 1.17 1997/09/01 18:29:42 deraadt Exp $	*/
+/*	$NetBSD: ar_io.c,v 1.5 1996/03/26 23:54:13 mrg Exp $	*/
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)ar_io.c	8.2 (Berkeley) 4/18/94";
+#else
+static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: ar_io.c,v 1.17 1997/09/01 18:29:42 deraadt Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mtio.h>
+#include <sys/param.h>
+#include <signal.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <err.h>
+#include "pax.h"
+#include "options.h"
+#include "extern.h"
+
+/*
+ * Routines which deal directly with the archive I/O device/file.
+ */
+
+#define DMOD		0666		/* default mode of created archives */
+#define EXT_MODE	O_RDONLY	/* open mode for list/extract */
+#define AR_MODE		(O_WRONLY | O_CREAT | O_TRUNC)	/* mode for archive */
+#define APP_MODE	O_RDWR		/* mode for append */
+#define STDO		"<STDOUT>"	/* psuedo name for stdout */
+#define STDN		"<STDIN>"	/* psuedo name for stdin */
+static int arfd = -1;			/* archive file descriptor */
+static int artyp = ISREG;		/* archive type: file/FIFO/tape */
+static int arvol = 1;			/* archive volume number */
+static int lstrval = -1;		/* return value from last i/o */
+static int io_ok;			/* i/o worked on volume after resync */
+static int did_io;			/* did i/o ever occur on volume? */
+static int done;			/* set via tty termination */
+static struct stat arsb;		/* stat of archive device at open */
+static int invld_rec;			/* tape has out of spec record size */
+static int wr_trail = 1;		/* trailer was rewritten in append */
+static int can_unlnk = 0;		/* do we unlink null archives?  */
+char *arcname;				/* printable name of archive */
+char *gzip_program;			/* name of gzip program */
+
+static int get_phys __P((void));
+extern sigset_t s_mask;
+static void ar_start_gzip __P((int));
+
+/*
+ * ar_open()
+ *	Opens the next archive volume. Determines the type of the device and
+ *	sets up block sizes as required by the archive device and the format.
+ *	Note: we may be called with name == NULL on the first open only.
+ * Return:
+ *	-1 on failure, 0 otherwise
+ */
+
+#ifdef __STDC__
+int
+ar_open(char *name)
+#else
+int
+ar_open(name)
+	char *name;
+#endif
+{
+	struct mtget mb;
+
+	if (arfd != -1)
+		(void)close(arfd);
+	arfd = -1;
+	can_unlnk = did_io = io_ok = invld_rec = 0;
+	artyp = ISREG;
+	flcnt = 0;
+
+	/*
+	 * open based on overall operation mode
+	 */
+	switch (act) {
+	case LIST:
+	case EXTRACT:
+		if (name == NULL) {
+			arfd = STDIN_FILENO;
+			arcname = STDN;
+		} else if ((arfd = open(name, EXT_MODE, DMOD)) < 0)
+			syswarn(0, errno, "Failed open to read on %s", name);
+		if (zflag)
+			ar_start_gzip(arfd);
+		break;
+	case ARCHIVE:
+		if (name == NULL) {
+			arfd = STDOUT_FILENO;
+			arcname = STDO;
+		} else if ((arfd = open(name, AR_MODE, DMOD)) < 0)
+			syswarn(0, errno, "Failed open to write on %s", name);
+		else
+			can_unlnk = 1;
+		if (zflag)
+			ar_start_gzip(arfd);
+		break;
+	case APPND:
+		if (zflag)
+			err(1, "can not gzip while appending");
+		if (name == NULL) {
+			arfd = STDOUT_FILENO;
+			arcname = STDO;
+		} else if ((arfd = open(name, APP_MODE, DMOD)) < 0)
+			syswarn(0, errno, "Failed open to read/write on %s",
+				name);
+		break;
+	case COPY:
+		/*
+		 * arfd not used in COPY mode
+		 */
+		arcname = "<NONE>";
+		lstrval = 1;
+		return(0);
+	}
+	if (arfd < 0)
+		return(-1);
+
+	if (chdname != NULL)
+		if (chdir(chdname) != 0)
+			syswarn(1, errno, "Failed chdir to %s", chdname);
+	/*
+	 * set up is based on device type
+	 */
+	if (fstat(arfd, &arsb) < 0) {
+		syswarn(0, errno, "Failed stat on %s", arcname);
+		(void)close(arfd);
+		arfd = -1;
+		can_unlnk = 0;
+		return(-1);
+	}
+	if (S_ISDIR(arsb.st_mode)) {
+		paxwarn(0, "Cannot write an archive on top of a directory %s",
+		    arcname);
+		(void)close(arfd);
+		arfd = -1;
+		can_unlnk = 0;
+		return(-1);
+	}
+
+	if (S_ISCHR(arsb.st_mode))
+		artyp = ioctl(arfd, MTIOCGET, &mb) ? ISCHR : ISTAPE;
+	else if (S_ISBLK(arsb.st_mode))
+		artyp = ISBLK;
+	else if ((lseek(arfd, (off_t)0L, SEEK_CUR) == -1) && (errno == ESPIPE))
+		artyp = ISPIPE;
+	else
+		artyp = ISREG;
+
+	/*
+	 * make sure we beyond any doubt that we only can unlink regular files
+	 * we created
+	 */
+	if (artyp != ISREG)
+		can_unlnk = 0;
+	/*
+	 * if we are writing, we are done
+	 */
+	if (act == ARCHIVE) {
+		blksz = rdblksz = wrblksz;
+		lstrval = 1;
+		return(0);
+	}
+
+	/*
+	 * set default blksz on read. APPNDs writes rdblksz on the last volume
+	 * On all new archive volumes, we shift to wrblksz (if the user
+	 * specified one, otherwize we will continue to use rdblksz). We
+	 * must to set blocksize based on what kind of device the archive is
+	 * stored.
+	 */
+	switch(artyp) {
+	case ISTAPE:
+		/*
+		 * Tape drives come in at least two flavors. Those that support
+		 * variable sized records and those that have fixed sized
+		 * records. They must be treated differently. For tape drives
+		 * that support variable sized records, we must make large
+		 * reads to make sure we get the entire record, otherwise we
+		 * will just get the first part of the record (up to size we
+		 * asked). Tapes with fixed sized records may or may not return
+		 * multiple records in a single read. We really do not care
+		 * what the physical record size is UNLESS we are going to
+		 * append. (We will need the physical block size to rewrite
+		 * the trailer). Only when we are appending do we go to the
+		 * effort to figure out the true PHYSICAL record size.
+		 */
+		blksz = rdblksz = MAXBLK;
+		break;
+	case ISPIPE:
+	case ISBLK:
+	case ISCHR:
+		/*
+		 * Blocksize is not a major issue with these devices (but must
+		 * be kept a multiple of 512). If the user specified a write
+		 * block size, we use that to read. Under append, we must
+		 * always keep blksz == rdblksz. Otherwise we go ahead and use
+		 * the device optimal blocksize as (and if) returned by stat
+		 * and if it is within pax specs.
+		 */
+		if ((act == APPND) && wrblksz) {
+			blksz = rdblksz = wrblksz;
+			break;
+		}
+
+		if ((arsb.st_blksize > 0) && (arsb.st_blksize < MAXBLK) &&
+		    ((arsb.st_blksize % BLKMULT) == 0))
+			rdblksz = arsb.st_blksize;
+		else
+			rdblksz = DEVBLK;
+		/*
+		 * For performance go for large reads when we can without harm
+		 */
+		if ((act == APPND) || (artyp == ISCHR))
+			blksz = rdblksz;
+		else
+			blksz = MAXBLK;
+		break;
+	case ISREG:
+		/*
+		 * if the user specified wrblksz works, use it. Under appends
+		 * we must always keep blksz == rdblksz
+		 */
+		if ((act == APPND) && wrblksz && ((arsb.st_size%wrblksz)==0)){
+			blksz = rdblksz = wrblksz;
+			break;
+		}
+		/*
+		 * See if we can find the blocking factor from the file size
+		 */
+		for (rdblksz = MAXBLK; rdblksz > 0; rdblksz -= BLKMULT)
+			if ((arsb.st_size % rdblksz) == 0)
+				break;
+		/*
+		 * When we cannont find a match, we may have a flawed archive.
+		 */
+		if (rdblksz <= 0)
+			rdblksz = FILEBLK;
+		/*
+		 * for performance go for large reads when we can
+		 */
+		if (act == APPND)
+			blksz = rdblksz;
+		else
+			blksz = MAXBLK;
+		break;
+	default:
+		/*
+		 * should never happen, worse case, slow... 
+		 */
+		blksz = rdblksz = BLKMULT;
+		break;
+	}
+	lstrval = 1;
+	return(0);
+}
+
+/*
+ * ar_close()
+ *	closes archive device, increments volume number, and prints i/o summary
+ */
+#ifdef __STDC__
+void
+ar_close(void)
+#else
+void
+ar_close()
+#endif
+{
+	FILE *outf;
+
+	if (arfd < 0) {
+		did_io = io_ok = flcnt = 0;
+		return;
+	}
+
+	if (act == LIST)
+		outf = stdout;
+	else
+		outf = stderr;
+
+	/*
+	 * Close archive file. This may take a LONG while on tapes (we may be
+	 * forced to wait for the rewind to complete) so tell the user what is
+	 * going on (this avoids the user hitting control-c thinking pax is
+	 * broken).
+	 */
+	if (vflag && (artyp == ISTAPE)) {
+		if (vfpart)
+			(void)putc('\n', outf);
+		(void)fprintf(outf,
+			"%s: Waiting for tape drive close to complete...",
+			argv0);
+		(void)fflush(outf);
+	}
+
+	/*
+	 * if nothing was written to the archive (and we created it), we remove
+	 * it
+	 */
+	if (can_unlnk && (fstat(arfd, &arsb) == 0) && (S_ISREG(arsb.st_mode)) &&
+	    (arsb.st_size == 0)) {
+		(void)unlink(arcname);
+		can_unlnk = 0;
+	}
+
+	(void)close(arfd);
+
+	if (vflag && (artyp == ISTAPE)) {
+		(void)fputs("done.\n", outf);
+		vfpart = 0;
+		(void)fflush(outf);
+	}
+	arfd = -1;
+
+	if (!io_ok && !did_io) {
+		flcnt = 0;
+		return;
+	}
+	did_io = io_ok = 0;
+
+	/*
+	 * The volume number is only increased when the last device has data
+	 * and we have already determined the archive format.
+	 */
+	if (frmt != NULL)
+		++arvol;
+
+	if (!vflag) {
+		flcnt = 0;
+		return;
+	}
+
+	/*
+	 * Print out a summary of I/O for this archive volume.
+	 */
+	if (vfpart) {
+		(void)putc('\n', outf);
+		vfpart = 0;
+	}
+
+	/*
+	 * If we have not determined the format yet, we just say how many bytes
+	 * we have skipped over looking for a header to id. there is no way we
+	 * could have written anything yet.
+	 */
+	if (frmt == NULL) {
+#	ifdef NET2_STAT
+		(void)fprintf(outf, "%s: unknown format, %lu bytes skipped.\n",
+#	else
+		(void)fprintf(outf, "%s: unknown format, %qu bytes skipped.\n",
+#	endif
+		    argv0, rdcnt);
+		(void)fflush(outf);
+		flcnt = 0;
+		return;
+	}
+
+	if (strcmp(NM_CPIO, argv0) == 0)
+		(void)fprintf(outf, "%qu blocks\n", (rdcnt ? rdcnt : wrcnt) / 5120);
+	else if (strcmp(NM_TAR, argv0) != 0)
+		(void)fprintf(outf,
+#	ifdef NET2_STAT
+		    "%s: %s vol %d, %lu files, %lu bytes read, %lu bytes written.\n",
+#	else
+		    "%s: %s vol %d, %lu files, %qu bytes read, %qu bytes written.\n",
+#	endif
+		    argv0, frmt->name, arvol-1, flcnt, rdcnt, wrcnt);
+	(void)fflush(outf);
+	flcnt = 0;
+}
+
+/*
+ * ar_drain()
+ *	drain any archive format independent padding from an archive read
+ *	from a socket or a pipe. This is to prevent the process on the
+ *	other side of the pipe from getting a SIGPIPE (pax will stop
+ *	reading an archive once a format dependent trailer is detected).
+ */
+#ifdef __STDC__
+void
+ar_drain(void)
+#else
+void
+ar_drain()
+#endif
+{
+	register int res;
+	char drbuf[MAXBLK];
+
+	/*
+	 * we only drain from a pipe/socket. Other devices can be closed
+	 * without reading up to end of file. We sure hope that pipe is closed
+	 * on the other side so we will get an EOF.
+	 */
+	if ((artyp != ISPIPE) || (lstrval <= 0))
+		return;
+
+	/*
+	 * keep reading until pipe is drained
+	 */
+	while ((res = read(arfd, drbuf, sizeof(drbuf))) > 0)
+		;
+	lstrval = res;
+}
+
+/*
+ * ar_set_wr()
+ *	Set up device right before switching from read to write in an append.
+ *	device dependent code (if required) to do this should be added here.
+ *	For all archive devices we are already positioned at the place we want
+ *	to start writing when this routine is called.
+ * Return:
+ *	0 if all ready to write, -1 otherwise
+ */
+
+#ifdef __STDC__
+int
+ar_set_wr(void)
+#else
+int
+ar_set_wr()
+#endif
+{
+	off_t cpos;
+
+	/*
+	 * we must make sure the trailer is rewritten on append, ar_next()
+	 * will stop us if the archive containing the trailer was not written
+	 */
+	wr_trail = 0;
+
+	/* 
+	 * Add any device dependent code as required here
+	 */
+	if (artyp != ISREG)
+		return(0);
+	/*
+	 * Ok we have an archive in a regular file. If we were rewriting a
+	 * file, we must get rid of all the stuff after the current offset
+	 * (it was not written by pax).
+	 */
+	if (((cpos = lseek(arfd, (off_t)0L, SEEK_CUR)) < 0) ||
+	    (ftruncate(arfd, cpos) < 0)) {
+		syswarn(1, errno, "Unable to truncate archive file");
+		return(-1);
+	}
+	return(0);
+}
+
+/*
+ * ar_app_ok()
+ *	check if the last volume in the archive allows appends. We cannot check
+ *	this until we are ready to write since there is no spec that says all 
+ *	volumes in a single archive have to be of the same type...
+ * Return:
+ *	0 if we can append, -1 otherwise.
+ */
+
+#ifdef __STDC__
+int
+ar_app_ok(void)
+#else
+int
+ar_app_ok()
+#endif
+{
+	if (artyp == ISPIPE) {
+		paxwarn(1, "Cannot append to an archive obtained from a pipe.");
+		return(-1);
+	}
+
+	if (!invld_rec)
+		return(0);
+	paxwarn(1,"Cannot append, device record size %d does not support %s spec",
+		rdblksz, argv0);
+	return(-1);
+}
+
+/*
+ * ar_read()
+ *	read up to a specified number of bytes from the archive into the
+ *	supplied buffer. When dealing with tapes we may not always be able to
+ *	read what we want.
+ * Return:
+ *	Number of bytes in buffer. 0 for end of file, -1 for a read error.
+ */
+
+#ifdef __STDC__
+int
+ar_read(register char *buf, register int cnt)
+#else
+int
+ar_read(buf, cnt)
+	register char *buf;
+	register int cnt;
+#endif
+{
+	register int res = 0;
+
+	/*
+	 * if last i/o was in error, no more reads until reset or new volume
+	 */
+	if (lstrval <= 0)
+		return(lstrval);
+
+	/*
+	 * how we read must be based on device type
+	 */
+	switch (artyp) {
+	case ISTAPE:
+		if ((res = read(arfd, buf, cnt)) > 0) {
+			/*
+			 * CAUTION: tape systems may not always return the same
+			 * sized records so we leave blksz == MAXBLK. The
+			 * physical record size that a tape drive supports is
+			 * very hard to determine in a uniform and portable
+			 * manner.
+			 */
+			io_ok = 1;
+			if (res != rdblksz) {
+				/*
+				 * Record size changed. If this is happens on
+				 * any record after the first, we probably have
+				 * a tape drive which has a fixed record size
+				 * we are getting multiple records in a single
+				 * read). Watch out for record blocking that
+				 * violates pax spec (must be a multiple of
+				 * BLKMULT).
+				 */
+				rdblksz = res;
+				if (rdblksz % BLKMULT)
+					invld_rec = 1;
+			}
+			return(res);
+		}
+		break;
+	case ISREG:
+	case ISBLK:
+	case ISCHR:
+	case ISPIPE:
+	default:
+		/*
+		 * Files are so easy to deal with. These other things cannot
+		 * be trusted at all. So when we are dealing with character
+		 * devices and pipes we just take what they have ready for us
+		 * and return. Trying to do anything else with them runs the
+		 * risk of failure.
+		 */
+		if ((res = read(arfd, buf, cnt)) > 0) {
+			io_ok = 1;
+			return(res);
+		}
+		break;
+	}
+
+	/*
+	 * We are in trouble at this point, something is broken...
+	 */
+	lstrval = res;
+	if (res < 0)
+		syswarn(1, errno, "Failed read on archive volume %d", arvol);
+	else
+		paxwarn(0, "End of archive volume %d reached", arvol);
+	return(res);
+}
+
+/*
+ * ar_write()
+ *	Write a specified number of bytes in supplied buffer to the archive
+ *	device so it appears as a single "block". Deals with errors and tries
+ *	to recover when faced with short writes.
+ * Return:
+ *	Number of bytes written. 0 indicates end of volume reached and with no
+ *	flaws (as best that can be detected). A -1 indicates an unrecoverable
+ *	error in the archive occured.
+ */
+
+#ifdef __STDC__
+int
+ar_write(register char *buf, register int bsz)
+#else
+int
+ar_write(buf, bsz)
+	register char *buf;
+	register int bsz;
+#endif
+{
+	register int res;
+	off_t cpos;
+
+	/*
+	 * do not allow pax to create a "bad" archive. Once a write fails on
+	 * an archive volume prevent further writes to it.
+	 */
+	if (lstrval <= 0)
+		return(lstrval);
+
+	if ((res = write(arfd, buf, bsz)) == bsz) {
+		wr_trail = 1;
+		io_ok = 1;
+		return(bsz);
+	}
+	/*
+	 * write broke, see what we can do with it. We try to send any partial
+	 * writes that may violate pax spec to the next archive volume.
+	 */
+	if (res < 0)
+		lstrval = res;
+	else
+		lstrval = 0;
+
+	switch (artyp) {
+	case ISREG:
+		if ((res > 0) && (res % BLKMULT)) {
+			/*
+		 	 * try to fix up partial writes which are not BLKMULT
+			 * in size by forcing the runt record to next archive
+			 * volume
+		 	 */
+			if ((cpos = lseek(arfd, (off_t)0L, SEEK_CUR)) < 0)
+				break;
+			cpos -= (off_t)res;
+			if (ftruncate(arfd, cpos) < 0)
+				break;
+			res = lstrval = 0;
+			break;
+		}
+		if (res >= 0)
+			break;
+		/*
+		 * if file is out of space, handle it like a return of 0
+		 */
+		if ((errno == ENOSPC) || (errno == EFBIG) || (errno == EDQUOT))
+			res = lstrval = 0;
+		break;
+	case ISTAPE:
+	case ISCHR:
+	case ISBLK:
+		if (res >= 0)
+			break;
+		if (errno == EACCES) {
+			paxwarn(0, "Write failed, archive is write protected.");
+			res = lstrval = 0;
+			return(0);
+		}
+		/*
+		 * see if we reached the end of media, if so force a change to
+		 * the next volume
+		 */
+		if ((errno == ENOSPC) || (errno == EIO) || (errno == ENXIO))
+			res = lstrval = 0;
+		break;
+	case ISPIPE:
+	default:
+		/*
+		 * we cannot fix errors to these devices
+		 */
+		break;
+	}
+
+	/*
+	 * Better tell the user the bad news...
+	 * if this is a block aligned archive format, we may have a bad archive
+	 * if the format wants the header to start at a BLKMULT boundry. While
+	 * we can deal with the mis-aligned data, it violates spec and other
+	 * archive readers will likely fail. if the format is not block
+	 * aligned, the user may be lucky (and the archive is ok).
+	 */
+	if (res >= 0) {
+		if (res > 0)
+			wr_trail = 1;
+		io_ok = 1;
+	}
+
+	/*
+	 * If we were trying to rewrite the trailer and it didn't work, we
+	 * must quit right away.
+	 */
+	if (!wr_trail && (res <= 0)) {
+		paxwarn(1,"Unable to append, trailer re-write failed. Quitting.");
+		return(res);
+	}
+
+	if (res == 0)
+		paxwarn(0, "End of archive volume %d reached", arvol);
+	else if (res < 0)
+		syswarn(1, errno, "Failed write to archive volume: %d", arvol);
+	else if (!frmt->blkalgn || ((res % frmt->blkalgn) == 0))
+		paxwarn(0,"WARNING: partial archive write. Archive MAY BE FLAWED");
+	else
+		paxwarn(1,"WARNING: partial archive write. Archive IS FLAWED");
+	return(res);
+}
+
+/*
+ * ar_rdsync()
+ *	Try to move past a bad spot on a flawed archive as needed to continue
+ *	I/O. Clears error flags to allow I/O to continue.
+ * Return:
+ *	0 when ok to try i/o again, -1 otherwise.
+ */
+
+#ifdef __STDC__
+int
+ar_rdsync(void)
+#else
+int
+ar_rdsync()
+#endif
+{
+	long fsbz;
+	off_t cpos;
+	off_t mpos;
+	struct mtop mb;
+
+	/*
+	 * Fail resync attempts at user request (done) or this is going to be
+	 * an update/append to a existing archive. if last i/o hit media end,
+	 * we need to go to the next volume not try a resync
+	 */
+	if ((done > 0) || (lstrval == 0))
+		return(-1);
+
+	if ((act == APPND) || (act == ARCHIVE)) {
+		paxwarn(1, "Cannot allow updates to an archive with flaws.");
+		return(-1);
+	}
+	if (io_ok)
+		did_io = 1;
+
+	switch(artyp) {
+	case ISTAPE:
+		/*
+		 * if the last i/o was a successful data transfer, we assume
+		 * the fault is just a bad record on the tape that we are now
+		 * past. If we did not get any data since the last resync try
+		 * to move the tape foward one PHYSICAL record past any
+		 * damaged tape section. Some tape drives are stubborn and need
+		 * to be pushed.
+		 */
+		if (io_ok) {
+			io_ok = 0;
+			lstrval = 1;
+			break;
+		}
+		mb.mt_op = MTFSR;
+		mb.mt_count = 1;
+		if (ioctl(arfd, MTIOCTOP, &mb) < 0)
+			break;
+		lstrval = 1;
+		break;
+	case ISREG:
+	case ISCHR:
+	case ISBLK:
+		/*
+		 * try to step over the bad part of the device.
+		 */
+		io_ok = 0;
+		if (((fsbz = arsb.st_blksize) <= 0) || (artyp != ISREG))
+			fsbz = BLKMULT;
+		if ((cpos = lseek(arfd, (off_t)0L, SEEK_CUR)) < 0)
+			break;
+		mpos = fsbz - (cpos % (off_t)fsbz);
+		if (lseek(arfd, mpos, SEEK_CUR) < 0)
+			break;
+		lstrval = 1;
+		break;
+	case ISPIPE:
+	default:
+		/*
+		 * cannot recover on these archive device types
+		 */
+		io_ok = 0;
+		break;
+	}
+	if (lstrval <= 0) {
+		paxwarn(1, "Unable to recover from an archive read failure.");
+		return(-1);
+	}
+	paxwarn(0, "Attempting to recover from an archive read failure.");
+	return(0);
+}
+
+/*
+ * ar_fow()
+ *	Move the I/O position within the archive foward the specified number of
+ *	bytes as supported by the device. If we cannot move the requested
+ *	number of bytes, return the actual number of bytes moved in skipped.
+ * Return:
+ *	0 if moved the requested distance, -1 on complete failure, 1 on
+ *	partial move (the amount moved is in skipped)
+ */
+
+#ifdef __STDC__
+int
+ar_fow(off_t sksz, off_t *skipped)
+#else
+int
+ar_fow(sksz, skipped)
+	off_t sksz;
+	off_t *skipped;
+#endif
+{
+	off_t cpos;
+	off_t mpos;
+
+	*skipped = 0;
+	if (sksz <= 0)
+		return(0);
+
+	/*
+	 * we cannot move foward at EOF or error
+	 */
+	if (lstrval <= 0)
+		return(lstrval);
+
+	/*
+	 * Safer to read forward on devices where it is hard to find the end of
+	 * the media without reading to it. With tapes we cannot be sure of the
+	 * number of physical blocks to skip (we do not know physical block
+	 * size at this point), so we must only read foward on tapes!
+	 */
+	if (artyp != ISREG)
+		return(0);
+
+	/*
+	 * figure out where we are in the archive
+	 */
+	if ((cpos = lseek(arfd, (off_t)0L, SEEK_CUR)) >= 0) {
+		/* 
+	 	 * we can be asked to move farther than there are bytes in this
+		 * volume, if so, just go to file end and let normal buf_fill()
+		 * deal with the end of file (it will go to next volume by
+		 * itself)
+	 	 */
+		if ((mpos = cpos + sksz) > arsb.st_size) {
+			*skipped = arsb.st_size - cpos;
+			mpos = arsb.st_size;
+		} else
+			*skipped = sksz;
+		if (lseek(arfd, mpos, SEEK_SET) >= 0)
+			return(0);
+	}
+	syswarn(1, errno, "Foward positioning operation on archive failed");
+	lstrval = -1;
+	return(-1);
+}
+
+/*
+ * ar_rev()
+ *	move the i/o position within the archive backwards the specified byte
+ *	count as supported by the device. With tapes drives we RESET rdblksz to
+ *	the PHYSICAL blocksize.
+ *	NOTE: We should only be called to move backwards so we can rewrite the
+ *	last records (the trailer) of an archive (APPEND).
+ * Return:
+ *	0 if moved the requested distance, -1 on complete failure
+ */
+
+#ifdef __STDC__
+int
+ar_rev(off_t sksz)
+#else
+int
+ar_rev(sksz)
+	off_t sksz;
+#endif
+{
+	off_t cpos;
+	struct mtop mb;
+	register int phyblk;
+
+	/*
+	 * make sure we do not have try to reverse on a flawed archive
+	 */
+	if (lstrval < 0)
+		return(lstrval);
+
+	switch(artyp) {
+	case ISPIPE:
+		if (sksz <= 0)
+			break;
+		/*
+		 * cannot go backwards on these critters
+		 */
+		paxwarn(1, "Reverse positioning on pipes is not supported.");
+		lstrval = -1;
+		return(-1);
+	case ISREG:
+	case ISBLK:
+	case ISCHR:
+	default:
+		if (sksz <= 0)
+			break;
+
+		/*
+		 * For things other than files, backwards movement has a very
+		 * high probability of failure as we really do not know the
+		 * true attributes of the device we are talking to (the device
+		 * may not even have the ability to lseek() in any direction).
+		 * First we figure out where we are in the archive.
+		 */
+		if ((cpos = lseek(arfd, (off_t)0L, SEEK_CUR)) < 0) {
+			syswarn(1, errno,
+			   "Unable to obtain current archive byte offset");
+			lstrval = -1;
+			return(-1);
+		}
+
+		/*
+		 * we may try to go backwards past the start when the archive
+		 * is only a single record. If this hapens and we are on a
+		 * multi volume archive, we need to go to the end of the
+		 * previous volume and continue our movement backwards from
+		 * there.
+		 */
+		if ((cpos -= sksz) < (off_t)0L) {
+			if (arvol > 1) {
+				/*
+				 * this should never happen
+				 */
+				paxwarn(1,"Reverse position on previous volume.");
+				lstrval = -1;
+				return(-1);
+			}
+			cpos = (off_t)0L;
+		}
+		if (lseek(arfd, cpos, SEEK_SET) < 0) {
+			syswarn(1, errno, "Unable to seek archive backwards");
+			lstrval = -1;
+			return(-1);
+		}
+		break;
+	case ISTAPE:
+		/*
+	 	 * Calculate and move the proper number of PHYSICAL tape
+		 * blocks. If the sksz is not an even multiple of the physical
+		 * tape size, we cannot do the move (this should never happen).
+		 * (We also cannot handler trailers spread over two vols).
+		 * get_phys() also makes sure we are in front of the filemark.
+	 	 */
+		if ((phyblk = get_phys()) <= 0) {
+			lstrval = -1;
+			return(-1);
+		}
+
+		/*
+		 * make sure future tape reads only go by physical tape block
+		 * size (set rdblksz to the real size).
+		 */
+		rdblksz = phyblk;
+
+		/*
+		 * if no movement is required, just return (we must be after
+		 * get_phys() so the physical blocksize is properly set)
+		 */
+		if (sksz <= 0)
+			break;
+
+		/*
+		 * ok we have to move. Make sure the tape drive can do it.
+		 */
+		if (sksz % phyblk) {
+			paxwarn(1,
+			    "Tape drive unable to backspace requested amount");
+			lstrval = -1;
+			return(-1);
+		}
+
+		/*
+		 * move backwards the requested number of bytes
+		 */
+		mb.mt_op = MTBSR;
+		mb.mt_count = sksz/phyblk;
+		if (ioctl(arfd, MTIOCTOP, &mb) < 0) {
+			syswarn(1,errno, "Unable to backspace tape %d blocks.",
+			    mb.mt_count);
+			lstrval = -1;
+			return(-1);
+		}
+		break;
+	}
+	lstrval = 1;
+	return(0);
+}
+
+/*
+ * get_phys()
+ *	Determine the physical block size on a tape drive. We need the physical
+ *	block size so we know how many bytes we skip over when we move with 
+ *	mtio commands. We also make sure we are BEFORE THE TAPE FILEMARK when
+ *	return.
+ *	This is one really SLOW routine...
+ * Return:
+ *	physical block size if ok (ok > 0), -1 otherwise
+ */
+
+#ifdef __STDC__
+static int
+get_phys(void)
+#else
+static int
+get_phys()
+#endif
+{
+	register int padsz = 0;
+	register int res;
+	register int phyblk;
+	struct mtop mb;
+	char scbuf[MAXBLK];
+
+	/*
+	 * move to the file mark, and then back up one record and read it.
+	 * this should tell us the physical record size the tape is using.
+	 */
+	if (lstrval == 1) {
+		/*
+		 * we know we are at file mark when we get back a 0 from
+		 * read()
+		 */
+		while ((res = read(arfd, scbuf, sizeof(scbuf))) > 0)
+			padsz += res;
+		if (res < 0) {
+			syswarn(1, errno, "Unable to locate tape filemark.");
+			return(-1);
+		}
+	}
+
+	/*
+	 * move backwards over the file mark so we are at the end of the
+	 * last record.
+	 */
+	mb.mt_op = MTBSF;
+	mb.mt_count = 1;
+	if (ioctl(arfd, MTIOCTOP, &mb) < 0) {
+		syswarn(1, errno, "Unable to backspace over tape filemark.");
+		return(-1);
+	}
+
+	/*
+	 * move backwards so we are in front of the last record and read it to
+	 * get physical tape blocksize.
+	 */
+	mb.mt_op = MTBSR;
+	mb.mt_count = 1;
+	if (ioctl(arfd, MTIOCTOP, &mb) < 0) {
+		syswarn(1, errno, "Unable to backspace over last tape block.");
+		return(-1);
+	}
+	if ((phyblk = read(arfd, scbuf, sizeof(scbuf))) <= 0) {
+		syswarn(1, errno, "Cannot determine archive tape blocksize.");
+		return(-1);
+	}
+
+	/*
+	 * read foward to the file mark, then back up in front of the filemark
+	 * (this is a bit paranoid, but should be safe to do).
+	 */
+	while ((res = read(arfd, scbuf, sizeof(scbuf))) > 0)
+		;
+	if (res < 0) {
+		syswarn(1, errno, "Unable to locate tape filemark.");
+		return(-1);
+	}
+	mb.mt_op = MTBSF;
+	mb.mt_count = 1;
+	if (ioctl(arfd, MTIOCTOP, &mb) < 0) {
+		syswarn(1, errno, "Unable to backspace over tape filemark.");
+		return(-1);
+	}
+
+	/*
+	 * set lstrval so we know that the filemark has not been seen
+	 */
+	lstrval = 1;
+
+	/*
+	 * return if there was no padding
+	 */
+	if (padsz == 0)
+		return(phyblk);
+
+	/*
+	 * make sure we can move backwards over the padding. (this should
+	 * never fail).
+	 */
+	if (padsz % phyblk) {
+		paxwarn(1, "Tape drive unable to backspace requested amount");
+		return(-1);
+	}
+
+	/*
+	 * move backwards over the padding so the head is where it was when
+	 * we were first called (if required).
+	 */
+	mb.mt_op = MTBSR;
+	mb.mt_count = padsz/phyblk;
+	if (ioctl(arfd, MTIOCTOP, &mb) < 0) {
+		syswarn(1,errno,"Unable to backspace tape over %d pad blocks",
+		    mb.mt_count);
+		return(-1);
+	}
+	return(phyblk);
+}
+
+/*
+ * ar_next()
+ *	prompts the user for the next volume in this archive. For some devices
+ *	we may allow the media to be changed. Otherwise a new archive is
+ *	prompted for. By pax spec, if there is no controlling tty or an eof is
+ *	read on tty input, we must quit pax.
+ * Return:
+ *	0 when ready to continue, -1 when all done
+ */
+
+#ifdef __STDC__
+int
+ar_next(void)
+#else
+int
+ar_next()
+#endif
+{
+	char buf[PAXPATHLEN+2];
+	static int freeit = 0;
+	sigset_t o_mask;
+
+	/*
+	 * WE MUST CLOSE THE DEVICE. A lot of devices must see last close, (so
+	 * things like writing EOF etc will be done) (Watch out ar_close() can
+	 * also be called via a signal handler, so we must prevent a race.
+	 */
+	if (sigprocmask(SIG_BLOCK, &s_mask, &o_mask) < 0)
+		syswarn(0, errno, "Unable to set signal mask");
+	ar_close();
+	if (sigprocmask(SIG_SETMASK, &o_mask, NULL) < 0)
+		syswarn(0, errno, "Unable to restore signal mask");
+
+	if (done || !wr_trail || strcmp(NM_TAR, argv0) == 0)
+		return(-1);
+
+	tty_prnt("\nATTENTION! %s archive volume change required.\n", argv0);
+
+	/*
+	 * if i/o is on stdin or stdout, we cannot reopen it (we do not know
+	 * the name), the user will be forced to type it in.
+	 */
+	if (strcmp(arcname, STDO) && strcmp(arcname, STDN) && (artyp != ISREG)
+	    && (artyp != ISPIPE)) {
+		if (artyp == ISTAPE) {
+			tty_prnt("%s ready for archive tape volume: %d\n",
+				arcname, arvol);
+			tty_prnt("Load the NEXT TAPE on the tape drive");
+		} else {
+			tty_prnt("%s ready for archive volume: %d\n",
+				arcname, arvol);
+			tty_prnt("Load the NEXT STORAGE MEDIA (if required)");
+		}
+
+		if ((act == ARCHIVE) || (act == APPND))
+			tty_prnt(" and make sure it is WRITE ENABLED.\n");
+		else
+			tty_prnt("\n");
+
+		for(;;) {
+			tty_prnt("Type \"y\" to continue, \".\" to quit %s,",
+				argv0);
+			tty_prnt(" or \"s\" to switch to new device.\nIf you");
+			tty_prnt(" cannot change storage media, type \"s\"\n");
+			tty_prnt("Is the device ready and online? > ");
+
+			if ((tty_read(buf,sizeof(buf))<0) || !strcmp(buf,".")){
+				done = 1;
+				lstrval = -1;
+				tty_prnt("Quitting %s!\n", argv0);
+				vfpart = 0;
+				return(-1);
+			}
+
+			if ((buf[0] == '\0') || (buf[1] != '\0')) {
+				tty_prnt("%s unknown command, try again\n",buf);
+				continue;
+			}
+
+			switch (buf[0]) {
+			case 'y':
+			case 'Y':
+				/*
+				 * we are to continue with the same device
+				 */
+				if (ar_open(arcname) >= 0)
+					return(0);
+				tty_prnt("Cannot re-open %s, try again\n",
+					arcname);
+				continue;
+			case 's':
+			case 'S':
+				/*
+				 * user wants to open a different device
+				 */
+				tty_prnt("Switching to a different archive\n");
+				break;
+			default:
+				tty_prnt("%s unknown command, try again\n",buf);
+				continue;
+			}
+			break;
+		}
+	} else
+		tty_prnt("Ready for archive volume: %d\n", arvol);
+
+	/*
+	 * have to go to a different archive
+	 */
+	for (;;) {
+		tty_prnt("Input archive name or \".\" to quit %s.\n", argv0);
+		tty_prnt("Archive name > ");
+
+		if ((tty_read(buf, sizeof(buf)) < 0) || !strcmp(buf, ".")) {
+			done = 1;
+			lstrval = -1;
+			tty_prnt("Quitting %s!\n", argv0);
+			vfpart = 0;
+			return(-1);
+		}
+		if (buf[0] == '\0') {
+			tty_prnt("Empty file name, try again\n");
+			continue;
+		}
+		if (!strcmp(buf, "..")) {
+			tty_prnt("Illegal file name: .. try again\n");
+			continue;
+		}
+		if (strlen(buf) > PAXPATHLEN) {
+			tty_prnt("File name too long, try again\n");
+			continue;
+		}
+
+		/*
+		 * try to open new archive
+		 */
+		if (ar_open(buf) >= 0) {
+			if (freeit) {
+				(void)free(arcname);
+				freeit = 0;
+			}
+			if ((arcname = strdup(buf)) == NULL) {
+				done = 1;
+				lstrval = -1;
+				paxwarn(0, "Cannot save archive name.");
+				return(-1);
+			}
+			freeit = 1;
+			break;
+		}
+		tty_prnt("Cannot open %s, try again\n", buf);
+		continue;
+	}
+	return(0);
+}
+
+/*
+ * ar_start_gzip()
+ * starts the gzip compression/decompression process as a child, using magic
+ * to keep the fd the same in the calling function (parent).
+ */
+void
+#ifdef __STDC__
+ar_start_gzip(int fd)
+#else
+ar_start_gzip(fd)
+	int fd;
+#endif
+{
+	pid_t pid;
+	int fds[2];
+	char *gzip_flags=NULL;
+
+	if (pipe(fds) < 0)
+		err(1, "could not pipe");
+	pid = fork();
+	if (pid < 0)
+		err(1, "could not fork");
+
+	/* parent */
+	if (pid) {
+		switch (act) {
+		case ARCHIVE:
+			dup2(fds[1], fd);
+			break;
+		case LIST:
+		case EXTRACT:
+			dup2(fds[0], fd);
+			break;
+		default:
+			errx(1, "ar_start_gzip:  impossible");
+		}
+		close(fds[0]);
+		close(fds[1]);
+	} else {
+		switch (act) {
+		case ARCHIVE:
+			dup2(fds[0], STDIN_FILENO);
+			dup2(fd, STDOUT_FILENO);
+			gzip_flags = "-c";
+			break;
+		case LIST:
+		case EXTRACT:
+			dup2(fds[1], STDOUT_FILENO);
+			dup2(fd, STDIN_FILENO);
+			gzip_flags = "-dc";
+			break;
+		default:
+			errx(1, "ar_start_gzip:  impossible");
+		}
+		close(fds[0]);
+		close(fds[1]);
+		if (execlp(gzip_program, gzip_program, gzip_flags, NULL) < 0)
+			err(1, "could not exec");
+		/* NOTREACHED */
+	}
+}
diff --git a/pax/ar_subs.c b/pax/ar_subs.c
new file mode 100644
index 0000000..95bd7d5
--- /dev/null
+++ b/pax/ar_subs.c
@@ -0,0 +1,1288 @@
+/*	$OpenBSD: ar_subs.c,v 1.13 1997/09/16 21:20:35 niklas Exp $	*/
+/*	$NetBSD: ar_subs.c,v 1.5 1995/03/21 09:07:06 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)ar_subs.c	8.2 (Berkeley) 4/18/94";
+#else
+static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: ar_subs.c,v 1.13 1997/09/16 21:20:35 niklas Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <signal.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "pax.h"
+#include "extern.h"
+
+static void wr_archive __P((register ARCHD *, int is_app));
+static int get_arc __P((void));
+static int next_head __P((register ARCHD *));
+extern sigset_t s_mask;
+
+char *chdname;
+
+/*
+ * Routines which control the overall operation modes of pax as specified by
+ * the user: list, append, read ...
+ */
+
+static char hdbuf[BLKMULT];		/* space for archive header on read */
+u_long flcnt;				/* number of files processed */
+
+/*
+ * list()
+ *	list the contents of an archive which match user supplied pattern(s)
+ *	(no pattern matches all).
+ */
+
+#ifdef __STDC__
+void
+list(void)
+#else
+void
+list()
+#endif
+{
+	register ARCHD *arcn;
+	register int res;
+	ARCHD archd;
+	time_t now;
+
+	arcn = &archd;
+	/*
+	 * figure out archive type; pass any format specific options to the
+	 * archive option processing routine; call the format init routine. We
+	 * also save current time for ls_list() so we do not make a system
+	 * call for each file we need to print. If verbose (vflag) start up
+	 * the name and group caches.
+	 */
+	if ((get_arc() < 0) || ((*frmt->options)() < 0) ||
+	    ((*frmt->st_rd)() < 0))
+		return;
+
+	if (vflag && ((uidtb_start() < 0) || (gidtb_start() < 0)))
+		return;
+
+	now = time(NULL);
+
+	/*
+	 * step through the archive until the format says it is done
+	 */
+	while (next_head(arcn) == 0) {
+		/*
+		 * check for pattern, and user specified options match.
+		 * When all patterns are matched we are done.
+		 */
+		if ((res = pat_match(arcn)) < 0)
+			break;
+
+		if ((res == 0) && (sel_chk(arcn) == 0)) {
+			/*
+			 * pattern resulted in a selected file
+			 */
+			if (pat_sel(arcn) < 0)
+				break;
+
+			/*
+			 * modify the name as requested by the user if name
+			 * survives modification, do a listing of the file
+			 */
+			if ((res = mod_name(arcn)) < 0)
+				break;
+			if (res == 0)
+				ls_list(arcn, now, stdout);
+		}
+
+		/*
+		 * skip to next archive format header using values calculated
+		 * by the format header read routine
+		 */
+		if (rd_skip(arcn->skip + arcn->pad) == 1)
+			break;
+	}
+
+	/*
+	 * all done, let format have a chance to cleanup, and make sure that
+	 * the patterns supplied by the user were all matched
+	 */
+	(void)(*frmt->end_rd)();
+	(void)sigprocmask(SIG_BLOCK, &s_mask, NULL);
+	ar_close();
+	pat_chk();
+}
+
+/*
+ * extract()
+ *	extract the member(s) of an archive as specified by user supplied
+ *	pattern(s) (no patterns extracts all members)
+ */
+
+#ifdef __STDC__
+void
+extract(void)
+#else
+void
+extract()
+#endif
+{
+	register ARCHD *arcn;
+	register int res;
+	off_t cnt;
+	ARCHD archd;
+	struct stat sb;
+	int fd;
+	time_t now;
+
+	arcn = &archd;
+	/*
+	 * figure out archive type; pass any format specific options to the
+	 * archive option processing routine; call the format init routine;
+	 * start up the directory modification time and access mode database
+	 */
+	if ((get_arc() < 0) || ((*frmt->options)() < 0) ||
+	    ((*frmt->st_rd)() < 0) || (dir_start() < 0))
+		return;
+
+	/*
+	 * When we are doing interactive rename, we store the mapping of names
+	 * so we can fix up hard links files later in the archive.
+	 */
+	if (iflag && (name_start() < 0))
+		return;
+
+	now = time(NULL);
+
+	/*
+	 * step through each entry on the archive until the format read routine
+	 * says it is done
+	 */
+	while (next_head(arcn) == 0) {
+
+		/*
+		 * check for pattern, and user specified options match. When
+		 * all the patterns are matched we are done
+		 */
+		if ((res = pat_match(arcn)) < 0)
+			break;
+
+		if ((res > 0) || (sel_chk(arcn) != 0)) {
+			/*
+			 * file is not selected. skip past any file data and
+			 * padding and go back for the next archive member
+			 */
+			(void)rd_skip(arcn->skip + arcn->pad);
+			continue;
+		}
+
+		/*
+		 * with -u or -D only extract when the archive member is newer
+		 * than the file with the same name in the file system (nos
+		 * test of being the same type is required).
+		 * NOTE: this test is done BEFORE name modifications as
+		 * specified by pax. this operation can be confusing to the
+		 * user who might expect the test to be done on an existing
+		 * file AFTER the name mod. In honesty the pax spec is probably
+		 * flawed in this respect.
+		 */
+		if ((uflag || Dflag) && ((lstat(arcn->name, &sb) == 0))) {
+			if (uflag && Dflag) {
+				if ((arcn->sb.st_mtime <= sb.st_mtime) &&
+				    (arcn->sb.st_ctime <= sb.st_ctime)) {
+					(void)rd_skip(arcn->skip + arcn->pad);
+					continue;
+				}
+			} else if (Dflag) {
+				if (arcn->sb.st_ctime <= sb.st_ctime) {
+					(void)rd_skip(arcn->skip + arcn->pad);
+					continue;
+				}
+			} else if (arcn->sb.st_mtime <= sb.st_mtime) {
+				(void)rd_skip(arcn->skip + arcn->pad);
+				continue;
+			}
+		}
+
+		/*
+		 * this archive member is now been selected. modify the name.
+		 */
+		if ((pat_sel(arcn) < 0) || ((res = mod_name(arcn)) < 0))
+			break;
+		if (res > 0) {
+			/*
+			 * a bad name mod, skip and purge name from link table
+			 */
+			purg_lnk(arcn);
+			(void)rd_skip(arcn->skip + arcn->pad);
+			continue;
+		}
+
+		/*
+		 * Non standard -Y and -Z flag. When the exisiting file is
+		 * same age or newer skip
+		 */
+		if ((Yflag || Zflag) && ((lstat(arcn->name, &sb) == 0))) {
+			if (Yflag && Zflag) {
+				if ((arcn->sb.st_mtime <= sb.st_mtime) &&
+				    (arcn->sb.st_ctime <= sb.st_ctime)) {
+					(void)rd_skip(arcn->skip + arcn->pad);
+					continue;
+				}
+			} else if (Yflag) {
+				if (arcn->sb.st_ctime <= sb.st_ctime) {
+					(void)rd_skip(arcn->skip + arcn->pad);
+					continue;
+				}
+			} else if (arcn->sb.st_mtime <= sb.st_mtime) {
+				(void)rd_skip(arcn->skip + arcn->pad);
+				continue;
+			}
+		}
+
+		if (vflag) {
+			if (vflag > 1)
+				ls_list(arcn, now, stderr);
+			else {
+				(void)fputs(arcn->name, stderr);
+				vfpart = 1;
+			}
+		}
+
+		/*
+		 * if required, chdir around.
+		 */
+		if ((arcn->pat != NULL) && (arcn->pat->chdname != NULL))
+			if (chdir(arcn->pat->chdname) != 0)
+				syswarn(1, errno, "Cannot chdir to %s",
+				    arcn->pat->chdname);
+
+		/*
+		 * all ok, extract this member based on type
+		 */
+		if ((arcn->type != PAX_REG) && (arcn->type != PAX_CTG)) {
+			/*
+			 * process archive members that are not regular files.
+			 * throw out padding and any data that might follow the
+			 * header (as determined by the format).
+			 */
+			if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG))
+				res = lnk_creat(arcn);
+			else
+				res = node_creat(arcn);
+
+			(void)rd_skip(arcn->skip + arcn->pad);
+			if (res < 0)
+				purg_lnk(arcn);
+
+			if (vflag && vfpart) {
+				(void)putc('\n', stderr);
+				vfpart = 0;
+			}
+			continue;
+		}
+		/*
+		 * we have a file with data here. If we can not create it, skip
+		 * over the data and purge the name from hard link table
+		 */
+		if ((fd = file_creat(arcn)) < 0) {
+			(void)rd_skip(arcn->skip + arcn->pad);
+			purg_lnk(arcn);
+			continue;
+		}
+		/*
+		 * extract the file from the archive and skip over padding and
+		 * any unprocessed data
+		 */
+		res = (*frmt->rd_data)(arcn, fd, &cnt);
+		file_close(arcn, fd);
+		if (vflag && vfpart) {
+			(void)putc('\n', stderr);
+			vfpart = 0;
+		}
+		if (!res)
+			(void)rd_skip(cnt + arcn->pad);
+
+		/*
+		 * if required, chdir around.
+		 */
+		if ((arcn->pat != NULL) && (arcn->pat->chdname != NULL))
+			if (fchdir(cwdfd) != 0)
+				syswarn(1, errno,
+				    "Can't fchdir to starting directory");
+	}
+
+	/*
+	 * all done, restore directory modes and times as required; make sure
+	 * all patterns supplied by the user were matched; block off signals
+	 * to avoid chance for multiple entry into the cleanup code.
+	 */
+	(void)(*frmt->end_rd)();
+	(void)sigprocmask(SIG_BLOCK, &s_mask, NULL);
+	ar_close();
+	proc_dir();
+	pat_chk();
+}
+
+/*
+ * wr_archive()
+ *	Write an archive. used in both creating a new archive and appends on
+ *	previously written archive.
+ */
+
+#ifdef __STDC__
+static void
+wr_archive(register ARCHD *arcn, int is_app)
+#else
+static void
+wr_archive(arcn, is_app)
+	register ARCHD *arcn;
+	int is_app;
+#endif
+{
+	register int res;
+	register int hlk;
+	register int wr_one;
+	off_t cnt;
+	int (*wrf)();
+	int fd = -1;
+	time_t now;
+
+	/*
+	 * if this format supports hard link storage, start up the database
+	 * that detects them.
+	 */
+	if (((hlk = frmt->hlk) == 1) && (lnk_start() < 0))
+		return;
+
+	/*
+	 * start up the file traversal code and format specific write
+	 */
+	if ((ftree_start() < 0) || ((*frmt->st_wr)() < 0))
+		return;
+	wrf = frmt->wr;
+
+	/*
+	 * When we are doing interactive rename, we store the mapping of names
+	 * so we can fix up hard links files later in the archive.
+	 */
+	if (iflag && (name_start() < 0))
+		return;
+
+	/*
+	 * if this not append, and there are no files, we do no write a trailer
+	 */
+	wr_one = is_app;
+
+	now = time(NULL);
+
+	/*
+	 * while there are files to archive, process them one at at time
+	 */
+	while (next_file(arcn) == 0) {
+		/*
+		 * check if this file meets user specified options match.
+		 */
+		if (sel_chk(arcn) != 0)
+			continue;
+		fd = -1;
+		if (uflag) {
+			/*
+			 * only archive if this file is newer than a file with
+			 * the same name that is already stored on the archive
+			 */
+			if ((res = chk_ftime(arcn)) < 0)
+				break;
+			if (res > 0)
+				continue;
+		}
+
+		/*
+		 * this file is considered selected now. see if this is a hard
+		 * link to a file already stored
+		 */
+		ftree_sel(arcn);
+		if (hlk && (chk_lnk(arcn) < 0))
+			break;
+
+		if ((arcn->type == PAX_REG) || (arcn->type == PAX_HRG) ||
+		    (arcn->type == PAX_CTG)) {
+			/*
+			 * we will have to read this file. by opening it now we
+			 * can avoid writing a header to the archive for a file
+			 * we were later unable to read (we also purge it from
+			 * the link table).
+			 */
+			if ((fd = open(arcn->org_name, O_RDONLY, 0)) < 0) {
+				syswarn(1,errno, "Unable to open %s to read",
+					arcn->org_name);
+				purg_lnk(arcn);
+				continue;
+			}
+		}
+
+		/*
+		 * Now modify the name as requested by the user
+		 */
+		if ((res = mod_name(arcn)) < 0) {
+			/*
+			 * name modification says to skip this file, close the
+			 * file and purge link table entry
+			 */
+			rdfile_close(arcn, &fd);
+			purg_lnk(arcn);
+			break;
+		}
+
+		if ((res > 0) || (docrc && (set_crc(arcn, fd) < 0))) {
+			/*
+			 * unable to obtain the crc we need, close the file,
+			 * purge link table entry 
+			 */
+			rdfile_close(arcn, &fd);
+			purg_lnk(arcn);
+			continue;
+		}
+
+		if (vflag) {
+			if (vflag > 1)
+				ls_list(arcn, now, stderr);
+			else {
+				(void)fputs(arcn->name, stderr);
+				vfpart = 1;
+			}
+		}
+		++flcnt;
+
+		/*
+		 * looks safe to store the file, have the format specific
+		 * routine write routine store the file header on the archive
+		 */
+		if ((res = (*wrf)(arcn)) < 0) {
+			rdfile_close(arcn, &fd);
+			break;
+		}
+		wr_one = 1;
+		if (res > 0) {
+			/* 
+			 * format write says no file data needs to be stored
+			 * so we are done messing with this file
+			 */
+			if (vflag && vfpart) {
+				(void)putc('\n', stderr);
+				vfpart = 0;
+			}
+			rdfile_close(arcn, &fd);
+			continue;
+		}
+
+		/*
+		 * Add file data to the archive, quit on write error. if we
+		 * cannot write the entire file contents to the archive we
+		 * must pad the archive to replace the missing file data
+		 * (otherwise during an extract the file header for the file
+		 * which FOLLOWS this one will not be where we expect it to
+		 * be).
+		 */
+		res = (*frmt->wr_data)(arcn, fd, &cnt);
+		rdfile_close(arcn, &fd);
+		if (vflag && vfpart) {
+			(void)putc('\n', stderr);
+			vfpart = 0;
+		}
+		if (res < 0)
+			break;
+
+		/*
+		 * pad as required, cnt is number of bytes not written
+		 */
+		if (((cnt > 0) && (wr_skip(cnt) < 0)) ||
+		    ((arcn->pad > 0) && (wr_skip(arcn->pad) < 0)))
+			break;
+	}
+
+	/*
+	 * tell format to write trailer; pad to block boundry; reset directory
+	 * mode/access times, and check if all patterns supplied by the user
+	 * were matched. block off signals to avoid chance for multiple entry
+	 * into the cleanup code
+	 */
+	if (wr_one) {
+		(*frmt->end_wr)();
+		wr_fin();
+	}
+	(void)sigprocmask(SIG_BLOCK, &s_mask, NULL);
+	ar_close();
+	if (tflag)
+		proc_dir();
+	ftree_chk();
+}
+
+/*
+ * append()
+ *	Add file to previously written archive. Archive format specified by the
+ *	user must agree with archive. The archive is read first to collect
+ *	modification times (if -u) and locate the archive trailer. The archive
+ *	is positioned in front of the record with the trailer and wr_archive()
+ *	is called to add the new members.
+ *	PAX IMPLEMENTATION DETAIL NOTE:
+ *	-u is implemented by adding the new members to the end of the archive.
+ *	Care is taken so that these do not end up as links to the older 
+ *	version of the same file already stored in the archive. It is expected
+ *	when extraction occurs these newer versions will over-write the older
+ *	ones stored "earlier" in the archive (this may be a bad assumption as
+ *	it depends on the implementation of the program doing the extraction).
+ *	It is really difficult to splice in members without either re-writing
+ *	the entire archive (from the point were the old version was), or having
+ *	assistance of the format specification in terms of a special update
+ *	header that invalidates a previous archive record. The posix spec left
+ *	the method used to implement -u unspecified. This pax is able to
+ *	over write existing files that it creates.
+ */
+
+#ifdef __STDC__
+void
+append(void)
+#else
+void
+append()
+#endif
+{
+	register ARCHD *arcn;
+	register int res;
+	ARCHD archd;
+	FSUB *orgfrmt;
+	int udev;
+	off_t tlen;
+
+	arcn = &archd;
+	orgfrmt = frmt;
+
+	/*
+	 * Do not allow an append operation if the actual archive is of a
+	 * different format than the user specified foramt.
+	 */
+	if (get_arc() < 0)
+		return;
+	if ((orgfrmt != NULL) && (orgfrmt != frmt)) {
+		paxwarn(1, "Cannot mix current archive format %s with %s",
+		    frmt->name, orgfrmt->name);
+		return;
+	}
+
+	/*
+	 * pass the format any options and start up format
+	 */
+	if (((*frmt->options)() < 0) || ((*frmt->st_rd)() < 0))
+		return;
+
+	/*
+	 * if we only are adding members that are newer, we need to save the
+	 * mod times for all files we see.
+	 */
+	if (uflag && (ftime_start() < 0))
+		return;
+
+	/*
+	 * some archive formats encode hard links by recording the device and
+	 * file serial number (inode) but copy the file anyway (multiple times)
+	 * to the archive. When we append, we run the risk that newly added
+	 * files may have the same device and inode numbers as those recorded
+	 * on the archive but during a previous run. If this happens, when the
+	 * archive is extracted we get INCORRECT hard links. We avoid this by
+	 * remapping the device numbers so that newly added files will never
+	 * use the same device number as one found on the archive. remapping
+	 * allows new members to safely have links among themselves. remapping
+	 * also avoids problems with file inode (serial number) truncations
+	 * when the inode number is larger than storage space in the archive
+	 * header. See the remap routines for more details.
+	 */
+	if ((udev = frmt->udev) && (dev_start() < 0))
+		return;
+
+	/*
+	 * reading the archive may take a long time. If verbose tell the user
+	 */
+	if (vflag) {
+		(void)fprintf(stderr,
+			"%s: Reading archive to position at the end...", argv0);
+		vfpart = 1;
+	}
+
+	/*
+	 * step through the archive until the format says it is done
+	 */
+	while (next_head(arcn) == 0) {
+		/*
+		 * check if this file meets user specified options.
+		 */
+		if (sel_chk(arcn) != 0) {
+			if (rd_skip(arcn->skip + arcn->pad) == 1)
+				break;
+			continue;
+		}
+
+		if (uflag) {
+			/*
+			 * see if this is the newest version of this file has
+			 * already been seen, if so skip.
+			 */
+			if ((res = chk_ftime(arcn)) < 0)
+				break;
+			if (res > 0) {
+				if (rd_skip(arcn->skip + arcn->pad) == 1)
+					break;
+				continue;
+			}
+		}
+
+		/*
+		 * Store this device number. Device numbers seen during the
+		 * read phase of append will cause newly appended files with a
+		 * device number seen in the old part of the archive to be
+		 * remapped to an unused device number.
+		 */
+		if ((udev && (add_dev(arcn) < 0)) ||
+		    (rd_skip(arcn->skip + arcn->pad) == 1))
+			break;
+	}
+
+	/*
+	 * done, finish up read and get the number of bytes to back up so we
+	 * can add new members. The format might have used the hard link table,
+	 * purge it.
+	 */
+	tlen = (*frmt->end_rd)();
+	lnk_end();
+
+	/*
+	 * try to postion for write, if this fails quit. if any error occurs,
+	 * we will refuse to write
+	 */
+	if (appnd_start(tlen) < 0)
+		return;
+
+	/*
+	 * tell the user we are done reading.
+	 */
+	if (vflag && vfpart) {
+		(void)fputs("done.\n", stderr);
+		vfpart = 0;
+	}
+       
+	/*
+	 * go to the writing phase to add the new members
+	 */
+	wr_archive(arcn, 1);
+}
+
+/*
+ * archive()
+ *	write a new archive
+ */
+
+#ifdef __STDC__
+void
+archive(void)
+#else
+void
+archive()
+#endif
+{
+	ARCHD archd;
+
+	/*
+	 * if we only are adding members that are newer, we need to save the
+	 * mod times for all files; set up for writing; pass the format any
+	 * options write the archive
+	 */
+	if ((uflag && (ftime_start() < 0)) || (wr_start() < 0))
+		return;
+	if ((*frmt->options)() < 0)
+		return;
+
+	wr_archive(&archd, 0);
+}
+
+/*
+ * copy()
+ *	copy files from one part of the file system to another. this does not
+ *	use any archive storage. The EFFECT OF THE COPY IS THE SAME as if an
+ *	archive was written and then extracted in the destination directory
+ *	(except the files are forced to be under the destination directory).
+ */
+
+#ifdef __STDC__
+void
+copy(void)
+#else
+void
+copy()
+#endif
+{
+	register ARCHD *arcn;
+	register int res;
+	register int fddest;
+	register char *dest_pt;
+	register int dlen;
+	register int drem;
+	int fdsrc = -1;
+	struct stat sb;
+	ARCHD archd;
+	char dirbuf[PAXPATHLEN+1];
+
+	arcn = &archd;
+	/*
+	 * set up the destination dir path and make sure it is a directory. We
+	 * make sure we have a trailing / on the destination
+	 */
+	dlen = l_strncpy(dirbuf, dirptr, sizeof(dirbuf) - 1);
+	dest_pt = dirbuf + dlen;
+	if (*(dest_pt-1) != '/') {
+		*dest_pt++ = '/';
+		++dlen;
+	}
+	*dest_pt = '\0';
+	drem = PAXPATHLEN - dlen;
+
+	if (stat(dirptr, &sb) < 0) {
+		syswarn(1, errno, "Cannot access destination directory %s",
+			dirptr);
+		return;
+	}
+	if (!S_ISDIR(sb.st_mode)) {
+		paxwarn(1, "Destination is not a directory %s", dirptr);
+		return;
+	}
+
+	/*
+	 * start up the hard link table; file traversal routines and the
+	 * modification time and access mode database 
+	 */
+	if ((lnk_start() < 0) || (ftree_start() < 0) || (dir_start() < 0))
+		return;
+
+	/*
+	 * When we are doing interactive rename, we store the mapping of names
+	 * so we can fix up hard links files later in the archive.
+	 */
+	if (iflag && (name_start() < 0))
+		return;
+
+	/*
+	 * set up to cp file trees
+	 */
+	cp_start();
+
+	/*
+	 * while there are files to archive, process them
+	 */
+	while (next_file(arcn) == 0) {
+		fdsrc = -1;
+
+		/*
+		 * check if this file meets user specified options
+		 */
+		if (sel_chk(arcn) != 0)
+			continue;
+
+		/*
+		 * if there is already a file in the destination directory with
+		 * the same name and it is newer, skip the one stored on the
+		 * archive.
+		 * NOTE: this test is done BEFORE name modifications as
+		 * specified by pax. this can be confusing to the user who
+		 * might expect the test to be done on an existing file AFTER
+		 * the name mod. In honesty the pax spec is probably flawed in
+		 * this respect
+		 */
+		if (uflag || Dflag) {
+			/*
+			 * create the destination name
+			 */
+			if (*(arcn->name) == '/')
+				res = 1;
+			else
+				res = 0;
+			if ((arcn->nlen - res) > drem) {
+				paxwarn(1, "Destination pathname too long %s",
+					arcn->name);
+				continue;
+			}
+			(void)strncpy(dest_pt, arcn->name + res, drem);
+			dirbuf[PAXPATHLEN] = '\0';
+
+			/*
+			 * if existing file is same age or newer skip
+			 */
+			res = lstat(dirbuf, &sb);
+			*dest_pt = '\0';
+
+		    	if (res == 0) {
+				if (uflag && Dflag) {
+					if ((arcn->sb.st_mtime<=sb.st_mtime) &&
+			    		    (arcn->sb.st_ctime<=sb.st_ctime))
+						continue;
+				} else if (Dflag) {
+					if (arcn->sb.st_ctime <= sb.st_ctime)
+						continue;
+				} else if (arcn->sb.st_mtime <= sb.st_mtime)
+					continue;
+			}
+		}
+
+		/*
+		 * this file is considered selected. See if this is a hard link
+		 * to a previous file; modify the name as requested by the
+		 * user; set the final destination.
+		 */
+		ftree_sel(arcn);
+		if ((chk_lnk(arcn) < 0) || ((res = mod_name(arcn)) < 0))
+			break;
+		if ((res > 0) || (set_dest(arcn, dirbuf, dlen) < 0)) {
+			/*
+			 * skip file, purge from link table
+			 */
+			purg_lnk(arcn);
+			continue;
+		}
+
+		/*
+		 * Non standard -Y and -Z flag. When the exisiting file is
+		 * same age or newer skip
+		 */
+		if ((Yflag || Zflag) && ((lstat(arcn->name, &sb) == 0))) {
+			if (Yflag && Zflag) {
+				if ((arcn->sb.st_mtime <= sb.st_mtime) &&
+				    (arcn->sb.st_ctime <= sb.st_ctime))
+					continue;
+			} else if (Yflag) {
+				if (arcn->sb.st_ctime <= sb.st_ctime)
+					continue;
+			} else if (arcn->sb.st_mtime <= sb.st_mtime)
+				continue;
+		}
+
+		if (vflag) {
+			(void)fputs(arcn->name, stderr);
+			vfpart = 1;
+		}
+		++flcnt;
+
+		/*
+		 * try to create a hard link to the src file if requested
+		 * but make sure we are not trying to overwrite ourselves.
+		 */
+		if (lflag)
+			res = cross_lnk(arcn);
+		else
+			res = chk_same(arcn);
+		if (res <= 0) {
+			if (vflag && vfpart) {
+				(void)putc('\n', stderr);
+				vfpart = 0;
+			}
+			continue;
+		}
+
+		/*
+		 * have to create a new file
+		 */
+		if ((arcn->type != PAX_REG) && (arcn->type != PAX_CTG)) {
+			/*
+			 * create a link or special file
+			 */
+			if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG))
+				res = lnk_creat(arcn);
+			else
+				res = node_creat(arcn);
+			if (res < 0)
+				purg_lnk(arcn);
+			if (vflag && vfpart) {
+				(void)putc('\n', stderr);
+				vfpart = 0;
+			}
+			continue;
+		}
+
+		/*
+		 * have to copy a regular file to the destination directory.
+		 * first open source file and then create the destination file
+		 */
+		if ((fdsrc = open(arcn->org_name, O_RDONLY, 0)) < 0) {
+			syswarn(1, errno, "Unable to open %s to read",
+			    arcn->org_name);
+			purg_lnk(arcn);
+			continue;
+		}
+		if ((fddest = file_creat(arcn)) < 0) {
+			rdfile_close(arcn, &fdsrc);
+			purg_lnk(arcn);
+			continue;
+		}
+
+		/*
+		 * copy source file data to the destination file
+		 */
+		cp_file(arcn, fdsrc, fddest);
+		file_close(arcn, fddest);
+		rdfile_close(arcn, &fdsrc);
+
+		if (vflag && vfpart) {
+			(void)putc('\n', stderr);
+			vfpart = 0;
+		}
+	}
+
+	/*
+	 * restore directory modes and times as required; make sure all
+	 * patterns were selected block off signals to avoid chance for
+	 * multiple entry into the cleanup code.
+	 */
+	(void)sigprocmask(SIG_BLOCK, &s_mask, NULL);
+	ar_close();
+	proc_dir();
+	ftree_chk();
+}
+
+/*
+ * next_head()
+ *	try to find a valid header in the archive. Uses format specific
+ *	routines to extract the header and id the trailer. Trailers may be
+ *	located within a valid header or in an invalid header (the location
+ *	is format specific. The inhead field from the option table tells us
+ *	where to look for the trailer).
+ *	We keep reading (and resyncing) until we get enough contiguous data
+ *	to check for a header. If we cannot find one, we shift by a byte
+ *	add a new byte from the archive to the end of the buffer and try again.
+ *	If we get a read error, we throw out what we have (as we must have
+ *	contiguous data) and start over again.
+ *	ASSUMED: headers fit within a BLKMULT header.
+ * Return:
+ *	0 if we got a header, -1 if we are unable to ever find another one
+ *	(we reached the end of input, or we reached the limit on retries. see
+ *	the specs for rd_wrbuf() for more details)
+ */
+
+#ifdef __STDC__
+static int
+next_head(register ARCHD *arcn)
+#else
+static int
+next_head(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	register int ret;
+	register char *hdend;
+	register int res;
+	register int shftsz;
+	register int hsz;
+	register int in_resync = 0; 	/* set when we are in resync mode */
+	int cnt = 0;			/* counter for trailer function */
+	int first = 1;			/* on 1st read, EOF isn't premature. */
+
+	/*
+	 * set up initial conditions, we want a whole frmt->hsz block as we
+	 * have no data yet.
+	 */
+	res = hsz = frmt->hsz;
+	hdend = hdbuf;
+	shftsz = hsz - 1;
+	for(;;) {
+		/*
+		 * keep looping until we get a contiguous FULL buffer
+		 * (frmt->hsz is the proper size)
+		 */
+		for (;;) {
+			if ((ret = rd_wrbuf(hdend, res)) == res)
+				break;
+
+			/*
+			 * If we read 0 bytes (EOF) from an archive when we
+			 * expect to find a header, we have stepped upon
+			 * an archive without the customary block of zeroes
+			 * end marker.  It's just stupid to error out on
+			 * them, so exit gracefully.
+			 */
+			if (first && ret == 0)
+				return(-1);
+			first = 0;
+
+			/*
+			 * some kind of archive read problem, try to resync the
+			 * storage device, better give the user the bad news.
+			 */
+			if ((ret == 0) || (rd_sync() < 0)) {
+				paxwarn(1,"Premature end of file on archive read");
+				return(-1);
+			}
+			if (!in_resync) {
+				if (act == APPND) {
+					paxwarn(1,
+					  "Archive I/O error, cannot continue");
+					return(-1);
+				}
+				paxwarn(1,"Archive I/O error. Trying to recover.");
+				++in_resync;
+			}
+
+			/*
+			 * oh well, throw it all out and start over
+			 */
+			res = hsz;
+			hdend = hdbuf;
+		}
+
+		/*
+		 * ok we have a contiguous buffer of the right size. Call the
+		 * format read routine. If this was not a valid header and this
+		 * format stores trailers outside of the header, call the
+		 * format specific trailer routine to check for a trailer. We
+		 * have to watch out that we do not mis-identify file data or
+		 * block padding as a header or trailer. Format specific
+		 * trailer functions must NOT check for the trailer while we
+		 * are running in resync mode. Some trailer functions may tell
+		 * us that this block cannot contain a valid header either, so
+		 * we then throw out the entire block and start over.
+		 */
+		if ((*frmt->rd)(arcn, hdbuf) == 0)
+			break;
+
+		if (!frmt->inhead) {
+			/*
+			 * this format has trailers outside of valid headers
+			 */
+			if ((ret = (*frmt->trail)(hdbuf,in_resync,&cnt)) == 0){
+				/*
+				 * valid trailer found, drain input as required
+				 */
+				ar_drain();
+				return(-1);
+			}
+
+			if (ret == 1) {
+				/*
+				 * we are in resync and we were told to throw
+				 * the whole block out because none of the
+				 * bytes in this block can be used to form a
+				 * valid header
+				 */
+				res = hsz;
+				hdend = hdbuf;
+				continue;
+			}
+		}
+
+		/*
+		 * Brute force section.
+		 * not a valid header. We may be able to find a header yet. So
+		 * we shift over by one byte, and set up to read one byte at a
+		 * time from the archive and place it at the end of the buffer.
+		 * We will keep moving byte at a time until we find a header or
+		 * get a read error and have to start over.
+		 */
+		if (!in_resync) {
+			if (act == APPND) {
+				paxwarn(1,"Unable to append, archive header flaw");
+				return(-1);
+			}
+			paxwarn(1,"Invalid header, starting valid header search.");
+			++in_resync;
+		}
+		memmove(hdbuf, hdbuf+1, shftsz);
+		res = 1;
+		hdend = hdbuf + shftsz;
+	}
+
+	/*
+	 * ok got a valid header, check for trailer if format encodes it in the
+	 * the header. NOTE: the parameters are different than trailer routines
+	 * which encode trailers outside of the header!
+	 */
+	if (frmt->inhead && ((*frmt->trail)(arcn) == 0)) {
+		/*
+		 * valid trailer found, drain input as required
+		 */
+		ar_drain();
+		return(-1);
+	}
+
+	++flcnt;
+	return(0);
+}
+
+/*
+ * get_arc()
+ *	Figure out what format an archive is. Handles archive with flaws by
+ *	brute force searches for a legal header in any supported format. The
+ *	format id routines have to be careful to NOT mis-identify a format.
+ *	ASSUMED: headers fit within a BLKMULT header.
+ * Return:
+ *	0 if archive found -1 otherwise
+ */
+
+#ifdef __STDC__
+static int
+get_arc(void)
+#else
+static int
+get_arc()
+#endif
+{
+	register int i;
+	register int hdsz = 0;
+	register int res;
+	register int minhd = BLKMULT;
+	char *hdend;
+	int notice = 0;
+
+	/*
+	 * find the smallest header size in all archive formats and then set up
+	 * to read the archive.
+	 */
+	for (i = 0; ford[i] >= 0; ++i) {
+		if (fsub[ford[i]].hsz < minhd)
+			minhd = fsub[ford[i]].hsz;
+	}
+	if (rd_start() < 0)
+		return(-1);
+	res = BLKMULT;
+	hdsz = 0;
+	hdend = hdbuf;
+	for(;;) {
+		for (;;) {
+			/*
+			 * fill the buffer with at least the smallest header
+			 */
+			i = rd_wrbuf(hdend, res);
+			if (i > 0)
+				hdsz += i;
+			if (hdsz >= minhd)
+				break;
+
+			/*
+			 * if we cannot recover from a read error quit
+			 */
+			if ((i == 0) || (rd_sync() < 0))
+				goto out;
+
+			/*
+			 * when we get an error none of the data we already
+			 * have can be used to create a legal header (we just
+			 * got an error in the middle), so we throw it all out
+			 * and refill the buffer with fresh data.
+			 */
+			res = BLKMULT;
+			hdsz = 0;
+			hdend = hdbuf;
+			if (!notice) {
+				if (act == APPND)
+					return(-1);
+				paxwarn(1,"Cannot identify format. Searching...");
+				++notice;
+			}
+		}
+
+		/*
+		 * we have at least the size of the smallest header in any
+		 * archive format. Look to see if we have a match. The array
+		 * ford[] is used to specify the header id order to reduce the
+		 * chance of incorrectly id'ing a valid header (some formats
+		 * may be subsets of each other and the order would then be
+		 * important).
+		 */
+		for (i = 0; ford[i] >= 0; ++i) {
+			if ((*fsub[ford[i]].id)(hdbuf, hdsz) < 0)
+				continue;
+			frmt = &(fsub[ford[i]]);
+			/* 
+			 * yuck, to avoid slow special case code in the extract
+			 * routines, just push this header back as if it was
+			 * not seen. We have left extra space at start of the
+			 * buffer for this purpose. This is a bit ugly, but
+			 * adding all the special case code is far worse.
+			 */
+			pback(hdbuf, hdsz);
+			return(0);
+		}
+
+		/*
+		 * We have a flawed archive, no match. we start searching, but
+		 * we never allow additions to flawed archives
+		 */
+		if (!notice) {
+			if (act == APPND)
+				return(-1);
+			paxwarn(1, "Cannot identify format. Searching...");
+			++notice;
+		}
+
+		/*
+		 * brute force search for a header that we can id.
+		 * we shift through byte at a time. this is slow, but we cannot
+		 * determine the nature of the flaw in the archive in a
+		 * portable manner
+		 */
+		if (--hdsz > 0) {
+			memmove(hdbuf, hdbuf+1, hdsz);
+			res = BLKMULT - hdsz;
+			hdend = hdbuf + hdsz;
+		} else {
+			res = BLKMULT;
+			hdend = hdbuf;
+			hdsz = 0;
+		}
+	}
+
+    out:
+	/*
+	 * we cannot find a header, bow, apologize and quit
+	 */
+	paxwarn(1, "Sorry, unable to determine archive format.");
+	return(-1);
+}
diff --git a/pax/buf_subs.c b/pax/buf_subs.c
new file mode 100644
index 0000000..6e13e8f
--- /dev/null
+++ b/pax/buf_subs.c
@@ -0,0 +1,1094 @@
+/*	$OpenBSD: buf_subs.c,v 1.7 1997/09/01 18:29:46 deraadt Exp $	*/
+/*	$NetBSD: buf_subs.c,v 1.5 1995/03/21 09:07:08 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)buf_subs.c	8.2 (Berkeley) 4/18/94";
+#else
+static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: buf_subs.c,v 1.7 1997/09/01 18:29:46 deraadt Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include "pax.h"
+#include "extern.h"
+
+/*
+ * routines which implement archive and file buffering
+ */
+
+#define MINFBSZ		512		/* default block size for hole detect */
+#define MAXFLT		10		/* default media read error limit */
+
+/*
+ * Need to change bufmem to dynamic allocation when the upper
+ * limit on blocking size is removed (though that will violate pax spec)
+ * MAXBLK define and tests will also need to be updated.
+ */
+static char bufmem[MAXBLK+BLKMULT];	/* i/o buffer + pushback id space */
+static char *buf;			/* normal start of i/o buffer */
+static char *bufend;			/* end or last char in i/o buffer */
+static char *bufpt;			/* read/write point in i/o buffer */
+int blksz = MAXBLK;			/* block input/output size in bytes */
+int wrblksz;				/* user spec output size in bytes */
+int maxflt = MAXFLT;			/* MAX consecutive media errors */
+int rdblksz;				/* first read blksize (tapes only) */
+off_t wrlimit;				/* # of bytes written per archive vol */
+off_t wrcnt;				/* # of bytes written on current vol */
+off_t rdcnt;				/* # of bytes read on current vol */
+
+/*
+ * wr_start()
+ *	set up the buffering system to operate in a write mode
+ * Return:
+ *	0 if ok, -1 if the user specified write block size violates pax spec
+ */
+
+#ifdef __STDC__
+int
+wr_start(void)
+#else
+int
+wr_start()
+#endif
+{
+	buf = &(bufmem[BLKMULT]);
+	/*
+	 * Check to make sure the write block size meets pax specs. If the user
+	 * does not specify a blocksize, we use the format default blocksize.
+	 * We must be picky on writes, so we do not allow the user to create an
+	 * archive that might be hard to read elsewhere. If all ok, we then
+	 * open the first archive volume
+	 */
+	if (!wrblksz)
+		wrblksz = frmt->bsz;
+	if (wrblksz > MAXBLK) {
+		paxwarn(1, "Write block size of %d too large, maximium is: %d",
+			wrblksz, MAXBLK);
+		return(-1);
+	}
+	if (wrblksz % BLKMULT) {
+		paxwarn(1, "Write block size of %d is not a %d byte multiple",
+		    wrblksz, BLKMULT);
+		return(-1);
+	}
+	if (wrblksz > MAXBLK_POSIX) {
+		paxwarn(0, "Write block size of %d larger than POSIX max %d, archive may not be portable",
+			wrblksz, MAXBLK_POSIX);
+		return(-1);
+	}
+
+	/*
+	 * we only allow wrblksz to be used with all archive operations 
+	 */
+	blksz = rdblksz = wrblksz;
+	if ((ar_open(arcname) < 0) && (ar_next() < 0))
+		return(-1);
+	wrcnt = 0;
+	bufend = buf + wrblksz;
+	bufpt = buf;
+	return(0);
+}
+
+/*
+ * rd_start()
+ *	set up buffering system to read an archive
+ * Return:
+ *	0 if ok, -1 otherwise
+ */
+
+#ifdef __STDC__
+int
+rd_start(void)
+#else
+int
+rd_start()
+#endif
+{
+	/*
+	 * leave space for the header pushback (see get_arc()). If we are
+	 * going to append and user specified a write block size, check it
+	 * right away
+	 */
+	buf = &(bufmem[BLKMULT]);
+	if ((act == APPND) && wrblksz) {
+		if (wrblksz > MAXBLK) {
+			paxwarn(1,"Write block size %d too large, maximium is: %d",
+				wrblksz, MAXBLK);
+			return(-1);
+		}
+		if (wrblksz % BLKMULT) {
+			paxwarn(1, "Write block size %d is not a %d byte multiple",
+		    	wrblksz, BLKMULT);
+			return(-1);
+		}
+	}
+
+	/*
+	 * open the archive
+	 */
+	if ((ar_open(arcname) < 0) && (ar_next() < 0))
+		return(-1);
+	bufend = buf + rdblksz;
+	bufpt = bufend;
+	rdcnt = 0;
+	return(0);
+}
+
+/*
+ * cp_start()
+ *	set up buffer system for copying within the file system
+ */
+
+#ifdef __STDC__
+void
+cp_start(void)
+#else
+void
+cp_start()
+#endif
+{
+	buf = &(bufmem[BLKMULT]);
+	rdblksz = blksz = MAXBLK;
+}
+
+/*
+ * appnd_start()
+ *	Set up the buffering system to append new members to an archive that
+ *	was just read. The last block(s) of an archive may contain a format
+ *	specific trailer. To append a new member, this trailer has to be
+ *	removed from the archive. The first byte of the trailer is replaced by
+ *	the start of the header of the first file added to the archive. The
+ *	format specific end read function tells us how many bytes to move
+ *	backwards in the archive to be positioned BEFORE the trailer. Two
+ *	different postions have to be adjusted, the O.S. file offset (e.g. the
+ *	position of the tape head) and the write point within the data we have
+ *	stored in the read (soon to become write) buffer. We may have to move
+ *	back several records (the number depends on the size of the archive
+ *	record and the size of the format trailer) to read up the record where
+ *	the first byte of the trailer is recorded. Trailers may span (and
+ *	overlap) record boundries.
+ *	We first calculate which record has the first byte of the trailer. We
+ *	move the OS file offset back to the start of this record and read it
+ *	up. We set the buffer write pointer to be at this byte (the byte where
+ *	the trailer starts). We then move the OS file pointer back to the
+ *	start of this record so a flush of this buffer will replace the record
+ *	in the archive.
+ *	A major problem is rewriting this last record. For archives stored
+ *	on disk files, this is trival. However, many devices are really picky
+ *	about the conditions under which they will allow a write to occur.
+ *	Often devices restrict the conditions where writes can be made writes,
+ *	so it may not be feasable to append archives stored on all types of
+ *	devices. 
+ * Return:
+ *	0 for success, -1 for failure
+ */
+
+#ifdef __STDC__
+int
+appnd_start(off_t skcnt)
+#else
+int
+appnd_start(skcnt)
+	off_t skcnt;
+#endif
+{
+	register int res;
+	off_t cnt;
+
+	if (exit_val != 0) {
+		paxwarn(0, "Cannot append to an archive that may have flaws.");
+		return(-1);
+	}
+	/*
+	 * if the user did not specify a write blocksize, inherit the size used
+	 * in the last archive volume read. (If a is set we still use rdblksz
+	 * until next volume, cannot shift sizes within a single volume).
+	 */
+	if (!wrblksz)
+		wrblksz = blksz = rdblksz;
+	else
+		blksz = rdblksz;
+
+	/*
+	 * make sure that this volume allows appends
+	 */
+	if (ar_app_ok() < 0)
+		return(-1);
+
+	/*
+	 * Calculate bytes to move back and move in front of record where we
+	 * need to start writing from. Remember we have to add in any padding
+	 * that might be in the buffer after the trailer in the last block. We
+	 * travel skcnt + padding ROUNDED UP to blksize.
+	 */
+	skcnt += bufend - bufpt;
+	if ((cnt = (skcnt/blksz) * blksz) < skcnt)
+		cnt += blksz;
+	if (ar_rev((off_t)cnt) < 0)
+		goto out;
+
+	/*
+	 * We may have gone too far if there is valid data in the block we are
+	 * now in front of, read up the block and position the pointer after
+	 * the valid data.
+	 */
+	if ((cnt -= skcnt) > 0) {
+		/*
+		 * watch out for stupid tape drives. ar_rev() will set rdblksz
+		 * to be real physical blocksize so we must loop until we get
+		 * the old rdblksz (now in blksz). If ar_rev() fouls up the
+		 * determination of the physical block size, we will fail.
+		 */
+		bufpt = buf;
+		bufend = buf + blksz;
+		while (bufpt < bufend) {
+			if ((res = ar_read(bufpt, rdblksz)) <= 0)
+				goto out;
+			bufpt += res;
+		}
+		if (ar_rev((off_t)(bufpt - buf)) < 0)
+			goto out;
+		bufpt = buf + cnt;
+		bufend = buf + blksz;
+	} else {
+		/*
+		 * buffer is empty
+		 */
+		bufend = buf + blksz;
+		bufpt = buf;
+	}
+	rdblksz = blksz;
+	rdcnt -= skcnt;
+	wrcnt = 0;
+
+	/*
+	 * At this point we are ready to write. If the device requires special
+	 * handling to write at a point were previously recorded data resides,
+	 * that is handled in ar_set_wr(). From now on we operate under normal
+	 * ARCHIVE mode (write) conditions
+	 */
+	if (ar_set_wr() < 0)
+		return(-1);
+	act = ARCHIVE;
+	return(0);
+
+    out:
+	paxwarn(1, "Unable to rewrite archive trailer, cannot append.");
+	return(-1);
+}
+	
+/*
+ * rd_sync()
+ *	A read error occurred on this archive volume. Resync the buffer and
+ *	try to reset the device (if possible) so we can continue to read. Keep
+ *	trying to do this until we get a valid read, or we reach the limit on
+ *	consecutive read faults (at which point we give up). The user can
+ *	adjust the read error limit through a command line option.
+ * Returns:
+ *	0 on success, and -1 on failure
+ */
+
+#ifdef __STDC__
+int
+rd_sync(void)
+#else
+int
+rd_sync()
+#endif
+{
+	register int errcnt = 0;
+	register int res;
+
+	/*
+	 * if the user says bail out on first fault, we are out of here...
+	 */
+	if (maxflt == 0)
+		return(-1);
+	if (act == APPND) {
+		paxwarn(1, "Unable to append when there are archive read errors.");
+		return(-1);
+	}
+
+	/*
+	 * poke at device and try to get past media error
+	 */
+	if (ar_rdsync() < 0) {
+		if (ar_next() < 0)
+			return(-1);
+		else
+			rdcnt = 0;
+	}
+
+	for (;;) {
+		if ((res = ar_read(buf, blksz)) > 0) {
+			/*
+			 * All right! got some data, fill that buffer
+			 */
+			bufpt = buf;
+			bufend = buf + res;
+			rdcnt += res;
+			return(0);
+		}
+
+		/*
+		 * Oh well, yet another failed read...
+		 * if error limit reached, ditch. o.w. poke device to move past
+		 * bad media and try again. if media is badly damaged, we ask
+		 * the poor (and upset user at this point) for the next archive
+		 * volume. remember the goal on reads is to get the most we
+		 * can extract out of the archive.
+		 */
+		if ((maxflt > 0) && (++errcnt > maxflt))
+			paxwarn(0,"Archive read error limit (%d) reached",maxflt);
+		else if (ar_rdsync() == 0)
+			continue;
+		if (ar_next() < 0)
+			break;
+		rdcnt = 0;
+		errcnt = 0;
+	}
+	return(-1);
+}
+
+/*
+ * pback()
+ *	push the data used during the archive id phase back into the I/O
+ *	buffer. This is required as we cannot be sure that the header does NOT
+ *	overlap a block boundry (as in the case we are trying to recover a
+ *	flawed archived). This was not designed to be used for any other
+ *	purpose. (What software engineering, HA!)
+ *	WARNING: do not even THINK of pback greater than BLKMULT, unless the
+ *	pback space is increased.
+ */
+
+#ifdef __STDC__
+void
+pback(char *pt, int cnt)
+#else
+void
+pback(pt, cnt)
+	char *pt;
+	int cnt;
+#endif
+{
+	bufpt -= cnt;
+	memcpy(bufpt, pt, cnt);
+	return;
+}
+
+/*
+ * rd_skip()
+ *	skip foward in the archive during a archive read. Used to get quickly
+ *	past file data and padding for files the user did NOT select.
+ * Return:
+ *	0 if ok, -1 failure, and 1 when EOF on the archive volume was detected.
+ */
+
+#ifdef __STDC__
+int
+rd_skip(off_t skcnt)
+#else
+int
+rd_skip(skcnt)
+	off_t skcnt;
+#endif
+{
+	off_t res;
+	off_t cnt;
+	off_t skipped = 0;
+
+	/*
+	 * consume what data we have in the buffer. If we have to move foward
+	 * whole records, we call the low level skip function to see if we can
+	 * move within the archive without doing the expensive reads on data we
+	 * do not want.
+	 */
+	if (skcnt == 0)
+		return(0);
+	res = MIN((bufend - bufpt), skcnt);
+	bufpt += res;
+	skcnt -= res;
+
+	/*
+	 * if skcnt is now 0, then no additional i/o is needed
+	 */
+	if (skcnt == 0)
+		return(0);
+
+	/*
+	 * We have to read more, calculate complete and partial record reads
+	 * based on rdblksz. we skip over "cnt" complete records
+	 */
+	res = skcnt%rdblksz;
+	cnt = (skcnt/rdblksz) * rdblksz;
+
+	/*
+	 * if the skip fails, we will have to resync. ar_fow will tell us
+	 * how much it can skip over. We will have to read the rest.
+	 */
+	if (ar_fow(cnt, &skipped) < 0)
+		return(-1);
+	res += cnt - skipped;
+	rdcnt += skipped;
+
+	/*
+	 * what is left we have to read (which may be the whole thing if
+	 * ar_fow() told us the device can only read to skip records);
+	 */
+	while (res > 0L) {
+		cnt = bufend - bufpt;
+		/*
+		 * if the read fails, we will have to resync
+		 */
+		if ((cnt <= 0) && ((cnt = buf_fill()) < 0))
+			return(-1);
+		if (cnt == 0)
+			return(1);
+		cnt = MIN(cnt, res);
+		bufpt += cnt;
+		res -= cnt;
+	}
+	return(0);
+}
+
+/* 
+ * wr_fin()
+ *	flush out any data (and pad if required) the last block. We always pad
+ *	with zero (even though we do not have to). Padding with 0 makes it a
+ *	lot easier to recover if the archive is damaged. zero paddding SHOULD
+ *	BE a requirement....
+ */
+
+#ifdef __STDC__
+void
+wr_fin(void)
+#else
+void
+wr_fin()
+#endif
+{
+	if (bufpt > buf) {
+		memset(bufpt, 0, bufend - bufpt);
+		bufpt = bufend;
+		(void)buf_flush(blksz);
+	}
+}
+
+/*
+ * wr_rdbuf()
+ *	fill the write buffer from data passed to it in a buffer (usually used
+ *	by format specific write routines to pass a file header). On failure we
+ *	punt. We do not allow the user to continue to write flawed archives.
+ *	We assume these headers are not very large (the memory copy we use is
+ *	a bit expensive). 
+ * Return:
+ *	0 if buffer was filled ok, -1 o.w. (buffer flush failure)
+ */
+
+#ifdef __STDC__
+int
+wr_rdbuf(register char *out, register int outcnt)
+#else
+int
+wr_rdbuf(out, outcnt)
+	register char *out;
+	register int outcnt;
+#endif
+{
+	register int cnt;
+
+	/*
+	 * while there is data to copy copy into the write buffer. when the
+	 * write buffer fills, flush it to the archive and continue
+	 */
+	while (outcnt > 0) {
+		cnt = bufend - bufpt;
+		if ((cnt <= 0) && ((cnt = buf_flush(blksz)) < 0))
+			return(-1);
+		/*
+		 * only move what we have space for
+		 */
+		cnt = MIN(cnt, outcnt);
+		memcpy(bufpt, out, cnt);
+		bufpt += cnt;
+		out += cnt;
+		outcnt -= cnt;
+	}
+	return(0);
+}
+
+/*
+ * rd_wrbuf()
+ *	copy from the read buffer into a supplied buffer a specified number of
+ *	bytes. If the read buffer is empty fill it and continue to copy.
+ *	usually used to obtain a file header for processing by a format
+ *	specific read routine.
+ * Return
+ *	number of bytes copied to the buffer, 0 indicates EOF on archive volume,
+ *	-1 is a read error
+ */
+
+#ifdef __STDC__
+int
+rd_wrbuf(register char *in, register int cpcnt)
+#else
+int
+rd_wrbuf(in, cpcnt)
+	register char *in;
+	register int cpcnt;
+#endif
+{
+	register int res;
+	register int cnt;
+	register int incnt = cpcnt;
+
+	/*
+	 * loop until we fill the buffer with the requested number of bytes
+	 */
+	while (incnt > 0) {
+		cnt = bufend - bufpt;
+		if ((cnt <= 0) && ((cnt = buf_fill()) <= 0)) {
+			/*
+			 * read error, return what we got (or the error if
+			 * no data was copied). The caller must know that an
+			 * error occured and has the best knowledge what to
+			 * do with it
+			 */
+			if ((res = cpcnt - incnt) > 0)
+				return(res);
+			return(cnt);
+		}
+
+		/*
+		 * calculate how much data to copy based on whats left and
+		 * state of buffer
+		 */
+		cnt = MIN(cnt, incnt);
+		memcpy(in, bufpt, cnt);
+		bufpt += cnt;
+		incnt -= cnt;
+		in += cnt;
+	}
+	return(cpcnt);
+}
+
+/*
+ * wr_skip()
+ *	skip foward during a write. In other words add padding to the file.
+ *	we add zero filled padding as it makes flawed archives much easier to
+ *	recover from. the caller tells us how many bytes of padding to add
+ *	This routine was not designed to add HUGE amount of padding, just small
+ *	amounts (a few 512 byte blocks at most)
+ * Return:
+ *	0 if ok, -1 if there was a buf_flush failure
+ */
+
+#ifdef __STDC__
+int
+wr_skip(off_t skcnt)
+#else
+int
+wr_skip(skcnt)
+	off_t skcnt;
+#endif
+{
+	register int cnt;
+
+	/*
+	 * loop while there is more padding to add
+	 */
+	while (skcnt > 0L) {
+		cnt = bufend - bufpt;
+		if ((cnt <= 0) && ((cnt = buf_flush(blksz)) < 0))
+			return(-1);
+		cnt = MIN(cnt, skcnt);
+		memset(bufpt, 0, cnt);
+		bufpt += cnt;
+		skcnt -= cnt;
+	}
+	return(0);
+}
+
+/*
+ * wr_rdfile()
+ *	fill write buffer with the contents of a file. We are passed an	open
+ *	file descriptor to the file an the archive structure that describes the
+ *	file we are storing. The variable "left" is modified to contain the
+ *	number of bytes of the file we were NOT able to write to the archive.
+ *	it is important that we always write EXACTLY the number of bytes that
+ *	the format specific write routine told us to. The file can also get
+ *	bigger, so reading to the end of file would create an improper archive,
+ *	we just detect this case and warn the user. We never create a bad
+ *	archive if we can avoid it. Of course trying to archive files that are
+ *	active is asking for trouble. It we fail, we pass back how much we
+ *	could NOT copy and let the caller deal with it.
+ * Return:
+ *	0 ok, -1 if archive write failure. a short read of the file returns a
+ *	0, but "left" is set to be greater than zero.
+ */
+
+#ifdef __STDC__
+int
+wr_rdfile(ARCHD *arcn, int ifd, off_t *left)
+#else
+int
+wr_rdfile(arcn, ifd, left)
+	ARCHD *arcn;
+	int ifd;
+	off_t *left;
+#endif
+{
+	register int cnt;
+	register int res = 0;
+	register off_t size = arcn->sb.st_size;
+	struct stat sb;
+
+	/*
+	 * while there are more bytes to write
+	 */
+	while (size > 0L) {
+		cnt = bufend - bufpt;
+		if ((cnt <= 0) && ((cnt = buf_flush(blksz)) < 0)) {
+			*left = size;
+			return(-1);
+		}
+		cnt = MIN(cnt, size);
+		if ((res = read(ifd, bufpt, cnt)) <= 0)
+			break;
+		size -= res;
+		bufpt += res;
+	}
+
+	/*
+	 * better check the file did not change during this operation
+	 * or the file read failed.
+	 */
+	if (res < 0)
+		syswarn(1, errno, "Read fault on %s", arcn->org_name);
+	else if (size != 0L)
+		paxwarn(1, "File changed size during read %s", arcn->org_name);
+	else if (fstat(ifd, &sb) < 0)
+		syswarn(1, errno, "Failed stat on %s", arcn->org_name);
+	else if (arcn->sb.st_mtime != sb.st_mtime)
+		paxwarn(1, "File %s was modified during copy to archive",
+			arcn->org_name);
+	*left = size;
+	return(0);
+}
+
+/*
+ * rd_wrfile()
+ *	extract the contents of a file from the archive. If we are unable to
+ *	extract the entire file (due to failure to write the file) we return
+ *	the numbers of bytes we did NOT process. This way the caller knows how
+ *	many bytes to skip past to find the next archive header. If the failure
+ *	was due to an archive read, we will catch that when we try to skip. If
+ *	the format supplies a file data crc value, we calculate the actual crc
+ *	so that it can be compared to the value stored in the header
+ * NOTE:
+ *	We call a special function to write the file. This function attempts to
+ *	restore file holes (blocks of zeros) into the file. When files are
+ *	sparse this saves space, and is a LOT faster. For non sparse files
+ *	the performance hit is small. As of this writing, no archive supports
+ *	information on where the file holes are.
+ * Return:
+ *	0 ok, -1 if archive read failure. if we cannot write the entire file,
+ *	we return a 0 but "left" is set to be the amount unwritten
+ */
+
+#ifdef __STDC__
+int
+rd_wrfile(ARCHD *arcn, int ofd, off_t *left)
+#else
+int
+rd_wrfile(arcn, ofd, left)
+	ARCHD *arcn;
+	int ofd;
+	off_t *left;
+#endif
+{
+	register int cnt = 0;
+	register off_t size = arcn->sb.st_size;
+	register int res = 0;
+	register char *fnm = arcn->name;
+	int isem = 1;
+	int rem;
+	int sz = MINFBSZ;
+ 	struct stat sb;
+	u_long crc = 0L;
+
+	/*
+	 * pass the blocksize of the file being written to the write routine,
+	 * if the size is zero, use the default MINFBSZ
+	 */
+	if (fstat(ofd, &sb) == 0) {
+		if (sb.st_blksize > 0)
+			sz = (int)sb.st_blksize;
+	} else
+		syswarn(0,errno,"Unable to obtain block size for file %s",fnm);
+	rem = sz;
+	*left = 0L;
+
+	/*
+	 * Copy the archive to the file the number of bytes specified. We have
+	 * to assume that we want to recover file holes as none of the archive
+	 * formats can record the location of file holes.
+	 */
+	while (size > 0L) {
+		cnt = bufend - bufpt;
+		/*
+		 * if we get a read error, we do not want to skip, as we may
+		 * miss a header, so we do not set left, but if we get a write
+		 * error, we do want to skip over the unprocessed data.
+		 */
+		if ((cnt <= 0) && ((cnt = buf_fill()) <= 0))
+			break;
+		cnt = MIN(cnt, size);
+		if ((res = file_write(ofd,bufpt,cnt,&rem,&isem,sz,fnm)) <= 0) {
+			*left = size;
+			break;
+		}
+
+		if (docrc) {
+			/*
+			 * update the actual crc value
+			 */
+			cnt = res;
+			while (--cnt >= 0)
+				crc += *bufpt++ & 0xff;
+		} else
+			bufpt += res;
+		size -= res;
+	}
+
+	/*
+	 * if the last block has a file hole (all zero), we must make sure this
+	 * gets updated in the file. We force the last block of zeros to be
+	 * written. just closing with the file offset moved foward may not put
+	 * a hole at the end of the file.
+	 */
+	if (isem && (arcn->sb.st_size > 0L))
+		file_flush(ofd, fnm, isem);
+
+	/*
+	 * if we failed from archive read, we do not want to skip
+	 */
+	if ((size > 0L) && (*left == 0L))
+		return(-1);
+
+	/*
+	 * some formats record a crc on file data. If so, then we compare the
+	 * calculated crc to the crc stored in the archive
+	 */
+	if (docrc && (size == 0L) && (arcn->crc != crc))
+		paxwarn(1,"Actual crc does not match expected crc %s",arcn->name);
+	return(0);
+}
+
+/*
+ * cp_file()
+ *	copy the contents of one file to another. used during -rw phase of pax
+ *	just as in rd_wrfile() we use a special write function to write the
+ *	destination file so we can properly copy files with holes.
+ */
+
+#ifdef __STDC__
+void
+cp_file(ARCHD *arcn, int fd1, int fd2)
+#else
+void
+cp_file(arcn, fd1, fd2)
+	ARCHD *arcn;
+	int fd1;
+	int fd2;
+#endif
+{
+	register int cnt;
+	register off_t cpcnt = 0L;
+	register int res = 0;
+	register char *fnm = arcn->name;
+	register int no_hole = 0;
+	int isem = 1;
+	int rem;
+	int sz = MINFBSZ;
+	struct stat sb;
+
+	/*
+	 * check for holes in the source file. If none, we will use regular
+	 * write instead of file write.
+	 */
+	 if (((off_t)(arcn->sb.st_blocks * BLKMULT)) >= arcn->sb.st_size)
+		++no_hole;
+
+	/*
+	 * pass the blocksize of the file being written to the write routine,
+	 * if the size is zero, use the default MINFBSZ
+	 */
+	if (fstat(fd2, &sb) == 0) {
+		if (sb.st_blksize > 0)
+			sz = sb.st_blksize;
+	} else
+		syswarn(0,errno,"Unable to obtain block size for file %s",fnm);
+	rem = sz;
+
+	/*
+	 * read the source file and copy to destination file until EOF
+	 */
+	for(;;) {
+		if ((cnt = read(fd1, buf, blksz)) <= 0)
+			break;
+		if (no_hole)
+			res = write(fd2, buf, cnt);
+		else
+			res = file_write(fd2, buf, cnt, &rem, &isem, sz, fnm);
+		if (res != cnt)
+			break;
+		cpcnt += cnt;
+	}
+
+	/*
+	 * check to make sure the copy is valid.
+	 */
+	if (res < 0)
+		syswarn(1, errno, "Failed write during copy of %s to %s",
+			arcn->org_name, arcn->name);
+	else if (cpcnt != arcn->sb.st_size)
+		paxwarn(1, "File %s changed size during copy to %s",
+			arcn->org_name, arcn->name);
+	else if (fstat(fd1, &sb) < 0)
+		syswarn(1, errno, "Failed stat of %s", arcn->org_name);
+	else if (arcn->sb.st_mtime != sb.st_mtime)
+		paxwarn(1, "File %s was modified during copy to %s",
+			arcn->org_name, arcn->name);
+
+	/*
+	 * if the last block has a file hole (all zero), we must make sure this
+	 * gets updated in the file. We force the last block of zeros to be
+	 * written. just closing with the file offset moved foward may not put
+	 * a hole at the end of the file.
+	 */
+	if (!no_hole && isem && (arcn->sb.st_size > 0L))
+		file_flush(fd2, fnm, isem);
+	return;
+}
+
+/*
+ * buf_fill()
+ *	fill the read buffer with the next record (or what we can get) from
+ *	the archive volume.
+ * Return:
+ *	Number of bytes of data in the read buffer, -1 for read error, and
+ *	0 when finished (user specified termination in ar_next()).
+ */
+
+#ifdef __STDC__
+int
+buf_fill(void)
+#else
+int
+buf_fill()
+#endif
+{
+	register int cnt;
+	static int fini = 0;
+
+	if (fini)
+		return(0);
+
+	for(;;) {
+		/*
+		 * try to fill the buffer. on error the next archive volume is
+		 * opened and we try again.
+		 */
+		if ((cnt = ar_read(buf, blksz)) > 0) {
+			bufpt = buf;
+			bufend = buf + cnt;
+			rdcnt += cnt;
+			return(cnt);
+		}
+
+		/*
+		 * errors require resync, EOF goes to next archive
+		 */
+		if (cnt < 0)
+			break;
+		if (ar_next() < 0) {
+			fini = 1;
+			return(0);
+		}
+		rdcnt = 0;
+	}
+	exit_val = 1;
+	return(-1);
+}
+
+/*
+ * buf_flush()
+ *	force the write buffer to the archive. We are passed the number of
+ *	bytes in the buffer at the point of the flush. When we change archives
+ *	the record size might change. (either larger or smaller).
+ * Return:
+ *	0 if all is ok, -1 when a write error occurs.
+ */
+
+#ifdef __STDC__
+int
+buf_flush(register int bufcnt)
+#else
+int
+buf_flush(bufcnt)
+	register int bufcnt;
+#endif
+{
+	register int cnt;
+	register int push = 0;
+	register int totcnt = 0;
+
+	/*
+	 * if we have reached the user specified byte count for each archive
+	 * volume, prompt for the next volume. (The non-standrad -R flag).
+	 * NOTE: If the wrlimit is smaller than wrcnt, we will always write
+	 * at least one record. We always round limit UP to next blocksize.
+	 */
+	if ((wrlimit > 0) && (wrcnt > wrlimit)) {
+		paxwarn(0, "User specified archive volume byte limit reached.");
+		if (ar_next() < 0) {
+			wrcnt = 0;
+			exit_val = 1;
+			return(-1);
+		}
+		wrcnt = 0;
+
+		/*
+		 * The new archive volume might have changed the size of the
+		 * write blocksize. if so we figure out if we need to write
+		 * (one or more times), or if there is now free space left in
+		 * the buffer (it is no longer full). bufcnt has the number of
+		 * bytes in the buffer, (the blocksize, at the point we were
+		 * CALLED). Push has the amount of "extra" data in the buffer
+		 * if the block size has shrunk from a volume change.
+		 */
+		bufend = buf + blksz;
+		if (blksz > bufcnt)
+			return(0);
+		if (blksz < bufcnt)
+			push = bufcnt - blksz;
+	}
+
+	/*
+	 * We have enough data to write at least one archive block
+	 */
+	for (;;) {
+		/*
+		 * write a block and check if it all went out ok
+		 */
+		cnt = ar_write(buf, blksz);
+		if (cnt == blksz) {
+			/*
+			 * the write went ok
+			 */
+			wrcnt += cnt;
+			totcnt += cnt;
+			if (push > 0) {
+				/* we have extra data to push to the front.
+				 * check for more than 1 block of push, and if
+				 * so we loop back to write again
+				 */
+				memcpy(buf, bufend, push);
+				bufpt = buf + push;
+				if (push >= blksz) {
+					push -= blksz;
+					continue;
+				}
+			} else
+				bufpt = buf;
+			return(totcnt);
+		} else if (cnt > 0) {
+			/*
+			 * Oh drat we got a partial write!
+			 * if format doesnt care about alignment let it go,
+			 * we warned the user in ar_write().... but this means
+			 * the last record on this volume violates pax spec....
+			 */
+			totcnt += cnt;
+			wrcnt += cnt;
+			bufpt = buf + cnt;
+			cnt = bufcnt - cnt;
+			memcpy(buf, bufpt, cnt);
+			bufpt = buf + cnt;
+			if (!frmt->blkalgn || ((cnt % frmt->blkalgn) == 0))
+				return(totcnt);
+			break;
+		}
+
+		/*
+		 * All done, go to next archive
+		 */
+		wrcnt = 0;
+		if (ar_next() < 0)
+			break;
+
+		/*
+		 * The new archive volume might also have changed the block
+		 * size. if so, figure out if we have too much or too little
+		 * data for using the new block size
+		 */
+		bufend = buf + blksz;
+		if (blksz > bufcnt)
+			return(0);
+		if (blksz < bufcnt)
+			push = bufcnt - blksz;
+	}
+
+	/*
+	 * write failed, stop pax. we must not create a bad archive!
+	 */
+	exit_val = 1;
+	return(-1);
+}
diff --git a/pax/cache.c b/pax/cache.c
new file mode 100644
index 0000000..df58ec4
--- /dev/null
+++ b/pax/cache.c
@@ -0,0 +1,500 @@
+/*	$OpenBSD: cache.c,v 1.6 1997/07/25 18:58:27 mickey Exp $	*/
+/*	$NetBSD: cache.c,v 1.4 1995/03/21 09:07:10 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)cache.c	8.1 (Berkeley) 5/31/93";
+#else
+static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: cache.c,v 1.6 1997/07/25 18:58:27 mickey Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <string.h>
+#include <stdio.h>
+#include <pwd.h>
+#include <grp.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "pax.h"
+#include "cache.h"
+#include "extern.h"
+
+/*
+ * routines that control user, group, uid and gid caches (for the archive
+ * member print routine).
+ * IMPORTANT:
+ * these routines cache BOTH hits and misses, a major performance improvement
+ */
+
+static	int pwopn = 0;		/* is password file open */
+static	int gropn = 0;		/* is group file open */
+static UIDC **uidtb = NULL;	/* uid to name cache */
+static GIDC **gidtb = NULL;	/* gid to name cache */
+static UIDC **usrtb = NULL;	/* user name to uid cache */
+static GIDC **grptb = NULL;	/* group name to gid cache */
+
+/*
+ * uidtb_start
+ *	creates an an empty uidtb
+ * Return:
+ *	0 if ok, -1 otherwise
+ */
+
+#ifdef __STDC__
+int
+uidtb_start(void)
+#else
+int
+uidtb_start()
+#endif
+{
+	static int fail = 0;
+
+	if (uidtb != NULL)
+		return(0);
+	if (fail)
+		return(-1);
+	if ((uidtb = (UIDC **)calloc(UID_SZ, sizeof(UIDC *))) == NULL) {
+		++fail;
+		paxwarn(1, "Unable to allocate memory for user id cache table");
+		return(-1);
+	}
+	return(0);
+}
+
+/*
+ * gidtb_start
+ *	creates an an empty gidtb
+ * Return:
+ *	0 if ok, -1 otherwise
+ */
+
+#ifdef __STDC__
+int
+gidtb_start(void)
+#else
+int
+gidtb_start()
+#endif
+{
+	static int fail = 0;
+
+	if (gidtb != NULL)
+		return(0);
+	if (fail)
+		return(-1);
+	if ((gidtb = (GIDC **)calloc(GID_SZ, sizeof(GIDC *))) == NULL) {
+		++fail;
+		paxwarn(1, "Unable to allocate memory for group id cache table");
+		return(-1);
+	}
+	return(0);
+}
+
+/*
+ * usrtb_start
+ *	creates an an empty usrtb
+ * Return:
+ *	0 if ok, -1 otherwise
+ */
+
+#ifdef __STDC__
+int
+usrtb_start(void)
+#else
+int
+usrtb_start()
+#endif
+{
+	static int fail = 0;
+
+	if (usrtb != NULL)
+		return(0);
+	if (fail)
+		return(-1);
+	if ((usrtb = (UIDC **)calloc(UNM_SZ, sizeof(UIDC *))) == NULL) {
+		++fail;
+		paxwarn(1, "Unable to allocate memory for user name cache table");
+		return(-1);
+	}
+	return(0);
+}
+
+/*
+ * grptb_start
+ *	creates an an empty grptb
+ * Return:
+ *	0 if ok, -1 otherwise
+ */
+
+#ifdef __STDC__
+int
+grptb_start(void)
+#else
+int
+grptb_start()
+#endif
+{
+	static int fail = 0;
+
+	if (grptb != NULL)
+		return(0);
+	if (fail)
+		return(-1);
+	if ((grptb = (GIDC **)calloc(GNM_SZ, sizeof(GIDC *))) == NULL) {
+		++fail;
+		paxwarn(1,"Unable to allocate memory for group name cache table");
+		return(-1);
+	}
+	return(0);
+}
+
+/*
+ * name_uid()
+ *	caches the name (if any) for the uid. If frc set, we always return the
+ *	the stored name (if valid or invalid match). We use a simple hash table.
+ * Return
+ *	Pointer to stored name (or a empty string)
+ */
+
+#ifdef __STDC__
+char *
+name_uid(uid_t uid, int frc)
+#else
+char *
+name_uid(uid, frc)
+	uid_t uid;
+	int frc;
+#endif
+{
+	register struct passwd *pw;
+	register UIDC *ptr;
+	register int hash;
+	if ((uidtb == NULL) && (uidtb_start() < 0))
+		return("");
+
+	/*
+	 * see if we have this uid cached
+	 */
+	hash = uid % UID_SZ;
+	ptr = uidtb[hash];
+	if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) {
+		/*
+		 * have an entry for this uid
+		 */
+		if (frc || (ptr->valid == VALID))
+			return(ptr->name);
+		return("");
+	}
+
+	/*
+	 * No entry for this uid, we will add it
+	 */
+	if (!pwopn) {
+		setpassent(1);
+		++pwopn;
+	}
+	if (ptr == NULL)
+		ptr = (UIDC *)malloc(sizeof(UIDC));
+
+	if ((pw = getpwuid(uid)) == NULL) {
+		/*
+		 * no match for this uid in the local password file
+		 * a string that is the uid in numberic format
+		 */
+		if (ptr == NULL)
+			return("");
+		ptr->uid = uid;
+		ptr->valid = INVALID;
+#		ifdef NET2_STAT
+		(void)snprintf(ptr->name, sizeof(ptr->name), "%u", uid);
+#		else
+		(void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
+			       (unsigned long)uid);
+#		endif
+		uidtb[hash] = ptr;
+		if (frc == 0)
+			return("");
+	} else {
+		/*
+		 * there is an entry for this uid in the password file
+		 */
+		if (ptr == NULL)
+			return(pw->pw_name);
+		ptr->uid = uid;
+		(void)strncpy(ptr->name, pw->pw_name, UNMLEN-1);
+		ptr->name[UNMLEN-1] = '\0';
+		ptr->valid = VALID;
+		uidtb[hash] = ptr;
+	}
+	return(ptr->name);
+}
+
+/*
+ * name_gid()
+ *	caches the name (if any) for the gid. If frc set, we always return the
+ *	the stored name (if valid or invalid match). We use a simple hash table.
+ * Return
+ *	Pointer to stored name (or a empty string)
+ */
+
+#ifdef __STDC__
+char *
+name_gid(gid_t gid, int frc)
+#else
+char *
+name_gid(gid, frc)
+	gid_t gid;
+	int frc;
+#endif
+{
+	register struct group *gr;
+	register GIDC *ptr;
+	register int hash;
+
+	if ((gidtb == NULL) && (gidtb_start() < 0))
+		return("");
+
+	/*
+	 * see if we have this gid cached
+	 */
+	hash = gid % GID_SZ;
+	ptr = gidtb[hash];
+	if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) {
+		/*
+		 * have an entry for this gid
+		 */
+		if (frc || (ptr->valid == VALID))
+			return(ptr->name);
+		return("");
+	}
+
+	/*
+	 * No entry for this gid, we will add it
+	 */
+	if (!gropn) {
+		setgroupent(1);
+		++gropn;
+	}
+	if (ptr == NULL)
+		ptr = (GIDC *)malloc(sizeof(GIDC));
+
+	if ((gr = getgrgid(gid)) == NULL) {
+		/*
+		 * no match for this gid in the local group file, put in
+		 * a string that is the gid in numberic format
+		 */
+		if (ptr == NULL)
+			return("");
+		ptr->gid = gid;
+		ptr->valid = INVALID;
+#		ifdef NET2_STAT
+		(void)snprintf(ptr->name, sizeof(ptr->name), "%u", gid);
+#		else
+		(void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
+			       (unsigned long)gid);
+#		endif
+		gidtb[hash] = ptr;
+		if (frc == 0)
+			return("");
+	} else {
+		/*
+		 * there is an entry for this group in the group file
+		 */
+		if (ptr == NULL)
+			return(gr->gr_name);
+		ptr->gid = gid;
+		(void)strncpy(ptr->name, gr->gr_name, GNMLEN-1);
+		ptr->name[GNMLEN-1] = '\0';
+		ptr->valid = VALID;
+		gidtb[hash] = ptr;
+	}
+	return(ptr->name);
+}
+
+/*
+ * uid_name()
+ *	caches the uid for a given user name. We use a simple hash table.
+ * Return
+ *	the uid (if any) for a user name, or a -1 if no match can be found
+ */
+
+#ifdef __STDC__
+int
+uid_name(char *name, uid_t *uid)
+#else
+int
+uid_name(name, uid)
+	char *name;
+	uid_t *uid;
+#endif
+{
+	register struct passwd *pw;
+	register UIDC *ptr;
+	register int namelen;
+	register int hash;
+
+	/*
+	 * return -1 for mangled names
+	 */
+	if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
+		return(-1);
+	if ((usrtb == NULL) && (usrtb_start() < 0))
+		return(-1);
+
+	/*
+	 * look up in hash table, if found and valid return the uid,
+	 * if found and invalid, return a -1
+	 */
+	hash = st_hash(name, namelen, UNM_SZ);
+	ptr = usrtb[hash];
+	if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
+		if (ptr->valid == INVALID)
+			return(-1);
+		*uid = ptr->uid;
+		return(0);
+	}
+
+	if (!pwopn) {
+		setpassent(1);
+		++pwopn;
+	}
+
+	if (ptr == NULL)
+		ptr = (UIDC *)malloc(sizeof(UIDC));
+
+	/*
+	 * no match, look it up, if no match store it as an invalid entry,
+	 * or store the matching uid
+	 */
+	if (ptr == NULL) {
+		if ((pw = getpwnam(name)) == NULL)
+			return(-1);
+		*uid = pw->pw_uid;
+		return(0);
+	}
+	usrtb[hash] = ptr;
+	(void)strncpy(ptr->name, name, UNMLEN-1);
+	ptr->name[UNMLEN-1] = '\0';
+	if ((pw = getpwnam(name)) == NULL) {
+		ptr->valid = INVALID;
+		return(-1);
+	}
+	ptr->valid = VALID;
+	*uid = ptr->uid = pw->pw_uid;
+	return(0);
+}
+
+/*
+ * gid_name()
+ *	caches the gid for a given group name. We use a simple hash table.
+ * Return
+ *	the gid (if any) for a group name, or a -1 if no match can be found
+ */
+
+#ifdef __STDC__
+int
+gid_name(char *name, gid_t *gid)
+#else
+int
+gid_name(name, gid)
+	char *name;
+	gid_t *gid;
+#endif
+{
+	register struct group *gr;
+	register GIDC *ptr;
+	register int namelen;
+	register int hash;
+
+	/*
+	 * return -1 for mangled names
+	 */
+	if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
+		return(-1);
+	if ((grptb == NULL) && (grptb_start() < 0))
+		return(-1);
+
+	/*
+	 * look up in hash table, if found and valid return the uid,
+	 * if found and invalid, return a -1
+	 */
+	hash = st_hash(name, namelen, GID_SZ);
+	ptr = grptb[hash];
+	if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
+		if (ptr->valid == INVALID)
+			return(-1);
+		*gid = ptr->gid;
+		return(0);
+	}
+
+	if (!gropn) {
+		setgroupent(1);
+		++gropn;
+	}
+	if (ptr == NULL)
+		ptr = (GIDC *)malloc(sizeof(GIDC));
+
+	/*
+	 * no match, look it up, if no match store it as an invalid entry,
+	 * or store the matching gid
+	 */
+	if (ptr == NULL) {
+		if ((gr = getgrnam(name)) == NULL)
+			return(-1);
+		*gid = gr->gr_gid;
+		return(0);
+	}
+
+	grptb[hash] = ptr;
+	(void)strncpy(ptr->name, name, GNMLEN-1);
+	ptr->name[GNMLEN-1] = '\0';
+	if ((gr = getgrnam(name)) == NULL) {
+		ptr->valid = INVALID;
+		return(-1);
+	}
+	ptr->valid = VALID;
+	*gid = ptr->gid = gr->gr_gid;
+	return(0);
+}
diff --git a/pax/cache.h b/pax/cache.h
new file mode 100644
index 0000000..01283ef
--- /dev/null
+++ b/pax/cache.h
@@ -0,0 +1,77 @@
+/*	$OpenBSD: cache.h,v 1.2 1996/06/23 14:20:31 deraadt Exp $	*/
+/*	$NetBSD: cache.h,v 1.3 1995/03/21 09:07:12 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *      @(#)cache.h	8.1 (Berkeley) 5/31/93
+ */
+
+/*
+ * Constants and data structures used to implement group and password file
+ * caches. Traditional passwd/group cache routines perform quite poorly with
+ * archives. The chances of hitting a valid lookup with an archive is quite a
+ * bit worse than with files already resident on the file system. These misses
+ * create a MAJOR performance cost. To adress this problem, these routines
+ * cache both hits and misses.
+ *
+ * NOTE:  name lengths must be as large as those stored in ANY PROTOCOL and
+ * as stored in the passwd and group files. CACHE SIZES MUST BE PRIME
+ */
+#define UNMLEN		32	/* >= user name found in any protocol */
+#define GNMLEN		32	/* >= group name found in any protocol */
+#define UID_SZ		317	/* size of user_name/uid cache */
+#define UNM_SZ		317	/* size of user_name/uid cache */
+#define GID_SZ		251	/* size of gid cache */
+#define GNM_SZ		317	/* size of group name cache */
+#define VALID		1	/* entry and name are valid */
+#define INVALID		2	/* entry valid, name NOT valid */
+
+/*
+ * Node structures used in the user, group, uid, and gid caches.
+ */
+
+typedef struct uidc {
+	int valid;		/* is this a valid or a miss entry */
+	char name[UNMLEN];	/* uid name */
+	uid_t uid;		/* cached uid */
+} UIDC;
+
+typedef struct gidc {
+	int valid;		/* is this a valid or a miss entry */
+	char name[GNMLEN];	/* gid name */
+	gid_t gid;		/* cached gid */
+} GIDC;
diff --git a/pax/cpio.1 b/pax/cpio.1
new file mode 100644
index 0000000..639bc07
--- /dev/null
+++ b/pax/cpio.1
@@ -0,0 +1,270 @@
+.\"
+.\" Copyright (c) 1997 SigmaSoft, Th. Lockert
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"      This product includes software developed by SigmaSoft, Th. Lockert.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\"    derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\"	$OpenBSD: cpio.1,v 1.3 1997/04/06 06:11:11 millert Exp $
+.\"
+.Dd February 16, 1997
+.Dt CPIO 1
+.Os
+.Sh NAME
+.Nm cpio
+.Nd copy file archives in and out
+.Sh SYNOPSIS
+.Nm
+.Fl o
+.Op Fl aABcLvzZ
+.Op Fl C Ar bytes
+.Op Fl F Ar archive
+.Op Fl H Ar format
+.Op Fl O Ar archive
+.Ar "< name-list"
+.Op Ar "> archive"
+.Nm
+.Fl i
+.Op Fl bBcdfmrsStuvzZ6
+.Op Fl C Ar bytes
+.Op Fl E Ar file
+.Op Fl F Ar archive
+.Op Fl H Ar format
+.Op Fl I Ar archive
+.Op Ar "pattern ..."
+.Op Ar "< archive"
+.Nm
+.Fl p
+.Op Fl adlLmuv
+.Ar destination-directory
+.Ar "< name-list"
+.Sh DESCRIPTION
+The
+.Nm
+command copies files to and from a
+.Nm
+archive.
+.Pp
+The following options are supported:
+.Bl -tag -width Fl
+.It Fl o
+Create an archive.  Reads the list of files to store in the
+archive from standard input, and writes the archive on standard
+output.
+.Bl -tag -width Fl
+.It Fl a
+Reset the access times on files that has been copied to the
+archive.
+.It Fl A
+Append to the specified archive.
+.It Fl B
+Set block size of output to 5120 bytes.
+.It Fl c
+Use ASCII format for
+.Nm
+header for portability.
+.It Fl C Ar bytes
+Set the block size of output to
+.Ar bytes .
+.It Fl F Ar archive
+.It Fl O Ar archive
+Use the specified file name as the archive to write to.
+.It Fl H Ar format
+Write the archive in the specified format.  Recognized
+formats are:
+.Bl -tag -width Ds
+.It Ar bcpio
+Old binary cpio format.
+.It Ar cpio
+Old octal character cpio format.
+.It Ar sv4cpio
+SVR4 hex cpio format.
+.It Ar tar
+Old tar format.
+.It Ar ustar
+POSIX ustar format.
+.El
+.It Fl L
+Follow symbolic links.
+.It Fl v
+Be verbose about operations.  List filenames as they are
+written to the archive.
+.It Fl z
+Compress archive using
+.Xr gzip 1
+format.
+.It Fl Z
+Compress archive using
+.Xr compress 1
+format.
+.El
+.It Fl i
+Restore files from an archive.  Reads the archive file from
+standard input and extracts files matching the
+.Ar patterns
+that were specified on the command line.
+.Bl -tag -width Fl
+.It Fl b
+Do byte- and word swapping after reading in data from the
+archive, for restoring archives created on systems with
+different byte order.
+.It Fl B
+Set the block size of the archive being read to 5120 bytes.
+.It Fl c
+Expect the archive headers to be in ASCII format.
+.It Fl C Ar bytes
+Read archive written with a blocksize of
+.Ar bytes .
+.It Fl d
+Create any intermediate directories as needed during
+restore.
+.It Fl E Ar file
+Read list of file name patters to extract or list from
+.Ar file .
+.It Fl f
+Restore all files except those matching the
+.Ar patterns
+given on the command line.
+.It Fl F Ar archive
+.It Fl I Ar archive
+Use the specified file as the input for the archive.
+.It Fl H Ar format
+Read an archive of the specified format.  Recognized
+formats are:
+.Bl -tag -width Ds
+.It Ar bcpio
+Old binary cpio format.
+.It Ar cpio
+Old octal character cpio format.
+.It Ar sv4cpio
+SVR4 hex cpio format.
+.It Ar tar
+Old tar format.
+.It Ar ustar
+POSIX ustar format.
+.El
+.It Fl m
+Restore modification times on files.
+.It Fl r
+Rename restored files interactively.
+.It Fl s
+Swap bytes after reading data from the archive.
+.It Fl S
+Swap words after reading data from the archive.
+.It Fl t
+Only list the contents of the archive, no files or
+directories will be created.
+.It Fl u
+Overwrite files even when the file in the archive is
+older than the one that will be overwritten.
+.It Fl v
+Be verbose about operations.  List filenames as they are
+copied in from the archive.
+.It Fl z
+Uncompress archive using
+.Xr gzip 1
+format.
+.It Fl Z
+Uncompress archive using
+.Xr compress 1
+format.
+.It Fl 6
+Process old-style \*Qcpio\*U format archives.
+.El
+.It Fl p
+Copy files from one location to another in a single pass.
+The list of files to copy are read from standard in and
+written out to a directory relative to the specified
+.Ar directory
+argument.
+.Bl -tag -width Fl
+.It Fl a
+Reset the access times on files that has been copied.
+.It Fl d
+Create any intermediate directories as needed to write
+the files at the new location.
+.It Fl l
+When possible, link files rather than creating an
+extra copy.
+.It Fl L
+Follow symbolic links.
+.It Fl m
+Restore modification times on files.
+.It Fl u
+Overwrite files even when the original file being copied is
+older than the one that will be overwritten.
+.It Fl v
+Be verbose about operations.  List filenames as they are
+copied.
+.El
+.El
+.Sh ERRORS
+.Nm
+will exit with one of the following values:
+.Bl -tag -width 2n
+.It 0
+All files were processed successfully.
+.It 1
+An error occured.
+.El
+.Pp
+Whenever
+.Nm
+cannot create a file or a link when extracting an archive or cannot
+find a file while writing an archive, or cannot preserve the user
+ID, group ID, file mode or access and modification times when the
+.Fl p
+options is specified, a diagnostic message is written to standard
+error and a non-zero exit value will be returned, but processing
+will continue.  In the case where
+.Nm
+cannot create a link to a file,
+.Nm
+will not create a second copy of the file.
+.Pp
+If the extraction of a file from an archive is prematurely terminated
+by a signal or error,
+.Nm
+may have only partially extracted the file the user wanted.
+Additionally, the file modes of extracted files and directories may
+have incorrect file bits, and the modification and access times may
+be wrong.
+.Pp
+If the creation of an archive is prematurely terminated by a signal
+or error,
+.Nm
+may have only partially created the archive which may violate the
+specific archive format specification.
+.Sh SEE ALSO
+.Xr pax 1 ,
+.Xr tar 1
+.Sh BUGS
+The 
+.Fl s
+and
+.Fl S
+options are currently not implemented.
+.Sh AUTHOR
+Keith Muller at the University of California, San Diego
diff --git a/pax/cpio.c b/pax/cpio.c
new file mode 100644
index 0000000..43feb64
--- /dev/null
+++ b/pax/cpio.c
@@ -0,0 +1,1284 @@
+/*	$OpenBSD: cpio.c,v 1.5 1997/07/25 18:58:28 mickey Exp $	*/
+/*	$NetBSD: cpio.c,v 1.5 1995/03/21 09:07:13 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)cpio.c	8.1 (Berkeley) 5/31/93";
+#else
+static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: cpio.c,v 1.5 1997/07/25 18:58:28 mickey Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "pax.h"
+#include "cpio.h"
+#include "extern.h"
+
+static int rd_nm __P((register ARCHD *, int));
+static int rd_ln_nm __P((register ARCHD *));
+static int com_rd __P((register ARCHD *));
+
+/*
+ * Routines which support the different cpio versions
+ */
+
+static int swp_head;		/* binary cpio header byte swap */
+
+/*
+ * Routines common to all versions of cpio
+ */
+
+/*
+ * cpio_strd()
+ *	Fire up the hard link detection code
+ * Return:
+ *      0 if ok -1 otherwise (the return values of lnk_start())
+ */
+
+#ifdef __STDC__
+int
+cpio_strd(void)
+#else
+int
+cpio_strd()
+#endif
+{
+	return(lnk_start());
+}
+
+/*
+ * cpio_trail()
+ *	Called to determine if a header block is a valid trailer. We are
+ *	passed the block, the in_sync flag (which tells us we are in resync
+ *	mode; looking for a valid header), and cnt (which starts at zero)
+ *	which is used to count the number of empty blocks we have seen so far.
+ * Return:
+ *	0 if a valid trailer, -1 if not a valid trailer, 
+ */
+
+#ifdef __STDC__
+int
+cpio_trail(register ARCHD *arcn)
+#else
+int
+cpio_trail(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	/*
+	 * look for trailer id in file we are about to process
+	 */
+	if ((strcmp(arcn->name, TRAILER) == 0) && (arcn->sb.st_size == 0))
+		return(0);
+	return(-1);
+}
+
+/*
+ * com_rd()
+ *	operations common to all cpio read functions.
+ * Return:
+ *	0
+ */
+
+#ifdef __STDC__
+static int
+com_rd(register ARCHD *arcn)
+#else
+static int
+com_rd(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	arcn->skip = 0;
+	arcn->pat = NULL;
+	arcn->org_name = arcn->name;
+	switch(arcn->sb.st_mode & C_IFMT) {
+	case C_ISFIFO:
+		arcn->type = PAX_FIF;
+		break;
+	case C_ISDIR:
+		arcn->type = PAX_DIR;
+		break;
+	case C_ISBLK:
+		arcn->type = PAX_BLK;
+		break;
+	case C_ISCHR:
+		arcn->type = PAX_CHR;
+		break;
+	case C_ISLNK:
+		arcn->type = PAX_SLK;
+		break;
+	case C_ISOCK:
+		arcn->type = PAX_SCK;
+		break;
+	case C_ISCTG:
+	case C_ISREG:
+	default:
+		/*
+		 * we have file data, set up skip (pad is set in the format
+		 * specific sections)
+		 */
+		arcn->sb.st_mode = (arcn->sb.st_mode & 0xfff) | C_ISREG;
+		arcn->type = PAX_REG;
+		arcn->skip = arcn->sb.st_size;
+		break;
+	}
+	if (chk_lnk(arcn) < 0)
+		return(-1);
+	return(0);
+}
+
+/*
+ * cpio_end_wr()
+ *	write the special file with the name trailer in the proper format
+ * Return:
+ *	result of the write of the trailer from the cpio specific write func
+ */
+
+#ifdef __STDC__
+int
+cpio_endwr(void)
+#else
+int
+cpio_endwr()
+#endif
+{
+	ARCHD last;
+
+	/*
+	 * create a trailer request and call the proper format write function
+	 */
+	memset(&last, 0, sizeof(last));
+	last.nlen = sizeof(TRAILER) - 1;
+	last.type = PAX_REG;
+	last.sb.st_nlink = 1;
+	(void)strcpy(last.name, TRAILER);
+	return((*frmt->wr)(&last));
+}
+
+/*
+ * rd_nam()
+ *	read in the file name which follows the cpio header
+ * Return:
+ *	0 if ok, -1 otherwise
+ */
+
+#ifdef __STDC__
+static int
+rd_nm(register ARCHD *arcn, int nsz)
+#else
+static int
+rd_nm(arcn, nsz)
+	register ARCHD *arcn;
+	int nsz;
+#endif
+{
+	/*
+	 * do not even try bogus values
+	 */
+	if ((nsz == 0) || (nsz > sizeof(arcn->name))) {
+		paxwarn(1, "Cpio file name length %d is out of range", nsz);
+		return(-1);
+	}
+
+	/*
+	 * read the name and make sure it is not empty and is \0 terminated
+	 */
+	if ((rd_wrbuf(arcn->name,nsz) != nsz) || (arcn->name[nsz-1] != '\0') ||
+	    (arcn->name[0] == '\0')) {
+		paxwarn(1, "Cpio file name in header is corrupted");
+		return(-1);
+	}
+	return(0);
+}
+
+/*
+ * rd_ln_nm()
+ *	read in the link name for a file with links. The link name is stored
+ *	like file data (and is NOT \0 terminated!)
+ * Return:
+ *	0 if ok, -1 otherwise
+ */
+
+#ifdef __STDC__
+static int
+rd_ln_nm(register ARCHD *arcn)
+#else
+static int
+rd_ln_nm(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	/*
+	 * check the length specified for bogus values
+	 */
+	if ((arcn->sb.st_size == 0) ||
+	    (arcn->sb.st_size >= sizeof(arcn->ln_name))) {
+#		ifdef NET2_STAT
+		paxwarn(1, "Cpio link name length is invalid: %lu",
+		    arcn->sb.st_size);
+#		else
+		paxwarn(1, "Cpio link name length is invalid: %qu",
+		    arcn->sb.st_size);
+#		endif
+		return(-1);
+	}
+
+	/*
+	 * read in the link name and \0 terminate it
+	 */
+	if (rd_wrbuf(arcn->ln_name, (int)arcn->sb.st_size) !=
+	    (int)arcn->sb.st_size) {
+		paxwarn(1, "Cpio link name read error");
+		return(-1);
+	}
+	arcn->ln_nlen = arcn->sb.st_size;
+	arcn->ln_name[arcn->ln_nlen] = '\0';
+
+	/*
+	 * watch out for those empty link names
+	 */
+	if (arcn->ln_name[0] == '\0') {
+		paxwarn(1, "Cpio link name is corrupt");
+		return(-1);
+	}
+	return(0);
+}
+
+/*
+ * Routines common to the extended byte oriented cpio format
+ */
+
+/*
+ * cpio_id()
+ *      determine if a block given to us is a valid extended byte oriented
+ *	cpio header
+ * Return:
+ *      0 if a valid header, -1 otherwise
+ */
+
+#ifdef __STDC__
+int
+cpio_id(char *blk, int size)
+#else
+int
+cpio_id(blk, size)
+	char *blk;
+	int size;
+#endif
+{
+	if ((size < sizeof(HD_CPIO)) ||
+	    (strncmp(blk, AMAGIC, sizeof(AMAGIC) - 1) != 0))
+		return(-1);
+	return(0);
+}
+
+/*
+ * cpio_rd()
+ *	determine if a buffer is a byte oriented extended cpio archive entry.
+ *	convert and store the values in the ARCHD parameter.
+ * Return:
+ *	0 if a valid header, -1 otherwise.
+ */
+
+#ifdef __STDC__
+int
+cpio_rd(register ARCHD *arcn, register char *buf)
+#else
+int
+cpio_rd(arcn, buf)
+	register ARCHD *arcn;
+	register char *buf;
+#endif
+{
+	register int nsz;
+	register HD_CPIO *hd;
+
+	/*
+	 * check that this is a valid header, if not return -1
+	 */
+	if (cpio_id(buf, sizeof(HD_CPIO)) < 0)
+		return(-1);
+	hd = (HD_CPIO *)buf;
+
+	/*
+	 * byte oriented cpio (posix) does not have padding! extract the octal
+	 * ascii fields from the header
+	 */
+	arcn->pad = 0L;
+	arcn->sb.st_dev = (dev_t)asc_ul(hd->c_dev, sizeof(hd->c_dev), OCT);
+	arcn->sb.st_ino = (ino_t)asc_ul(hd->c_ino, sizeof(hd->c_ino), OCT);
+	arcn->sb.st_mode = (mode_t)asc_ul(hd->c_mode, sizeof(hd->c_mode), OCT);
+	arcn->sb.st_uid = (uid_t)asc_ul(hd->c_uid, sizeof(hd->c_uid), OCT);
+	arcn->sb.st_gid = (gid_t)asc_ul(hd->c_gid, sizeof(hd->c_gid), OCT);
+	arcn->sb.st_nlink = (nlink_t)asc_ul(hd->c_nlink, sizeof(hd->c_nlink),
+	    OCT);
+	arcn->sb.st_rdev = (dev_t)asc_ul(hd->c_rdev, sizeof(hd->c_rdev), OCT);
+	arcn->sb.st_mtime = (time_t)asc_ul(hd->c_mtime, sizeof(hd->c_mtime),
+	    OCT);
+	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
+#	ifdef NET2_STAT
+	arcn->sb.st_size = (off_t)asc_ul(hd->c_filesize,sizeof(hd->c_filesize),
+	    OCT);
+#	else
+	arcn->sb.st_size = (off_t)asc_uqd(hd->c_filesize,sizeof(hd->c_filesize),
+	    OCT);
+#	endif
+
+	/*
+	 * check name size and if valid, read in the name of this entry (name
+	 * follows header in the archive)
+	 */
+	if ((nsz = (int)asc_ul(hd->c_namesize,sizeof(hd->c_namesize),OCT)) < 2)
+		return(-1);
+	arcn->nlen = nsz - 1;
+	if (rd_nm(arcn, nsz) < 0)
+		return(-1);
+
+	if (((arcn->sb.st_mode&C_IFMT) != C_ISLNK)||(arcn->sb.st_size == 0)) {
+		/*
+	 	 * no link name to read for this file
+	 	 */
+		arcn->ln_nlen = 0;
+		arcn->ln_name[0] = '\0';
+		return(com_rd(arcn));
+	}
+
+	/*
+	 * check link name size and read in the link name. Link names are
+	 * stored like file data.
+	 */
+	if (rd_ln_nm(arcn) < 0)
+		return(-1);
+
+	/*
+	 * we have a valid header (with a link)
+	 */
+	return(com_rd(arcn));
+}
+
+/*
+ * cpio_endrd()
+ *      no cleanup needed here, just return size of the trailer (for append)
+ * Return:
+ *      size of trailer header in this format
+ */
+
+#ifdef __STDC__
+off_t
+cpio_endrd(void)
+#else
+off_t
+cpio_endrd()
+#endif
+{
+	return((off_t)(sizeof(HD_CPIO) + sizeof(TRAILER)));
+}
+
+/*
+ * cpio_stwr()
+ *	start up the device mapping table
+ * Return:
+ *	0 if ok, -1 otherwise (what dev_start() returns)
+ */
+
+#ifdef __STDC__
+int
+cpio_stwr(void)
+#else
+int
+cpio_stwr()
+#endif
+{
+	return(dev_start());
+}
+
+/*
+ * cpio_wr()
+ *	copy the data in the ARCHD to buffer in extended byte oriented cpio
+ *	format.
+ * Return
+ *      0 if file has data to be written after the header, 1 if file has NO
+ *	data to write after the header, -1 if archive write failed
+ */
+
+#ifdef __STDC__
+int
+cpio_wr(register ARCHD *arcn)
+#else
+int
+cpio_wr(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	register HD_CPIO *hd;
+	register int nsz;
+	char hdblk[sizeof(HD_CPIO)];
+
+	/*
+	 * check and repair truncated device and inode fields in the header
+	 */
+	if (map_dev(arcn, (u_long)CPIO_MASK, (u_long)CPIO_MASK) < 0)
+		return(-1);
+
+	arcn->pad = 0L;
+	nsz = arcn->nlen + 1;
+	hd = (HD_CPIO *)hdblk;
+	if ((arcn->type != PAX_BLK) && (arcn->type != PAX_CHR))
+		arcn->sb.st_rdev = 0;
+
+	switch(arcn->type) {
+	case PAX_CTG:
+	case PAX_REG:
+	case PAX_HRG:
+		/*
+		 * set data size for file data
+		 */
+#		ifdef NET2_STAT
+		if (ul_asc((u_long)arcn->sb.st_size, hd->c_filesize,
+		    sizeof(hd->c_filesize), OCT)) {
+#		else
+		if (uqd_asc((u_quad_t)arcn->sb.st_size, hd->c_filesize,
+		    sizeof(hd->c_filesize), OCT)) {
+#		endif
+			paxwarn(1,"File is too large for cpio format %s",
+			    arcn->org_name);
+			return(1);
+		}
+		break;
+	case PAX_SLK:
+		/*
+		 * set data size to hold link name
+		 */
+		if (ul_asc((u_long)arcn->ln_nlen, hd->c_filesize,
+		    sizeof(hd->c_filesize), OCT))
+			goto out;
+		break;
+	default:
+		/*
+		 * all other file types have no file data
+		 */
+		if (ul_asc((u_long)0, hd->c_filesize, sizeof(hd->c_filesize),
+		     OCT))
+			goto out;
+		break;
+	}
+
+	/*
+	 * copy the values to the header using octal ascii
+	 */
+	if (ul_asc((u_long)MAGIC, hd->c_magic, sizeof(hd->c_magic), OCT) ||
+	    ul_asc((u_long)arcn->sb.st_dev, hd->c_dev, sizeof(hd->c_dev),
+		OCT) ||
+	    ul_asc((u_long)arcn->sb.st_ino, hd->c_ino, sizeof(hd->c_ino),
+		OCT) ||
+	    ul_asc((u_long)arcn->sb.st_mode, hd->c_mode, sizeof(hd->c_mode),
+		OCT) ||
+	    ul_asc((u_long)arcn->sb.st_uid, hd->c_uid, sizeof(hd->c_uid),
+		OCT) ||
+	    ul_asc((u_long)arcn->sb.st_gid, hd->c_gid, sizeof(hd->c_gid),
+		OCT) ||
+	    ul_asc((u_long)arcn->sb.st_nlink, hd->c_nlink, sizeof(hd->c_nlink),
+		 OCT) ||
+	    ul_asc((u_long)arcn->sb.st_rdev, hd->c_rdev, sizeof(hd->c_rdev),
+		OCT) ||
+	    ul_asc((u_long)arcn->sb.st_mtime,hd->c_mtime,sizeof(hd->c_mtime),
+		OCT) ||
+	    ul_asc((u_long)nsz, hd->c_namesize, sizeof(hd->c_namesize), OCT))
+		goto out;
+
+	/*
+	 * write the file name to the archive
+	 */
+	if ((wr_rdbuf(hdblk, (int)sizeof(HD_CPIO)) < 0) ||
+	    (wr_rdbuf(arcn->name, nsz) < 0)) {
+		paxwarn(1, "Unable to write cpio header for %s", arcn->org_name);
+		return(-1);
+	}
+
+	/*
+	 * if this file has data, we are done. The caller will write the file
+	 * data, if we are link tell caller we are done, go to next file
+	 */
+	if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG) ||
+	    (arcn->type == PAX_HRG))
+		return(0);
+	if (arcn->type != PAX_SLK)
+		return(1);
+
+	/*
+	 * write the link name to the archive, tell the caller to go to the
+	 * next file as we are done.
+	 */
+	if (wr_rdbuf(arcn->ln_name, arcn->ln_nlen) < 0) {
+		paxwarn(1,"Unable to write cpio link name for %s",arcn->org_name);
+		return(-1);
+	}
+	return(1);
+
+    out:
+	/*
+	 * header field is out of range
+	 */
+	paxwarn(1, "Cpio header field is too small to store file %s",
+	    arcn->org_name);
+	return(1);
+}
+
+/*
+ * Routines common to the system VR4 version of cpio (with/without file CRC)
+ */
+
+/*
+ * vcpio_id()
+ *      determine if a block given to us is a valid system VR4 cpio header
+ *	WITHOUT crc. WATCH it the magic cookies are in OCTAL, the header 
+ *	uses HEX
+ * Return:
+ *      0 if a valid header, -1 otherwise
+ */
+
+#ifdef __STDC__
+int
+vcpio_id(char *blk, int size)
+#else
+int
+vcpio_id(blk, size)
+	char *blk;
+	int size;
+#endif
+{
+	if ((size < sizeof(HD_VCPIO)) ||
+	    (strncmp(blk, AVMAGIC, sizeof(AVMAGIC) - 1) != 0))
+		return(-1);
+	return(0);
+}
+
+/*
+ * crc_id()
+ *      determine if a block given to us is a valid system VR4 cpio header
+ *	WITH crc. WATCH it the magic cookies are in OCTAL the header uses HEX
+ * Return:
+ *      0 if a valid header, -1 otherwise
+ */
+
+#ifdef __STDC__
+int
+crc_id(char *blk, int size)
+#else
+int
+crc_id(blk, size)
+	char *blk;
+	int size;
+#endif
+{
+	if ((size < sizeof(HD_VCPIO)) ||
+	    (strncmp(blk, AVCMAGIC, sizeof(AVCMAGIC) - 1) != 0))
+		return(-1);
+	return(0);
+}
+
+/*
+ * crc_strd()
+ w	set file data CRC calculations. Fire up the hard link detection code
+ * Return:
+ *      0 if ok -1 otherwise (the return values of lnk_start())
+ */
+
+#ifdef __STDC__
+int
+crc_strd(void)
+#else
+int
+crc_strd()
+#endif
+{
+	docrc = 1;
+	return(lnk_start());
+}
+
+/*
+ * vcpio_rd()
+ *	determine if a buffer is a system VR4 archive entry. (with/without CRC)
+ *	convert and store the values in the ARCHD parameter.
+ * Return:
+ *	0 if a valid header, -1 otherwise.
+ */
+
+#ifdef __STDC__
+int
+vcpio_rd(register ARCHD *arcn, register char *buf)
+#else
+int
+vcpio_rd(arcn, buf)
+	register ARCHD *arcn;
+	register char *buf;
+#endif
+{
+	register HD_VCPIO *hd;
+	dev_t devminor;
+	dev_t devmajor;
+	register int nsz;
+
+	/*
+	 * during the id phase it was determined if we were using CRC, use the
+	 * proper id routine.
+	 */
+	if (docrc) {
+		if (crc_id(buf, sizeof(HD_VCPIO)) < 0)
+			return(-1);
+	} else {
+		if (vcpio_id(buf, sizeof(HD_VCPIO)) < 0)
+			return(-1);
+	}
+
+	hd = (HD_VCPIO *)buf;
+	arcn->pad = 0L;
+
+	/*
+	 * extract the hex ascii fields from the header
+	 */
+	arcn->sb.st_ino = (ino_t)asc_ul(hd->c_ino, sizeof(hd->c_ino), HEX);
+	arcn->sb.st_mode = (mode_t)asc_ul(hd->c_mode, sizeof(hd->c_mode), HEX);
+	arcn->sb.st_uid = (uid_t)asc_ul(hd->c_uid, sizeof(hd->c_uid), HEX);
+	arcn->sb.st_gid = (gid_t)asc_ul(hd->c_gid, sizeof(hd->c_gid), HEX);
+	arcn->sb.st_mtime = (time_t)asc_ul(hd->c_mtime,sizeof(hd->c_mtime),HEX);
+	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
+#	ifdef NET2_STAT
+	arcn->sb.st_size = (off_t)asc_ul(hd->c_filesize,
+	    sizeof(hd->c_filesize), HEX);
+#	else
+	arcn->sb.st_size = (off_t)asc_uqd(hd->c_filesize,
+	    sizeof(hd->c_filesize), HEX);
+#	endif
+	arcn->sb.st_nlink = (nlink_t)asc_ul(hd->c_nlink, sizeof(hd->c_nlink),
+	    HEX);
+	devmajor = (dev_t)asc_ul(hd->c_maj, sizeof(hd->c_maj), HEX);
+	devminor = (dev_t)asc_ul(hd->c_min, sizeof(hd->c_min), HEX);
+	arcn->sb.st_dev = TODEV(devmajor, devminor);
+	devmajor = (dev_t)asc_ul(hd->c_rmaj, sizeof(hd->c_maj), HEX);
+	devminor = (dev_t)asc_ul(hd->c_rmin, sizeof(hd->c_min), HEX);
+	arcn->sb.st_rdev = TODEV(devmajor, devminor);
+	arcn->crc = asc_ul(hd->c_chksum, sizeof(hd->c_chksum), HEX);
+
+	/*
+	 * check the length of the file name, if ok read it in, return -1 if
+	 * bogus
+	 */
+	if ((nsz = (int)asc_ul(hd->c_namesize,sizeof(hd->c_namesize),HEX)) < 2)
+		return(-1);
+	arcn->nlen = nsz - 1;
+	if (rd_nm(arcn, nsz) < 0)
+		return(-1);
+
+	/*
+	 * skip padding. header + filename is aligned to 4 byte boundries
+	 */
+	if (rd_skip((off_t)(VCPIO_PAD(sizeof(HD_VCPIO) + nsz))) < 0)
+		return(-1);
+
+	/*
+	 * if not a link (or a file with no data), calculate pad size (for
+	 * padding which follows the file data), clear the link name and return
+	 */
+	if (((arcn->sb.st_mode&C_IFMT) != C_ISLNK)||(arcn->sb.st_size == 0)) {
+		/*
+		 * we have a valid header (not a link)
+		 */
+		arcn->ln_nlen = 0;
+		arcn->ln_name[0] = '\0';
+		arcn->pad = VCPIO_PAD(arcn->sb.st_size);
+		return(com_rd(arcn));
+	}
+
+	/*
+	 * read in the link name and skip over the padding
+	 */
+	if ((rd_ln_nm(arcn) < 0) ||
+	    (rd_skip((off_t)(VCPIO_PAD(arcn->sb.st_size))) < 0))
+		return(-1);
+
+	/*
+	 * we have a valid header (with a link)
+	 */
+	return(com_rd(arcn));
+}
+
+/*
+ * vcpio_endrd()
+ *      no cleanup needed here, just return size of the trailer (for append)
+ * Return:
+ *      size of trailer header in this format
+ */
+
+#ifdef __STDC__
+off_t
+vcpio_endrd(void)
+#else
+off_t
+vcpio_endrd()
+#endif
+{
+	return((off_t)(sizeof(HD_VCPIO) + sizeof(TRAILER) +
+		(VCPIO_PAD(sizeof(HD_VCPIO) + sizeof(TRAILER)))));
+}
+
+/*
+ * crc_stwr()
+ *	start up the device mapping table, enable crc file calculation
+ * Return:
+ *	0 if ok, -1 otherwise (what dev_start() returns)
+ */
+
+#ifdef __STDC__
+int
+crc_stwr(void)
+#else
+int
+crc_stwr()
+#endif
+{
+	docrc = 1;
+	return(dev_start());
+}
+
+/*
+ * vcpio_wr()
+ *	copy the data in the ARCHD to buffer in system VR4 cpio
+ *	(with/without crc) format.
+ * Return
+ *	0 if file has data to be written after the header, 1 if file has
+ *	NO data to write after the header, -1 if archive write failed
+ */
+
+#ifdef __STDC__
+int
+vcpio_wr(register ARCHD *arcn)
+#else
+int
+vcpio_wr(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	register HD_VCPIO *hd;
+	unsigned int nsz;
+	char hdblk[sizeof(HD_VCPIO)];
+
+	/*
+	 * check and repair truncated device and inode fields in the cpio
+	 * header
+	 */
+	if (map_dev(arcn, (u_long)VCPIO_MASK, (u_long)VCPIO_MASK) < 0)
+		return(-1);
+	nsz = arcn->nlen + 1;
+	hd = (HD_VCPIO *)hdblk;
+	if ((arcn->type != PAX_BLK) && (arcn->type != PAX_CHR))
+		arcn->sb.st_rdev = 0;
+
+	/*
+	 * add the proper magic value depending whether we were asked for
+	 * file data crc's, and the crc if needed.
+	 */
+	if (docrc) {
+		if (ul_asc((u_long)VCMAGIC, hd->c_magic, sizeof(hd->c_magic),
+	    		OCT) ||
+		    ul_asc((u_long)arcn->crc,hd->c_chksum,sizeof(hd->c_chksum),
+	    		HEX))
+			goto out;
+	} else {
+		if (ul_asc((u_long)VMAGIC, hd->c_magic, sizeof(hd->c_magic),
+	    		OCT) ||
+		    ul_asc((u_long)0L, hd->c_chksum, sizeof(hd->c_chksum),HEX))
+			goto out;
+	}
+
+	switch(arcn->type) {
+	case PAX_CTG:
+	case PAX_REG:
+	case PAX_HRG:
+		/*
+		 * caller will copy file data to the archive. tell him how
+		 * much to pad.
+		 */
+		arcn->pad = VCPIO_PAD(arcn->sb.st_size);
+#		ifdef NET2_STAT
+		if (ul_asc((u_long)arcn->sb.st_size, hd->c_filesize,
+		    sizeof(hd->c_filesize), HEX)) {
+#		else
+		if (uqd_asc((u_quad_t)arcn->sb.st_size, hd->c_filesize,
+		    sizeof(hd->c_filesize), HEX)) {
+#		endif
+			paxwarn(1,"File is too large for sv4cpio format %s",
+			    arcn->org_name);
+			return(1);
+		}
+		break;
+	case PAX_SLK:
+		/*
+		 * no file data for the caller to process, the file data has
+		 * the size of the link
+		 */
+		arcn->pad = 0L;
+		if (ul_asc((u_long)arcn->ln_nlen, hd->c_filesize,
+		    sizeof(hd->c_filesize), HEX))
+			goto out;
+		break;
+	default:
+		/*
+		 * no file data for the caller to process
+		 */
+		arcn->pad = 0L;
+		if (ul_asc((u_long)0L, hd->c_filesize, sizeof(hd->c_filesize),
+		    HEX))
+			goto out;
+		break;
+	}
+
+	/*
+	 * set the other fields in the header
+	 */
+	if (ul_asc((u_long)arcn->sb.st_ino, hd->c_ino, sizeof(hd->c_ino),
+		HEX) ||
+	    ul_asc((u_long)arcn->sb.st_mode, hd->c_mode, sizeof(hd->c_mode),
+		HEX) ||
+	    ul_asc((u_long)arcn->sb.st_uid, hd->c_uid, sizeof(hd->c_uid),
+		HEX) ||
+	    ul_asc((u_long)arcn->sb.st_gid, hd->c_gid, sizeof(hd->c_gid),
+    		HEX) ||
+	    ul_asc((u_long)arcn->sb.st_mtime, hd->c_mtime, sizeof(hd->c_mtime),
+    		HEX) ||
+	    ul_asc((u_long)arcn->sb.st_nlink, hd->c_nlink, sizeof(hd->c_nlink),
+    		HEX) ||
+	    ul_asc((u_long)MAJOR(arcn->sb.st_dev),hd->c_maj, sizeof(hd->c_maj),
+		HEX) ||
+	    ul_asc((u_long)MINOR(arcn->sb.st_dev),hd->c_min, sizeof(hd->c_min),
+		HEX) ||
+	    ul_asc((u_long)MAJOR(arcn->sb.st_rdev),hd->c_rmaj,sizeof(hd->c_maj),
+		HEX) ||
+	    ul_asc((u_long)MINOR(arcn->sb.st_rdev),hd->c_rmin,sizeof(hd->c_min),
+		HEX) ||
+	    ul_asc((u_long)nsz, hd->c_namesize, sizeof(hd->c_namesize), HEX))
+		goto out;
+
+	/*
+	 * write the header, the file name and padding as required.
+	 */
+	if ((wr_rdbuf(hdblk, (int)sizeof(HD_VCPIO)) < 0) ||
+	    (wr_rdbuf(arcn->name, (int)nsz) < 0)  ||
+	    (wr_skip((off_t)(VCPIO_PAD(sizeof(HD_VCPIO) + nsz))) < 0)) {
+		paxwarn(1,"Could not write sv4cpio header for %s",arcn->org_name);
+		return(-1);
+	}
+
+	/*
+	 * if we have file data, tell the caller we are done, copy the file
+	 */
+	if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG) ||
+	    (arcn->type == PAX_HRG))
+		return(0);
+
+	/*
+	 * if we are not a link, tell the caller we are done, go to next file
+	 */
+	if (arcn->type != PAX_SLK)
+		return(1);
+
+	/*
+	 * write the link name, tell the caller we are done.
+	 */
+	if ((wr_rdbuf(arcn->ln_name, arcn->ln_nlen) < 0) ||
+	    (wr_skip((off_t)(VCPIO_PAD(arcn->ln_nlen))) < 0)) {
+		paxwarn(1,"Could not write sv4cpio link name for %s",
+		    arcn->org_name);
+		return(-1);
+	}
+	return(1);
+
+    out:
+	/*
+	 * header field is out of range
+	 */
+	paxwarn(1,"Sv4cpio header field is too small for file %s",arcn->org_name);
+	return(1);
+}
+
+/*
+ * Routines common to the old binary header cpio
+ */
+
+/*
+ * bcpio_id()
+ *      determine if a block given to us is a old binary cpio header
+ *	(with/without header byte swapping)
+ * Return:
+ *      0 if a valid header, -1 otherwise
+ */
+
+#ifdef __STDC__
+int
+bcpio_id(char *blk, int size)
+#else
+int
+bcpio_id(blk, size)
+	char *blk;
+	int size;
+#endif
+{
+	if (size < sizeof(HD_BCPIO))
+		return(-1);
+
+	/*
+	 * check both normal and byte swapped magic cookies
+	 */
+	if (((u_short)SHRT_EXT(blk)) == MAGIC)
+		return(0);
+	if (((u_short)RSHRT_EXT(blk)) == MAGIC) {
+		if (!swp_head)
+			++swp_head;
+		return(0);
+	}
+	return(-1);
+}
+
+/*
+ * bcpio_rd()
+ *	determine if a buffer is a old binary archive entry. (it may have byte
+ *	swapped header) convert and store the values in the ARCHD parameter.
+ *	This is a very old header format and should not really be used.
+ * Return:
+ *	0 if a valid header, -1 otherwise.
+ */
+
+#ifdef __STDC__
+int
+bcpio_rd(register ARCHD *arcn, register char *buf)
+#else
+int
+bcpio_rd(arcn, buf)
+	register ARCHD *arcn;
+	register char *buf;
+#endif
+{
+	register HD_BCPIO *hd;
+	register int nsz;
+
+	/*
+	 * check the header
+	 */
+	if (bcpio_id(buf, sizeof(HD_BCPIO)) < 0)
+		return(-1);
+
+	arcn->pad = 0L;
+	hd = (HD_BCPIO *)buf;
+	if (swp_head) {
+		/*
+		 * header has swapped bytes on 16 bit boundries
+		 */
+		arcn->sb.st_dev = (dev_t)(RSHRT_EXT(hd->h_dev));
+		arcn->sb.st_ino = (ino_t)(RSHRT_EXT(hd->h_ino));
+		arcn->sb.st_mode = (mode_t)(RSHRT_EXT(hd->h_mode));
+		arcn->sb.st_uid = (uid_t)(RSHRT_EXT(hd->h_uid));
+		arcn->sb.st_gid = (gid_t)(RSHRT_EXT(hd->h_gid));
+		arcn->sb.st_nlink = (nlink_t)(RSHRT_EXT(hd->h_nlink));
+		arcn->sb.st_rdev = (dev_t)(RSHRT_EXT(hd->h_rdev));
+		arcn->sb.st_mtime = (time_t)(RSHRT_EXT(hd->h_mtime_1));
+		arcn->sb.st_mtime =  (arcn->sb.st_mtime << 16) |
+			((time_t)(RSHRT_EXT(hd->h_mtime_2)));
+		arcn->sb.st_size = (off_t)(RSHRT_EXT(hd->h_filesize_1));
+		arcn->sb.st_size = (arcn->sb.st_size << 16) |
+			((off_t)(RSHRT_EXT(hd->h_filesize_2)));
+		nsz = (int)(RSHRT_EXT(hd->h_namesize));
+	} else {
+		arcn->sb.st_dev = (dev_t)(SHRT_EXT(hd->h_dev));
+		arcn->sb.st_ino = (ino_t)(SHRT_EXT(hd->h_ino));
+		arcn->sb.st_mode = (mode_t)(SHRT_EXT(hd->h_mode));
+		arcn->sb.st_uid = (uid_t)(SHRT_EXT(hd->h_uid));
+		arcn->sb.st_gid = (gid_t)(SHRT_EXT(hd->h_gid));
+		arcn->sb.st_nlink = (nlink_t)(SHRT_EXT(hd->h_nlink));
+		arcn->sb.st_rdev = (dev_t)(SHRT_EXT(hd->h_rdev));
+		arcn->sb.st_mtime = (time_t)(SHRT_EXT(hd->h_mtime_1));
+		arcn->sb.st_mtime =  (arcn->sb.st_mtime << 16) |
+			((time_t)(SHRT_EXT(hd->h_mtime_2)));
+		arcn->sb.st_size = (off_t)(SHRT_EXT(hd->h_filesize_1));
+		arcn->sb.st_size = (arcn->sb.st_size << 16) |
+			((off_t)(SHRT_EXT(hd->h_filesize_2)));
+		nsz = (int)(SHRT_EXT(hd->h_namesize));
+	}
+	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
+
+	/*
+	 * check the file name size, if bogus give up. otherwise read the file
+	 * name
+	 */
+	if (nsz < 2)
+		return(-1);
+	arcn->nlen = nsz - 1;
+	if (rd_nm(arcn, nsz) < 0)
+		return(-1);
+
+	/*
+	 * header + file name are aligned to 2 byte boundries, skip if needed
+	 */
+	if (rd_skip((off_t)(BCPIO_PAD(sizeof(HD_BCPIO) + nsz))) < 0)
+		return(-1);
+
+	/*
+	 * if not a link (or a file with no data), calculate pad size (for
+	 * padding which follows the file data), clear the link name and return
+	 */
+	if (((arcn->sb.st_mode & C_IFMT) != C_ISLNK)||(arcn->sb.st_size == 0)){
+		/*
+		 * we have a valid header (not a link)
+		 */
+		arcn->ln_nlen = 0;
+		arcn->ln_name[0] = '\0';
+		arcn->pad = BCPIO_PAD(arcn->sb.st_size);
+		return(com_rd(arcn));
+	}
+
+	if ((rd_ln_nm(arcn) < 0) ||
+	    (rd_skip((off_t)(BCPIO_PAD(arcn->sb.st_size))) < 0))
+		return(-1);
+
+	/*
+	 * we have a valid header (with a link)
+	 */
+	return(com_rd(arcn));
+}
+
+/*
+ * bcpio_endrd()
+ *      no cleanup needed here, just return size of the trailer (for append)
+ * Return:
+ *      size of trailer header in this format
+ */
+
+#ifdef __STDC__
+off_t
+bcpio_endrd(void)
+#else
+off_t
+bcpio_endrd()
+#endif
+{
+	return((off_t)(sizeof(HD_BCPIO) + sizeof(TRAILER) +
+		(BCPIO_PAD(sizeof(HD_BCPIO) + sizeof(TRAILER)))));
+}
+
+/*
+ * bcpio_wr()
+ *	copy the data in the ARCHD to buffer in old binary cpio format
+ *	There is a real chance of field overflow with this critter. So we
+ *	always check the conversion is ok. nobody in his their right mind
+ *	should write an achive in this format...
+ * Return
+ *      0 if file has data to be written after the header, 1 if file has NO
+ *	data to write after the header, -1 if archive write failed
+ */
+
+#ifdef __STDC__
+int
+bcpio_wr(register ARCHD *arcn)
+#else
+int
+bcpio_wr(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	register HD_BCPIO *hd;
+	register int nsz;
+	char hdblk[sizeof(HD_BCPIO)];
+	off_t t_offt;
+	int t_int;
+	time_t t_timet;
+
+	/*
+	 * check and repair truncated device and inode fields in the cpio
+	 * header
+	 */
+	if (map_dev(arcn, (u_long)BCPIO_MASK, (u_long)BCPIO_MASK) < 0)
+		return(-1);
+
+	if ((arcn->type != PAX_BLK) && (arcn->type != PAX_CHR))
+		arcn->sb.st_rdev = 0;
+	hd = (HD_BCPIO *)hdblk;
+
+	switch(arcn->type) {
+	case PAX_CTG:
+	case PAX_REG:
+	case PAX_HRG:
+		/*
+		 * caller will copy file data to the archive. tell him how
+		 * much to pad.
+		 */
+		arcn->pad = BCPIO_PAD(arcn->sb.st_size);
+		hd->h_filesize_1[0] = CHR_WR_0(arcn->sb.st_size);
+		hd->h_filesize_1[1] = CHR_WR_1(arcn->sb.st_size);
+		hd->h_filesize_2[0] = CHR_WR_2(arcn->sb.st_size);
+		hd->h_filesize_2[1] = CHR_WR_3(arcn->sb.st_size);
+		t_offt = (off_t)(SHRT_EXT(hd->h_filesize_1));
+		t_offt = (t_offt<<16) | ((off_t)(SHRT_EXT(hd->h_filesize_2)));
+		if (arcn->sb.st_size != t_offt) {
+			paxwarn(1,"File is too large for bcpio format %s",
+			    arcn->org_name);
+			return(1);
+		}
+		break;
+	case PAX_SLK:
+		/*
+		 * no file data for the caller to process, the file data has
+		 * the size of the link
+		 */
+		arcn->pad = 0L;
+		hd->h_filesize_1[0] = CHR_WR_0(arcn->ln_nlen);
+		hd->h_filesize_1[1] = CHR_WR_1(arcn->ln_nlen);
+		hd->h_filesize_2[0] = CHR_WR_2(arcn->ln_nlen);
+		hd->h_filesize_2[1] = CHR_WR_3(arcn->ln_nlen);
+		t_int = (int)(SHRT_EXT(hd->h_filesize_1));
+		t_int = (t_int << 16) | ((int)(SHRT_EXT(hd->h_filesize_2)));
+		if (arcn->ln_nlen != t_int)
+			goto out;
+		break;
+	default:
+		/*
+		 * no file data for the caller to process
+		 */
+		arcn->pad = 0L;
+		hd->h_filesize_1[0] = (char)0;
+		hd->h_filesize_1[1] = (char)0;
+		hd->h_filesize_2[0] = (char)0;
+		hd->h_filesize_2[1] = (char)0;
+		break;
+	}
+
+	/*
+	 * build up the rest of the fields
+	 */
+	hd->h_magic[0] = CHR_WR_2(MAGIC);
+	hd->h_magic[1] = CHR_WR_3(MAGIC);
+	hd->h_dev[0] = CHR_WR_2(arcn->sb.st_dev);
+	hd->h_dev[1] = CHR_WR_3(arcn->sb.st_dev);
+	if (arcn->sb.st_dev != (dev_t)(SHRT_EXT(hd->h_dev)))
+		goto out;
+	hd->h_ino[0] = CHR_WR_2(arcn->sb.st_ino);
+	hd->h_ino[1] = CHR_WR_3(arcn->sb.st_ino);
+	if (arcn->sb.st_ino != (ino_t)(SHRT_EXT(hd->h_ino)))
+		goto out;
+	hd->h_mode[0] = CHR_WR_2(arcn->sb.st_mode);
+	hd->h_mode[1] = CHR_WR_3(arcn->sb.st_mode);
+	if (arcn->sb.st_mode != (mode_t)(SHRT_EXT(hd->h_mode)))
+		goto out;
+	hd->h_uid[0] = CHR_WR_2(arcn->sb.st_uid);
+	hd->h_uid[1] = CHR_WR_3(arcn->sb.st_uid);
+	if (arcn->sb.st_uid != (uid_t)(SHRT_EXT(hd->h_uid)))
+		goto out;
+	hd->h_gid[0] = CHR_WR_2(arcn->sb.st_gid);
+	hd->h_gid[1] = CHR_WR_3(arcn->sb.st_gid);
+	if (arcn->sb.st_gid != (gid_t)(SHRT_EXT(hd->h_gid)))
+		goto out;
+	hd->h_nlink[0] = CHR_WR_2(arcn->sb.st_nlink);
+	hd->h_nlink[1] = CHR_WR_3(arcn->sb.st_nlink);
+	if (arcn->sb.st_nlink != (nlink_t)(SHRT_EXT(hd->h_nlink)))
+		goto out;
+	hd->h_rdev[0] = CHR_WR_2(arcn->sb.st_rdev);
+	hd->h_rdev[1] = CHR_WR_3(arcn->sb.st_rdev);
+	if (arcn->sb.st_rdev != (dev_t)(SHRT_EXT(hd->h_rdev)))
+		goto out;
+	hd->h_mtime_1[0] = CHR_WR_0(arcn->sb.st_mtime);
+	hd->h_mtime_1[1] = CHR_WR_1(arcn->sb.st_mtime);
+	hd->h_mtime_2[0] = CHR_WR_2(arcn->sb.st_mtime);
+	hd->h_mtime_2[1] = CHR_WR_3(arcn->sb.st_mtime);
+	t_timet = (time_t)(SHRT_EXT(hd->h_mtime_1));
+	t_timet =  (t_timet << 16) | ((time_t)(SHRT_EXT(hd->h_mtime_2)));
+	if (arcn->sb.st_mtime != t_timet)
+		goto out;
+	nsz = arcn->nlen + 1;
+	hd->h_namesize[0] = CHR_WR_2(nsz);
+	hd->h_namesize[1] = CHR_WR_3(nsz);
+	if (nsz != (int)(SHRT_EXT(hd->h_namesize)))
+		goto out;
+
+	/*
+	 * write the header, the file name and padding as required.
+	 */
+	if ((wr_rdbuf(hdblk, (int)sizeof(HD_BCPIO)) < 0) ||
+	    (wr_rdbuf(arcn->name, nsz) < 0) ||
+	    (wr_skip((off_t)(BCPIO_PAD(sizeof(HD_BCPIO) + nsz))) < 0)) {
+		paxwarn(1, "Could not write bcpio header for %s", arcn->org_name);
+		return(-1);
+	}
+
+	/*
+	 * if we have file data, tell the caller we are done
+	 */
+	if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG) ||
+	    (arcn->type == PAX_HRG))
+		return(0);
+
+	/*
+	 * if we are not a link, tell the caller we are done, go to next file
+	 */
+	if (arcn->type != PAX_SLK)
+		return(1);
+
+	/*
+	 * write the link name, tell the caller we are done.
+	 */
+	if ((wr_rdbuf(arcn->ln_name, arcn->ln_nlen) < 0) ||
+	    (wr_skip((off_t)(BCPIO_PAD(arcn->ln_nlen))) < 0)) {
+		paxwarn(1,"Could not write bcpio link name for %s",arcn->org_name);
+		return(-1);
+	}
+	return(1);
+
+    out:
+	/*
+	 * header field is out of range
+	 */
+	paxwarn(1,"Bcpio header field is too small for file %s", arcn->org_name);
+	return(1);
+}
diff --git a/pax/cpio.h b/pax/cpio.h
new file mode 100644
index 0000000..811f8f3
--- /dev/null
+++ b/pax/cpio.h
@@ -0,0 +1,154 @@
+/*	$OpenBSD: cpio.h,v 1.2 1996/06/23 14:20:32 deraadt Exp $	*/
+/*	$NetBSD: cpio.h,v 1.3 1995/03/21 09:07:15 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)cpio.h	8.1 (Berkeley) 5/31/93
+ */
+
+/*
+ * Defines common to all versions of cpio
+ */
+#define TRAILER		"TRAILER!!!"	/* name in last archive record */
+
+/*
+ * Header encoding of the different file types
+ */
+#define	C_ISDIR		 040000		/* Directory */
+#define	C_ISFIFO	 010000		/* FIFO */
+#define	C_ISREG		0100000		/* Regular file */
+#define	C_ISBLK		 060000		/* Block special file */
+#define	C_ISCHR		 020000		/* Character special file */
+#define	C_ISCTG		0110000		/* Reserved for contiguous files */
+#define	C_ISLNK		0120000		/* Reserved for symbolic links */
+#define	C_ISOCK		0140000		/* Reserved for sockets */
+#define C_IFMT		0170000		/* type of file */
+
+/*
+ * Data Interchange Format - Extended cpio header format - POSIX 1003.1-1990
+ */
+typedef struct {
+	char	c_magic[6];		/* magic cookie */
+	char	c_dev[6];		/* device number */
+	char	c_ino[6];		/* inode number */
+	char	c_mode[6];		/* file type/access */
+	char	c_uid[6];		/* owners uid */
+	char	c_gid[6];		/* owners gid */
+	char	c_nlink[6];		/* # of links at archive creation */
+	char	c_rdev[6];		/* block/char major/minor # */
+	char	c_mtime[11];		/* modification time */
+	char	c_namesize[6];		/* length of pathname */
+	char	c_filesize[11];		/* length of file in bytes */
+} HD_CPIO; 
+
+#define	MAGIC		070707		/* transportable archive id */
+
+#ifdef _PAX_
+#define	AMAGIC		"070707"	/* ascii equivalent string of MAGIC */
+#define CPIO_MASK	0x3ffff		/* bits valid in the dev/ino fields */
+					/* used for dev/inode remaps */
+#endif /* _PAX_ */
+
+/*
+ * Binary cpio header structure 
+ *
+ * CAUTION! CAUTION! CAUTION!
+ * Each field really represents a 16 bit short (NOT ASCII). Described as
+ * an array of chars in an attempt to improve portability!!
+ */
+typedef struct {
+	u_char	h_magic[2];
+	u_char	h_dev[2];
+	u_char	h_ino[2];
+	u_char	h_mode[2];
+	u_char	h_uid[2];
+	u_char	h_gid[2];
+	u_char	h_nlink[2];
+	u_char	h_rdev[2];
+	u_char	h_mtime_1[2];
+	u_char	h_mtime_2[2];
+	u_char	h_namesize[2];
+	u_char	h_filesize_1[2];
+	u_char	h_filesize_2[2];
+} HD_BCPIO; 
+
+#ifdef _PAX_
+/*
+ * extraction and creation macros for binary cpio
+ */
+#define SHRT_EXT(ch)	((((unsigned)(ch)[0])<<8) | (((unsigned)(ch)[1])&0xff))
+#define RSHRT_EXT(ch)	((((unsigned)(ch)[1])<<8) | (((unsigned)(ch)[0])&0xff))
+#define CHR_WR_0(val)	((char)(((val) >> 24) & 0xff))
+#define CHR_WR_1(val)	((char)(((val) >> 16) & 0xff))
+#define CHR_WR_2(val)	((char)(((val) >> 8) & 0xff))
+#define CHR_WR_3(val)	((char)((val) & 0xff))
+
+/*
+ * binary cpio masks and pads
+ */
+#define BCPIO_PAD(x)	((2 - ((x) & 1)) & 1)	/* pad to next 2 byte word */
+#define BCPIO_MASK	0xffff			/* mask for dev/ino fields */
+#endif /* _PAX_ */
+
+/*
+ * System VR4 cpio header structure (with/without file data crc)
+ */
+typedef struct {
+	char	c_magic[6];		/* magic cookie */
+	char	c_ino[8];		/* inode number */
+	char	c_mode[8];		/* file type/access */
+	char	c_uid[8];		/* owners uid */
+	char	c_gid[8];		/* owners gid */
+	char	c_nlink[8];		/* # of links at archive creation */
+	char	c_mtime[8];		/* modification time */
+	char	c_filesize[8];		/* length of file in bytes */
+	char	c_maj[8];		/* block/char major # */
+	char	c_min[8];		/* block/char minor # */
+	char	c_rmaj[8];		/* special file major # */
+	char	c_rmin[8];		/* special file minor # */
+	char	c_namesize[8];		/* length of pathname */
+	char	c_chksum[8];		/* 0 OR CRC of bytes of FILE data */
+} HD_VCPIO; 
+
+#define	VMAGIC		070701		/* sVr4 new portable archive id */
+#define	VCMAGIC		070702		/* sVr4 new portable archive id CRC */
+#ifdef _PAX_
+#define	AVMAGIC		"070701"	/* ascii string of above */
+#define	AVCMAGIC	"070702"	/* ascii string of above */
+#define VCPIO_PAD(x)	((4 - ((x) & 3)) & 3)	/* pad to next 4 byte word */
+#define VCPIO_MASK	0xffffffff	/* mask for dev/ino fields */
+#endif /* _PAX_ */
diff --git a/pax/extern.h b/pax/extern.h
new file mode 100644
index 0000000..478152c
--- /dev/null
+++ b/pax/extern.h
@@ -0,0 +1,299 @@
+/*	$OpenBSD: extern.h,v 1.14 1997/07/24 23:19:18 millert Exp $	*/
+/*	$NetBSD: extern.h,v 1.5 1996/03/26 23:54:16 mrg Exp $	*/
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)extern.h	8.2 (Berkeley) 4/18/94
+ */
+
+/*
+ * External references from each source file
+ */
+
+#include <sys/cdefs.h>
+
+/*
+ * ar_io.c
+ */
+extern char *arcname;
+extern char *gzip_program;
+int ar_open __P((char *));
+void ar_close __P((void));
+void ar_drain __P((void));
+int ar_set_wr __P((void));
+int ar_app_ok __P((void));
+int ar_read __P((register char *, register int));
+int ar_write __P((register char *, register int));
+int ar_rdsync __P((void));
+int ar_fow __P((off_t, off_t *));
+int ar_rev __P((off_t ));
+int ar_next __P((void));
+
+/*
+ * ar_subs.c
+ */
+extern u_long flcnt;
+void list __P((void));
+void extract __P((void));
+void append __P((void));
+void archive __P((void));
+void copy __P((void));
+
+/*
+ * buf_subs.c
+ */
+extern int blksz;
+extern int wrblksz;
+extern int maxflt;
+extern int rdblksz;
+extern off_t wrlimit;
+extern off_t rdcnt;
+extern off_t wrcnt;
+int wr_start __P((void));
+int rd_start __P((void));
+void cp_start __P((void));
+int appnd_start __P((off_t));
+int rd_sync __P((void));
+void pback __P((char *, int));
+int rd_skip __P((off_t));
+void wr_fin __P((void));
+int wr_rdbuf __P((register char *, register int));
+int rd_wrbuf __P((register char *, register int));
+int wr_skip __P((off_t));
+int wr_rdfile __P((ARCHD *, int, off_t *));
+int rd_wrfile __P((ARCHD *, int, off_t *));
+void cp_file __P((ARCHD *, int, int));
+int buf_fill __P((void));
+int buf_flush __P((register int));
+
+/*
+ * cache.c
+ */
+int uidtb_start __P((void));
+int gidtb_start __P((void));
+int usrtb_start __P((void));
+int grptb_start __P((void));
+char * name_uid __P((uid_t, int));
+char * name_gid __P((gid_t, int));
+int uid_name __P((char *, uid_t *));
+int gid_name __P((char *, gid_t *));
+
+/*
+ * cpio.c
+ */
+int cpio_strd __P((void));
+int cpio_trail __P((register ARCHD *));
+int cpio_endwr __P((void));
+int cpio_id __P((char *, int));
+int cpio_rd __P((register ARCHD *, register char *));
+off_t cpio_endrd __P((void));
+int cpio_stwr __P((void));
+int cpio_wr __P((register ARCHD *));
+int vcpio_id __P((char *, int));
+int crc_id __P((char *, int));
+int crc_strd __P((void));
+int vcpio_rd __P((register ARCHD *, register char *));
+off_t vcpio_endrd __P((void));
+int crc_stwr __P((void));
+int vcpio_wr __P((register ARCHD *));
+int bcpio_id __P((char *, int));
+int bcpio_rd __P((register ARCHD *, register char *));
+off_t bcpio_endrd __P((void));
+int bcpio_wr __P((register ARCHD *));
+
+/*
+ * file_subs.c
+ */
+int file_creat __P((register ARCHD *));
+void file_close __P((register ARCHD *, int));
+int lnk_creat __P((register ARCHD *));
+int cross_lnk __P((register ARCHD *));
+int chk_same __P((register ARCHD *));
+int node_creat __P((register ARCHD *));
+int unlnk_exist __P((register char *, register int));
+int chk_path __P((register char *, uid_t, gid_t));
+void set_ftime __P((char *fnm, time_t mtime, time_t atime, int frc));
+int set_ids __P((char *, uid_t, gid_t));
+int set_lids __P((char *, uid_t, gid_t));
+void set_pmode __P((char *, mode_t));
+int file_write __P((int, char *, register int, int *, int *, int, char *));
+void file_flush __P((int, char *, int));
+void rdfile_close __P((register ARCHD *, register int *));
+int set_crc __P((register ARCHD *, register int));
+
+/*
+ * ftree.c
+ */
+int ftree_start __P((void));
+int ftree_add __P((register char *, int));
+void ftree_sel __P((register ARCHD *));
+void ftree_chk __P((void));
+int next_file __P((register ARCHD *));
+
+/*
+ * gen_subs.c
+ */
+void ls_list __P((register ARCHD *, time_t, FILE *));
+void ls_tty __P((register ARCHD *));
+int l_strncpy __P((register char *, register char *, int));
+u_long asc_ul __P((register char *, int, register int));
+int ul_asc __P((u_long, register char *, register int, register int));
+#ifndef NET2_STAT
+u_quad_t asc_uqd __P((register char *, int, register int));
+int uqd_asc __P((u_quad_t, register char *, register int, register int));
+#endif
+
+/* 
+ * getoldopt.c
+ */
+int getoldopt __P((int, char **, char *));
+
+/*
+ * options.c
+ */
+extern FSUB fsub[];
+extern int ford[];
+void options __P((register int, register char **));
+OPLIST * opt_next __P((void));
+int opt_add __P((register char *));
+int bad_opt __P((void));
+extern char *chdname;
+
+/*
+ * pat_rep.c
+ */
+int rep_add __P((register char *));
+int pat_add __P((char *, char *));
+void pat_chk __P((void));
+int pat_sel __P((register ARCHD *));
+int pat_match __P((register ARCHD *));
+int mod_name __P((register ARCHD *));
+int set_dest __P((register ARCHD *, char *, int));
+
+/*
+ * pax.c
+ */
+extern int act;
+extern FSUB *frmt;
+extern int cflag;
+extern int cwdfd;
+extern int dflag;
+extern int iflag;
+extern int kflag;
+extern int lflag;
+extern int nflag;
+extern int tflag;
+extern int uflag;
+extern int vflag;
+extern int zflag;
+extern int Dflag;
+extern int Hflag;
+extern int Lflag;
+extern int Xflag;
+extern int Yflag;
+extern int Zflag;
+extern int vfpart;
+extern int patime;
+extern int pmtime;
+extern int nodirs;
+extern int pmode;
+extern int pids;
+extern int rmleadslash;
+extern int exit_val;
+extern int docrc;
+extern char *dirptr;
+extern char *ltmfrmt;
+extern char *argv0;
+int main __P((int, char **));
+void sig_cleanup __P((int));
+
+/*
+ * sel_subs.c
+ */
+int sel_chk __P((register ARCHD *));
+int grp_add __P((register char *));
+int usr_add __P((register char *));
+int trng_add __P((register char *));
+
+/*
+ * tables.c
+ */
+int lnk_start __P((void));
+int chk_lnk __P((register ARCHD *));
+void purg_lnk __P((register ARCHD *));
+void lnk_end __P((void));
+int ftime_start __P((void));
+int chk_ftime __P((register ARCHD *));
+int name_start __P((void));
+int add_name __P((register char *, int, char *));
+void sub_name __P((register char *, int *, size_t));
+int dev_start __P((void));
+int add_dev __P((register ARCHD *));
+int map_dev __P((register ARCHD *, u_long, u_long));
+int atdir_start __P((void));
+void atdir_end __P((void));
+void add_atdir __P((char *, dev_t, ino_t, time_t, time_t));
+int get_atdir __P((dev_t, ino_t, time_t *, time_t *));
+int dir_start __P((void));
+void add_dir __P((char *, int, struct stat *, int));
+void proc_dir __P((void));
+u_int st_hash __P((char *, int, int));
+
+/*
+ * tar.c
+ */
+int tar_endwr __P((void));
+off_t tar_endrd __P((void));
+int tar_trail __P((register char *, register int, register int *));
+int tar_id __P((register char *, int));
+int tar_opt __P((void));
+int tar_rd __P((register ARCHD *, register char *));
+int tar_wr __P((register ARCHD *));
+int ustar_strd __P((void));
+int ustar_stwr __P((void));
+int ustar_id __P((char *, int));
+int ustar_rd __P((register ARCHD *, register char *));
+int ustar_wr __P((register ARCHD *));
+
+/*
+ * tty_subs.c
+ */
+int tty_init __P((void));
+void tty_prnt __P((char *, ...));
+int tty_read __P((char *, int));
+void paxwarn __P((int, char *, ...));
+void syswarn __P((int, int, char *, ...));
diff --git a/pax/file_subs.c b/pax/file_subs.c
new file mode 100644
index 0000000..2aba0fb
--- /dev/null
+++ b/pax/file_subs.c
@@ -0,0 +1,1112 @@
+/*	$OpenBSD: file_subs.c,v 1.13 1997/09/01 18:29:48 deraadt Exp $	*/
+/*	$NetBSD: file_subs.c,v 1.4 1995/03/21 09:07:18 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)file_subs.c	8.1 (Berkeley) 5/31/93";
+#else
+static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: file_subs.c,v 1.13 1997/09/01 18:29:48 deraadt Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/uio.h>
+#include <stdlib.h>
+#include "pax.h"
+#include "options.h"
+#include "extern.h"
+
+static int
+mk_link __P((register char *,register struct stat *,register char *, int));
+
+/*
+ * routines that deal with file operations such as: creating, removing;
+ * and setting access modes, uid/gid and times of files
+ */
+
+#define FILEBITS		(S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
+#define SETBITS			(S_ISUID | S_ISGID)
+#define ABITS			(FILEBITS | SETBITS)
+
+/*
+ * file_creat()
+ *	Create and open a file.
+ * Return:
+ *	file descriptor or -1 for failure
+ */
+
+#ifdef __STDC__
+int
+file_creat(register ARCHD *arcn)
+#else
+int
+file_creat(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	int fd = -1;
+	mode_t file_mode;
+	int oerrno;
+
+	/*
+	 * assume file doesn't exist, so just try to create it, most times this
+	 * works. We have to take special handling when the file does exist. To
+	 * detect this, we use O_EXCL. For example when trying to create a
+	 * file and a character device or fifo exists with the same name, we
+	 * can accidently open the device by mistake (or block waiting to open)
+	 * If we find that the open has failed, then figure spend the effore to
+	 * figure out why. This strategy was found to have better average
+	 * performance in common use than checking the file (and the path)
+	 * first with lstat.
+	 */
+	file_mode = arcn->sb.st_mode & FILEBITS;
+	if ((fd = open(arcn->name, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,
+	    file_mode)) >= 0)
+		return(fd);
+
+	/*
+	 * the file seems to exist. First we try to get rid of it (found to be
+	 * the second most common failure when traced). If this fails, only
+	 * then we go to the expense to check and create the path to the file
+	 */
+	if (unlnk_exist(arcn->name, arcn->type) != 0)
+		return(-1);
+
+	for (;;) {
+		/*
+		 * try to open it again, if this fails, check all the nodes in
+		 * the path and give it a final try. if chk_path() finds that
+		 * it cannot fix anything, we will skip the last attempt
+		 */
+		if ((fd = open(arcn->name, O_WRONLY | O_CREAT | O_TRUNC,
+		    file_mode)) >= 0)
+			break;
+		oerrno = errno;
+		if (nodirs || chk_path(arcn->name,arcn->sb.st_uid,arcn->sb.st_gid) < 0) {
+			syswarn(1, oerrno, "Unable to create %s", arcn->name);
+			return(-1);
+		}
+	}
+	return(fd);
+}
+
+/*
+ * file_close()
+ *	Close file descriptor to a file just created by pax. Sets modes,
+ *	ownership and times as required.
+ * Return:
+ *	0 for success, -1 for failure
+ */
+
+#ifdef __STDC__
+void
+file_close(register ARCHD *arcn, int fd)
+#else
+void
+file_close(arcn, fd)
+	register ARCHD *arcn;
+	int fd;
+#endif
+{
+	int res = 0;
+
+	if (fd < 0)
+		return;
+	if (close(fd) < 0)
+		syswarn(0, errno, "Unable to close file descriptor on %s",
+		    arcn->name);
+
+	/*
+	 * set owner/groups first as this may strip off mode bits we want
+	 * then set file permission modes. Then set file access and
+	 * modification times. 
+	 */
+	if (pids)
+		res = set_ids(arcn->name, arcn->sb.st_uid, arcn->sb.st_gid);
+
+	/*
+	 * IMPORTANT SECURITY NOTE:
+	 * if not preserving mode or we cannot set uid/gid, then PROHIBIT
+	 * set uid/gid bits
+	 */
+	if (!pmode || res)
+		arcn->sb.st_mode &= ~(SETBITS);
+	if (pmode)
+		set_pmode(arcn->name, arcn->sb.st_mode);
+	if (patime || pmtime)
+		set_ftime(arcn->name, arcn->sb.st_mtime, arcn->sb.st_atime, 0);
+}
+
+/*
+ * lnk_creat()
+ *	Create a hard link to arcn->ln_name from arcn->name. arcn->ln_name
+ *	must exist; 
+ * Return:
+ *	0 if ok, -1 otherwise
+ */
+
+#ifdef __STDC__
+int
+lnk_creat(register ARCHD *arcn)
+#else
+int
+lnk_creat(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	struct stat sb;
+
+	/*
+	 * we may be running as root, so we have to be sure that link target
+	 * is not a directory, so we lstat and check
+	 */
+	if (lstat(arcn->ln_name, &sb) < 0) {
+		syswarn(1,errno,"Unable to link to %s from %s", arcn->ln_name,
+		    arcn->name);
+		return(-1);
+	}
+
+	if (S_ISDIR(sb.st_mode)) {
+		paxwarn(1, "A hard link to the directory %s is not allowed",
+		    arcn->ln_name);
+		return(-1);
+	}
+
+	return(mk_link(arcn->ln_name, &sb, arcn->name, 0));
+}
+
+/*
+ * cross_lnk()
+ *	Create a hard link to arcn->org_name from arcn->name. Only used in copy
+ *	with the -l flag. No warning or error if this does not succeed (we will
+ *	then just create the file)
+ * Return:
+ *	1 if copy() should try to create this file node
+ *	0 if cross_lnk() ok, -1 for fatal flaw (like linking to self).
+ */
+
+#ifdef __STDC__
+int
+cross_lnk(register ARCHD *arcn)
+#else
+int
+cross_lnk(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	/*
+	 * try to make a link to orginal file (-l flag in copy mode). make sure
+	 * we do not try to link to directories in case we are running as root
+	 * (and it might succeed).
+	 */
+	if (arcn->type == PAX_DIR)
+		return(1);
+	return(mk_link(arcn->org_name, &(arcn->sb), arcn->name, 1));
+}
+
+/*
+ * chk_same()
+ *	In copy mode if we are not trying to make hard links between the src
+ *	and destinations, make sure we are not going to overwrite ourselves by
+ *	accident. This slows things down a little, but we have to protect all
+ *	those people who make typing errors.
+ * Return:
+ *	1 the target does not exist, go ahead and copy
+ *	0 skip it file exists (-k) or may be the same as source file
+ */
+
+#ifdef __STDC__
+int
+chk_same(register ARCHD *arcn)
+#else
+int
+chk_same(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	struct stat sb;
+
+	/* 
+	 * if file does not exist, return. if file exists and -k, skip it
+	 * quietly
+	 */
+	if (lstat(arcn->name, &sb) < 0)
+		return(1);
+	if (kflag)
+		return(0);
+
+	/*
+	 * better make sure the user does not have src == dest by mistake
+	 */
+	if ((arcn->sb.st_dev == sb.st_dev) && (arcn->sb.st_ino == sb.st_ino)) {
+		paxwarn(1, "Unable to copy %s, file would overwrite itself",
+		    arcn->name);
+		return(0);
+	}
+	return(1);
+}
+
+/*
+ * mk_link()
+ *	try to make a hard link between two files. if ign set, we do not
+ *	complain.
+ * Return:
+ *	0 if successful (or we are done with this file but no error, such as
+ *	finding the from file exists and the user has set -k).
+ *	1 when ign was set to indicates we could not make the link but we
+ *	should try to copy/extract the file as that might work (and is an
+ *	allowed option). -1 an error occurred.
+ */
+
+#ifdef __STDC__
+static int
+mk_link(register char *to, register struct stat *to_sb, register char *from,
+	int ign)
+#else
+static int
+mk_link(to, to_sb, from, ign)
+	register char *to;
+	register struct stat *to_sb;
+	register char *from;
+	int ign;
+#endif
+{
+	struct stat sb;
+	int oerrno;
+
+	/*
+	 * if from file exists, it has to be unlinked to make the link. If the
+	 * file exists and -k is set, skip it quietly
+	 */
+	if (lstat(from, &sb) == 0) {
+		if (kflag)
+			return(0);
+
+		/*
+		 * make sure it is not the same file, protect the user
+		 */
+		if ((to_sb->st_dev==sb.st_dev)&&(to_sb->st_ino == sb.st_ino)) {
+			paxwarn(1, "Unable to link file %s to itself", to);
+			return(-1);;
+		}
+
+		/*
+		 * try to get rid of the file, based on the type
+		 */
+		if (S_ISDIR(sb.st_mode)) {
+			if (rmdir(from) < 0) {
+				syswarn(1, errno, "Unable to remove %s", from);
+				return(-1);
+			}
+		} else if (unlink(from) < 0) {
+			if (!ign) {
+				syswarn(1, errno, "Unable to remove %s", from);
+				return(-1);
+			}
+			return(1);
+		}
+	}
+
+	/*
+	 * from file is gone (or did not exist), try to make the hard link.
+	 * if it fails, check the path and try it again (if chk_path() says to
+	 * try again)
+	 */
+	for (;;) {
+		if (link(to, from) == 0)
+			break;
+		oerrno = errno;
+		if (!nodirs && chk_path(from, to_sb->st_uid, to_sb->st_gid) == 0)
+			continue;
+		if (!ign) {
+			syswarn(1, oerrno, "Could not link to %s from %s", to,
+			    from);
+			return(-1);
+		}
+		return(1);
+	}
+
+	/*
+	 * all right the link was made
+	 */
+	return(0);
+}
+
+/*
+ * node_creat()
+ *	create an entry in the file system (other than a file or hard link).
+ *	If successful, sets uid/gid modes and times as required.
+ * Return:
+ *	0 if ok, -1 otherwise
+ */
+
+#ifdef __STDC__
+int
+node_creat(register ARCHD *arcn)
+#else
+int
+node_creat(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	register int res;
+	register int ign = 0;
+	register int oerrno;
+	register int pass = 0;
+	mode_t file_mode;
+	struct stat sb;
+
+	/*
+	 * create node based on type, if that fails try to unlink the node and
+	 * try again. finally check the path and try again. As noted in the
+	 * file and link creation routines, this method seems to exhibit the
+	 * best performance in general use workloads.
+	 */
+	file_mode = arcn->sb.st_mode & FILEBITS;
+
+	for (;;) {
+		switch(arcn->type) {
+		case PAX_DIR:
+			res = mkdir(arcn->name, file_mode);
+			if (ign)
+				res = 0;
+			break;
+		case PAX_CHR:
+			file_mode |= S_IFCHR;
+			res = mknod(arcn->name, file_mode, arcn->sb.st_rdev);
+			break;
+		case PAX_BLK:
+			file_mode |= S_IFBLK;
+			res = mknod(arcn->name, file_mode, arcn->sb.st_rdev);
+			break;
+		case PAX_FIF:
+			res = mkfifo(arcn->name, file_mode);
+			break;
+		case PAX_SCK:
+			/*
+			 * Skip sockets, operation has no meaning under BSD
+			 */
+			paxwarn(0,
+			    "%s skipped. Sockets cannot be copied or extracted",
+			    arcn->name);
+			return(-1);
+		case PAX_SLK:
+			res = symlink(arcn->ln_name, arcn->name);
+			break;
+		case PAX_CTG:
+		case PAX_HLK:
+		case PAX_HRG:
+		case PAX_REG:
+		default:
+			/*
+			 * we should never get here
+			 */
+			paxwarn(0, "%s has an unknown file type, skipping",
+				arcn->name);
+			return(-1);
+		}
+
+		/*
+		 * if we were able to create the node break out of the loop,
+		 * otherwise try to unlink the node and try again. if that
+		 * fails check the full path and try a final time.
+		 */
+		if (res == 0)
+			break;
+
+		/*
+		 * we failed to make the node
+		 */
+		oerrno = errno;
+		if ((ign = unlnk_exist(arcn->name, arcn->type)) < 0)
+			return(-1);
+
+		if (++pass <= 1)
+			continue;
+
+		if (nodirs || chk_path(arcn->name,arcn->sb.st_uid,arcn->sb.st_gid) < 0) {
+			syswarn(1, oerrno, "Could not create: %s", arcn->name);
+			return(-1);
+		}
+	}
+
+	/*
+	 * we were able to create the node. set uid/gid, modes and times
+	 */
+	if (pids)
+		res = ((arcn->type == PAX_SLK) ?
+		    set_lids(arcn->name, arcn->sb.st_uid, arcn->sb.st_gid) :
+		    set_ids(arcn->name, arcn->sb.st_uid, arcn->sb.st_gid));
+	else
+		res = 0;
+
+	/*
+	 * symlinks are done now.
+	 */
+	if (arcn->type == PAX_SLK)
+		return(0);
+
+	/*
+	 * IMPORTANT SECURITY NOTE:
+	 * if not preserving mode or we cannot set uid/gid, then PROHIBIT any
+	 * set uid/gid bits
+	 */
+	if (!pmode || res)
+		arcn->sb.st_mode &= ~(SETBITS);
+	if (pmode)
+		set_pmode(arcn->name, arcn->sb.st_mode);
+
+	if (arcn->type == PAX_DIR && strcmp(NM_CPIO, argv0) != 0) {
+		/*
+		 * Dirs must be processed again at end of extract to set times
+		 * and modes to agree with those stored in the archive. However
+		 * to allow extract to continue, we may have to also set owner
+		 * rights. This allows nodes in the archive that are children
+		 * of this directory to be extracted without failure. Both time
+		 * and modes will be fixed after the entire archive is read and
+		 * before pax exits.
+		 */
+		if (access(arcn->name, R_OK | W_OK | X_OK) < 0) {
+			if (lstat(arcn->name, &sb) < 0) {
+				syswarn(0, errno,"Could not access %s (stat)",
+				    arcn->name);
+				set_pmode(arcn->name,file_mode | S_IRWXU);
+			} else {
+				/*
+				 * We have to add rights to the dir, so we make
+				 * sure to restore the mode. The mode must be
+				 * restored AS CREATED and not as stored if
+				 * pmode is not set.
+				 */
+				set_pmode(arcn->name,
+				    ((sb.st_mode & FILEBITS) | S_IRWXU));
+				if (!pmode)
+					arcn->sb.st_mode = sb.st_mode;
+			}
+
+			/*
+			 * we have to force the mode to what was set here,
+			 * since we changed it from the default as created.
+			 */
+			add_dir(arcn->name, arcn->nlen, &(arcn->sb), 1);
+		} else if (pmode || patime || pmtime)
+			add_dir(arcn->name, arcn->nlen, &(arcn->sb), 0);
+	}
+
+	if (patime || pmtime)
+		set_ftime(arcn->name, arcn->sb.st_mtime, arcn->sb.st_atime, 0);
+	return(0);
+}
+
+/*
+ * unlnk_exist()
+ *	Remove node from file system with the specified name. We pass the type
+ *	of the node that is going to replace it. When we try to create a
+ *	directory and find that it already exists, we allow processing to
+ *	continue as proper modes etc will always be set for it later on.
+ * Return:
+ *	0 is ok to proceed, no file with the specified name exists
+ *	-1 we were unable to remove the node, or we should not remove it (-k)
+ *	1 we found a directory and we were going to create a directory.
+ */
+
+#ifdef __STDC__
+int
+unlnk_exist(register char *name, register int type)
+#else
+int
+unlnk_exist(name, type)
+	register char *name;
+	register int type;
+#endif
+{
+	struct stat sb;
+
+	/*
+	 * the file does not exist, or -k we are done
+	 */
+	if (lstat(name, &sb) < 0)
+		return(0);
+	if (kflag)
+		return(-1);
+
+	if (S_ISDIR(sb.st_mode)) {
+		/*
+		 * try to remove a directory, if it fails and we were going to
+		 * create a directory anyway, tell the caller (return a 1)
+		 */
+		if (rmdir(name) < 0) {
+			if (type == PAX_DIR)
+				return(1);
+			syswarn(1,errno,"Unable to remove directory %s", name);
+			return(-1);
+		}
+		return(0);
+	}
+
+	/*
+	 * try to get rid of all non-directory type nodes
+	 */
+	if (unlink(name) < 0) {
+		syswarn(1, errno, "Could not unlink %s", name);
+		return(-1);
+	}
+	return(0);
+}
+
+/*
+ * chk_path()
+ *	We were trying to create some kind of node in the file system and it
+ *	failed. chk_path() makes sure the path up to the node exists and is
+ *	writeable. When we have to create a directory that is missing along the
+ *	path somewhere, the directory we create will be set to the same
+ *	uid/gid as the file has (when uid and gid are being preserved).
+ *	NOTE: this routine is a real performance loss. It is only used as a
+ *	last resort when trying to create entries in the file system.
+ * Return:
+ *	-1 when it could find nothing it is allowed to fix.
+ *	0 otherwise
+ */
+
+#ifdef __STDC__
+int
+chk_path( register char *name, uid_t st_uid, gid_t st_gid)
+#else
+int
+chk_path(name, st_uid, st_gid)
+	register char *name;
+	uid_t st_uid;
+	gid_t st_gid;
+#endif
+{
+	register char *spt = name;
+	struct stat sb;
+	int retval = -1;
+
+	/*
+	 * watch out for paths with nodes stored directly in / (e.g. /bozo)
+	 */
+	if (*spt == '/')
+		++spt;
+
+	for(;;) {
+		/*
+		 * work foward from the first / and check each part of the path
+		 */
+		spt = strchr(spt, '/');
+		if (spt == NULL)
+			break;
+		*spt = '\0';
+
+		/*
+		 * if it exists we assume it is a directory, it is not within
+		 * the spec (at least it seems to read that way) to alter the
+		 * file system for nodes NOT EXPLICITLY stored on the archive.
+		 * If that assumption is changed, you would test the node here
+		 * and figure out how to get rid of it (probably like some
+		 * recursive unlink()) or fix up the directory permissions if
+		 * required (do an access()).
+		 */
+		if (lstat(name, &sb) == 0) {
+			*(spt++) = '/';
+			continue;
+		}
+
+		/*
+		 * the path fails at this point, see if we can create the
+		 * needed directory and continue on
+		 */
+		if (mkdir(name, S_IRWXU | S_IRWXG | S_IRWXO) < 0) {
+			*spt = '/';
+			retval = -1;
+			break;
+		}
+
+		/*
+		 * we were able to create the directory. We will tell the
+		 * caller that we found something to fix, and it is ok to try
+		 * and create the node again.
+		 */
+		retval = 0;
+		if (pids)
+			(void)set_ids(name, st_uid, st_gid);
+
+		/*
+		 * make sure the user doen't have some strange umask that
+		 * causes this newly created directory to be unusable. We fix
+		 * the modes and restore them back to the creation default at
+		 * the end of pax
+		 */
+		if ((access(name, R_OK | W_OK | X_OK) < 0) &&
+		    (lstat(name, &sb) == 0)) {
+			set_pmode(name, ((sb.st_mode & FILEBITS) | S_IRWXU));
+			add_dir(name, spt - name, &sb, 1);
+		}
+		*(spt++) = '/';
+		continue;
+	}
+	return(retval);
+}
+
+/*
+ * set_ftime()
+ *	Set the access time and modification time for a named file. If frc is
+ *	non-zero we force these times to be set even if the user did not
+ *	request access and/or modification time preservation (this is also
+ *	used by -t to reset access times).
+ *	When ign is zero, only those times the user has asked for are set, the
+ *	other ones are left alone. We do not assume the un-documented feature
+ *	of many utimes() implementations that consider a 0 time value as a do
+ *	not set request.
+ */
+
+#ifdef __STDC__
+void
+set_ftime(char *fnm, time_t mtime, time_t atime, int frc)
+#else
+void
+set_ftime(fnm, mtime, atime, frc)
+	char *fnm;
+	time_t mtime;
+	time_t atime;
+	int frc;
+#endif
+{
+	static struct timeval tv[2] = {{0L, 0L}, {0L, 0L}};
+	struct stat sb;
+
+	tv[0].tv_sec = (long)atime;
+	tv[1].tv_sec = (long)mtime;
+	if (!frc && (!patime || !pmtime)) {
+		/*
+		 * if we are not forcing, only set those times the user wants
+		 * set. We get the current values of the times if we need them.
+		 */
+		if (lstat(fnm, &sb) == 0) {
+			if (!patime)
+				tv[0].tv_sec = (long)sb.st_atime;
+			if (!pmtime)
+				tv[1].tv_sec = (long)sb.st_mtime;
+		} else
+			syswarn(0,errno,"Unable to obtain file stats %s", fnm);
+	}
+
+	/*
+	 * set the times
+	 */
+	if (utimes(fnm, tv) < 0)
+		syswarn(1, errno, "Access/modification time set failed on: %s",
+		    fnm);
+	return;
+}
+
+/*
+ * set_ids()
+ *	set the uid and gid of a file system node
+ * Return:
+ *	0 when set, -1 on failure
+ */
+
+#ifdef __STDC__
+int
+set_ids(char *fnm, uid_t uid, gid_t gid)
+#else
+int
+set_ids(fnm, uid, gid)
+	char *fnm;
+	uid_t uid;
+	gid_t gid;
+#endif
+{
+	if (chown(fnm, uid, gid) < 0) {
+		/*
+		 * ignore EPERM unless in verbose mode or being run by root.
+		 * if running as pax, POSIX requires a warning.
+		 */
+		if (strcmp(NM_PAX, argv0) == 0 || errno != EPERM || vflag ||
+		    geteuid() == 0)
+			syswarn(1, errno, "Unable to set file uid/gid of %s",
+			    fnm);
+		return(-1);
+	}
+	return(0);
+}
+
+/*
+ * set_lids()
+ *	set the uid and gid of a file system node
+ * Return:
+ *	0 when set, -1 on failure
+ */
+
+#ifdef __STDC__
+int
+set_lids(char *fnm, uid_t uid, gid_t gid)
+#else
+int
+set_lids(fnm, uid, gid)
+	char *fnm;
+	uid_t uid;
+	gid_t gid;
+#endif
+{
+#ifdef __APPLE__
+	if (chown(fnm, uid, gid) < 0) {
+#else
+	if (lchown(fnm, uid, gid) < 0) {
+#endif
+		/*
+		 * ignore EPERM unless in verbose mode or being run by root.
+		 * if running as pax, POSIX requires a warning.
+		 */
+		if (strcmp(NM_PAX, argv0) == 0 || errno != EPERM || vflag ||
+		    geteuid() == 0)
+			syswarn(1, errno, "Unable to set file uid/gid of %s",
+			    fnm);
+		return(-1);
+	}
+	return(0);
+}
+
+/*
+ * set_pmode()
+ *	Set file access mode
+ */
+
+#ifdef __STDC__
+void
+set_pmode(char *fnm, mode_t mode)
+#else
+void
+set_pmode(fnm, mode)
+	char *fnm;
+	mode_t mode;
+#endif
+{
+	mode &= ABITS;
+	if (chmod(fnm, mode) < 0)
+		syswarn(1, errno, "Could not set permissions on %s", fnm);
+	return;
+}
+
+/*
+ * file_write()
+ *	Write/copy a file (during copy or archive extract). This routine knows
+ *	how to copy files with lseek holes in it. (Which are read as file
+ *	blocks containing all 0's but do not have any file blocks associated
+ *	with the data). Typical examples of these are files created by dbm
+ *	variants (.pag files). While the file size of these files are huge, the
+ *	actual storage is quite small (the files are sparse). The problem is
+ *	the holes read as all zeros so are probably stored on the archive that
+ *	way (there is no way to determine if the file block is really a hole,
+ *	we only know that a file block of all zero's can be a hole).
+ *	At this writing, no major archive format knows how to archive files
+ *	with holes. However, on extraction (or during copy, -rw) we have to
+ *	deal with these files. Without detecting the holes, the files can
+ *	consume a lot of file space if just written to disk. This replacement
+ *	for write when passed the basic allocation size of a file system block,
+ *	uses lseek whenever it detects the input data is all 0 within that
+ *	file block. In more detail, the strategy is as follows:
+ *	While the input is all zero keep doing an lseek. Keep track of when we
+ *	pass over file block boundries. Only write when we hit a non zero
+ *	input. once we have written a file block, we continue to write it to
+ *	the end (we stop looking at the input). When we reach the start of the
+ *	next file block, start checking for zero blocks again. Working on file
+ *	block boundries significantly reduces the overhead when copying files
+ *	that are NOT very sparse. This overhead (when compared to a write) is
+ *	almost below the measurement resolution on many systems. Without it,
+ *	files with holes cannot be safely copied. It does has a side effect as
+ *	it can put holes into files that did not have them before, but that is
+ *	not a problem since the file contents are unchanged (in fact it saves
+ *	file space). (Except on paging files for diskless clients. But since we
+ *	cannot determine one of those file from here, we ignore them). If this
+ *	ever ends up on a system where CTG files are supported and the holes
+ *	are not desired, just do a conditional test in those routines that
+ *	call file_write() and have it call write() instead. BEFORE CLOSING THE
+ *	FILE, make sure to call file_flush() when the last write finishes with
+ *	an empty block. A lot of file systems will not create an lseek hole at
+ *	the end. In this case we drop a single 0 at the end to force the
+ *	trailing 0's in the file.
+ *	---Parameters---
+ *	rem: how many bytes left in this file system block
+ *	isempt: have we written to the file block yet (is it empty)
+ *	sz: basic file block allocation size
+ *	cnt: number of bytes on this write
+ *	str: buffer to write
+ * Return:
+ *	number of bytes written, -1 on write (or lseek) error.
+ */
+
+#ifdef __STDC__
+int
+file_write(int fd, char *str, register int cnt, int *rem, int *isempt, int sz,
+	char *name)
+#else
+int
+file_write(fd, str, cnt, rem, isempt, sz, name)
+	int fd;
+	char *str;
+	register int cnt;
+	int *rem;
+	int *isempt;
+	int sz;
+	char *name;
+#endif
+{
+	register char *pt;
+	register char *end;
+	register int wcnt;
+	register char *st = str;
+
+	/*
+	 * while we have data to process
+	 */
+	while (cnt) {
+		if (!*rem) {
+			/*
+			 * We are now at the start of file system block again
+			 * (or what we think one is...). start looking for
+			 * empty blocks again
+			 */
+			*isempt = 1;
+			*rem = sz;
+		}
+
+		/*
+		 * only examine up to the end of the current file block or
+		 * remaining characters to write, whatever is smaller
+		 */
+		wcnt = MIN(cnt, *rem);
+		cnt -= wcnt;
+		*rem -= wcnt;
+		if (*isempt) {
+			/*
+			 * have not written to this block yet, so we keep
+			 * looking for zero's
+			 */
+			pt = st;
+			end = st + wcnt;
+
+			/*
+			 * look for a zero filled buffer
+			 */
+			while ((pt < end) && (*pt == '\0'))
+				++pt;
+
+			if (pt == end) {
+				/*
+				 * skip, buf is empty so far
+				 */
+				if (lseek(fd, (off_t)wcnt, SEEK_CUR) < 0) {
+					syswarn(1,errno,"File seek on %s",
+					    name);
+					return(-1);
+				}
+				st = pt;
+				continue;
+			}
+			/*
+			 * drat, the buf is not zero filled
+			 */
+			*isempt = 0;
+		}
+
+		/*
+		 * have non-zero data in this file system block, have to write
+		 */
+		if (write(fd, st, wcnt) != wcnt) {
+			syswarn(1, errno, "Failed write to file %s", name);
+			return(-1);
+		}
+		st += wcnt;
+	}
+	return(st - str);
+}
+
+/*
+ * file_flush()
+ *	when the last file block in a file is zero, many file systems will not
+ *	let us create a hole at the end. To get the last block with zeros, we
+ *	write the last BYTE with a zero (back up one byte and write a zero).
+ */
+
+#ifdef __STDC__
+void
+file_flush(int fd, char *fname, int isempt)
+#else
+void
+file_flush(fd, fname, isempt)
+	int fd;
+	char *fname;
+	int isempt;
+#endif
+{
+	static char blnk[] = "\0";
+
+	/*
+	 * silly test, but make sure we are only called when the last block is
+	 * filled with all zeros.
+	 */
+	if (!isempt)
+		return;
+
+	/*
+	 * move back one byte and write a zero
+	 */
+	if (lseek(fd, (off_t)-1, SEEK_CUR) < 0) {
+		syswarn(1, errno, "Failed seek on file %s", fname);
+		return;
+	}
+
+	if (write(fd, blnk, 1) < 0)
+		syswarn(1, errno, "Failed write to file %s", fname);
+	return;
+}
+
+/*
+ * rdfile_close()
+ *	close a file we have beed reading (to copy or archive). If we have to
+ *	reset access time (tflag) do so (the times are stored in arcn).
+ */
+
+#ifdef __STDC__
+void
+rdfile_close(register ARCHD *arcn, register int *fd)
+#else
+void
+rdfile_close(arcn, fd)
+	register ARCHD *arcn;
+	register int *fd;
+#endif
+{
+	/*
+	 * make sure the file is open
+	 */
+	if (*fd < 0)
+		return;
+
+	(void)close(*fd);
+	*fd = -1;
+	if (!tflag)
+		return;
+
+	/*
+	 * user wants last access time reset
+	 */
+	set_ftime(arcn->org_name, arcn->sb.st_mtime, arcn->sb.st_atime, 1);
+	return;
+}
+
+/*
+ * set_crc()
+ *	read a file to calculate its crc. This is a real drag. Archive formats
+ *	that have this, end up reading the file twice (we have to write the
+ *	header WITH the crc before writing the file contents. Oh well...
+ * Return:
+ *	0 if was able to calculate the crc, -1 otherwise
+ */
+
+#ifdef __STDC__
+int
+set_crc(register ARCHD *arcn, register int fd)
+#else
+int
+set_crc(arcn, fd)
+	register ARCHD *arcn;
+	register int fd;
+#endif
+{
+	register int i;
+	register int res;
+	off_t cpcnt = 0L;
+	u_long size;
+	unsigned long crc = 0L;
+	char tbuf[FILEBLK];
+	struct stat sb;
+
+	if (fd < 0) {
+		/*
+		 * hmm, no fd, should never happen. well no crc then.
+		 */
+		arcn->crc = 0L;
+		return(0);
+	}
+
+	if ((size = (u_long)arcn->sb.st_blksize) > (u_long)sizeof(tbuf))
+		size = (u_long)sizeof(tbuf);
+
+	/*
+	 * read all the bytes we think that there are in the file. If the user
+	 * is trying to archive an active file, forget this file.
+	 */
+	for(;;) {
+		if ((res = read(fd, tbuf, size)) <= 0)
+			break;
+		cpcnt += res;
+		for (i = 0; i < res; ++i)
+			crc += (tbuf[i] & 0xff);
+	}
+
+	/*
+	 * safety check. we want to avoid archiving files that are active as
+	 * they can create inconsistant archive copies.
+	 */
+	if (cpcnt != arcn->sb.st_size)
+		paxwarn(1, "File changed size %s", arcn->org_name);
+	else if (fstat(fd, &sb) < 0)
+		syswarn(1, errno, "Failed stat on %s", arcn->org_name);
+	else if (arcn->sb.st_mtime != sb.st_mtime)
+		paxwarn(1, "File %s was modified during read", arcn->org_name);
+	else if (lseek(fd, (off_t)0L, SEEK_SET) < 0)
+		syswarn(1, errno, "File rewind failed on: %s", arcn->org_name);
+	else {
+		arcn->crc = crc;
+		return(0);
+	}
+	return(-1);
+}
diff --git a/pax/ftree.c b/pax/ftree.c
new file mode 100644
index 0000000..c5fcc44
--- /dev/null
+++ b/pax/ftree.c
@@ -0,0 +1,565 @@
+/*	$OpenBSD: ftree.c,v 1.8 1997/09/01 18:29:49 deraadt Exp $	*/
+/*	$NetBSD: ftree.c,v 1.4 1995/03/21 09:07:21 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)ftree.c	8.2 (Berkeley) 4/18/94";
+#else
+static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: ftree.c,v 1.8 1997/09/01 18:29:49 deraadt Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <fts.h>
+#include "pax.h"
+#include "ftree.h"
+#include "extern.h"
+
+/*
+ * routines to interface with the fts library function.
+ *
+ * file args supplied to pax are stored on a single linked list (of type FTREE)
+ * and given to fts to be processed one at a time. pax "selects" files from
+ * the expansion of each arg into the corresponding file tree (if the arg is a
+ * directory, otherwise the node itself is just passed to pax). The selection
+ * is modified by the -n and -u flags. The user is informed when a specific
+ * file arg does not generate any selected files. -n keeps expanding the file
+ * tree arg until one of its files is selected, then skips to the next file
+ * arg. when the user does not supply the file trees as command line args to
+ * pax, they are read from stdin
+ */
+
+static FTS *ftsp = NULL;		/* curent FTS handle */
+static int ftsopts;			/* options to be used on fts_open */
+static char *farray[2];			/* array for passing each arg to fts */
+static FTREE *fthead = NULL;		/* head of linked list of file args */
+static FTREE *fttail = NULL;		/* tail of linked list of file args */
+static FTREE *ftcur = NULL;		/* current file arg being processed */
+static FTSENT *ftent = NULL;		/* current file tree entry */
+static int ftree_skip;			/* when set skip to next file arg */
+
+static int ftree_arg __P((void));
+
+/*
+ * ftree_start()
+ *	initialize the options passed to fts_open() during this run of pax
+ *	options are based on the selection of pax options by the user
+ *	fts_start() also calls fts_arg() to open the first valid file arg. We
+ *	also attempt to reset directory access times when -t (tflag) is set.
+ * Return:
+ *	0 if there is at least one valid file arg to process, -1 otherwise
+ */
+
+#ifdef __STDC__
+int
+ftree_start(void)
+#else
+int
+ftree_start()
+#endif
+{
+	/*
+	 * set up the operation mode of fts, open the first file arg. We must
+	 * use FTS_NOCHDIR, as the user may have to open multiple archives and
+	 * if fts did a chdir off into the boondocks, we may create an archive
+	 * volume in an place where the user did not expect to.
+	 */
+	ftsopts = FTS_NOCHDIR;
+
+	/*
+	 * optional user flags that effect file traversal
+	 * -H command line symlink follow only (half follow)
+	 * -L follow sylinks (logical)
+	 * -P do not follow sylinks (physical). This is the default.
+	 * -X do not cross over mount points
+	 * -t preserve access times on files read.
+	 * -n select only the first member of a file tree when a match is found
+	 * -d do not extract subtrees rooted at a directory arg.
+	 */
+	if (Lflag)
+		ftsopts |= FTS_LOGICAL;
+	else
+		ftsopts |= FTS_PHYSICAL;
+	if (Hflag)
+#	ifdef NET2_FTS
+		paxwarn(0, "The -H flag is not supported on this version");
+#	else
+		ftsopts |= FTS_COMFOLLOW;
+#	endif
+	if (Xflag)
+		ftsopts |= FTS_XDEV;
+
+	if ((fthead == NULL) && ((farray[0] = malloc(PAXPATHLEN+2)) == NULL)) {
+		paxwarn(1, "Unable to allocate memory for file name buffer");
+		return(-1);
+	}
+
+	if (ftree_arg() < 0)
+		return(-1);
+	if (tflag && (atdir_start() < 0))
+		return(-1);
+	return(0);
+}
+
+/*
+ * ftree_add()
+ *	add the arg to the linked list of files to process. Each will be
+ *	processed by fts one at a time
+ * Return:
+ *	0 if added to the linked list, -1 if failed
+ */
+
+#ifdef __STDC__
+int
+ftree_add(register char *str, int chflg)
+#else
+int
+ftree_add(str, chflg)
+	register char *str;
+	int chflg;
+#endif
+{
+	register FTREE *ft;
+	register int len;
+
+	/*
+	 * simple check for bad args
+	 */
+	if ((str == NULL) || (*str == '\0')) {
+		paxwarn(0, "Invalid file name arguement");
+		return(-1);
+	}
+
+	/*
+	 * allocate FTREE node and add to the end of the linked list (args are
+	 * processed in the same order they were passed to pax). Get rid of any
+	 * trailing / the user may pass us. (watch out for / by itself).
+	 */
+	if ((ft = (FTREE *)malloc(sizeof(FTREE))) == NULL) {
+		paxwarn(0, "Unable to allocate memory for filename");
+		return(-1);
+	}
+
+	if (((len = strlen(str) - 1) > 0) && (str[len] == '/'))
+		str[len] = '\0';
+	ft->fname = str;
+	ft->refcnt = 0;
+	ft->chflg = chflg;
+	ft->fow = NULL;
+	if (fthead == NULL) {
+		fttail = fthead = ft;
+		return(0);
+	}
+	fttail->fow = ft;
+	fttail = ft;
+	return(0);
+}
+
+/*
+ * ftree_sel()
+ *	this entry has been selected by pax. bump up reference count and handle
+ *	-n and -d processing.
+ */
+
+#ifdef __STDC__
+void
+ftree_sel(register ARCHD *arcn)
+#else
+void
+ftree_sel(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	/*
+	 * set reference bit for this pattern. This linked list is only used
+	 * when file trees are supplied pax as args. The list is not used when
+	 * the trees are read from stdin.
+	 */
+	if (ftcur != NULL)
+		ftcur->refcnt = 1;
+
+	/*
+	 * if -n we are done with this arg, force a skip to the next arg when
+	 * pax asks for the next file in next_file().
+	 * if -d we tell fts only to match the directory (if the arg is a dir)
+	 * and not the entire file tree rooted at that point.
+	 */
+	if (nflag)
+		ftree_skip = 1;
+
+	if (!dflag || (arcn->type != PAX_DIR))
+		return;
+
+	if (ftent != NULL)
+		(void)fts_set(ftsp, ftent, FTS_SKIP);
+}
+
+/*
+ * ftree_chk()
+ *	called at end on pax execution. Prints all those file args that did not
+ *	have a selected member (reference count still 0)
+ */
+
+#ifdef __STDC__
+void
+ftree_chk(void)
+#else
+void
+ftree_chk()
+#endif
+{
+	register FTREE *ft;
+	register int wban = 0;
+
+	/*
+	 * make sure all dir access times were reset.
+	 */
+	if (tflag)
+		atdir_end();
+
+	/*
+	 * walk down list and check reference count. Print out those members
+	 * that never had a match
+	 */
+	for (ft = fthead; ft != NULL; ft = ft->fow) {
+		if ((ft->refcnt > 0) || ft->chflg)
+			continue;
+		if (wban == 0) {
+			paxwarn(1,"WARNING! These file names were not selected:");
+			++wban;
+		}
+		(void)fprintf(stderr, "%s\n", ft->fname);
+	}
+}
+
+/*
+ * ftree_arg()
+ *	Get the next file arg for fts to process. Can be from either the linked
+ *	list or read from stdin when the user did not them as args to pax. Each
+ *	arg is processed until the first successful fts_open().
+ * Return:
+ *	0 when the next arg is ready to go, -1 if out of file args (or EOF on
+ *	stdin).
+ */
+
+#ifdef __STDC__
+static int
+ftree_arg(void)
+#else
+static int
+ftree_arg()
+#endif
+{
+	register char *pt;
+
+	/*
+	 * close off the current file tree
+	 */
+	if (ftsp != NULL) {
+		(void)fts_close(ftsp);
+		ftsp = NULL;
+	}
+
+	/*
+	 * keep looping until we get a valid file tree to process. Stop when we
+	 * reach the end of the list (or get an eof on stdin)
+	 */
+	for(;;) {
+		if (fthead == NULL) {
+			/*
+			 * the user didn't supply any args, get the file trees
+			 * to process from stdin; 
+			 */
+			if (fgets(farray[0], PAXPATHLEN+1, stdin) == NULL)
+				return(-1);
+			if ((pt = strchr(farray[0], '\n')) != NULL)
+				*pt = '\0';
+		} else {
+			/*
+			 * the user supplied the file args as arguements to pax
+			 */
+			if (ftcur == NULL)
+				ftcur = fthead;
+			else if ((ftcur = ftcur->fow) == NULL)
+				return(-1);
+			if (ftcur->chflg) {
+				/* First fchdir() back... */
+				if (fchdir(cwdfd) < 0) {
+					syswarn(1, errno,
+					  "Can't fchdir to starting directory");
+					return(-1);
+				}
+				if (chdir(ftcur->fname) < 0) {
+					syswarn(1, errno, "Can't chdir to %s",
+					    ftcur->fname);
+					return(-1);
+				}
+				continue;
+			} else
+				farray[0] = ftcur->fname;
+		}
+
+		/*
+		 * watch it, fts wants the file arg stored in a array of char
+		 * ptrs, with the last one a null. we use a two element array
+		 * and set farray[0] to point at the buffer with the file name
+		 * in it. We cannnot pass all the file args to fts at one shot
+		 * as we need to keep a handle on which file arg generates what
+		 * files (the -n and -d flags need this). If the open is
+		 * successful, return a 0.
+		 */
+		if ((ftsp = fts_open(farray, ftsopts, NULL)) != NULL)
+			break;
+	}
+	return(0);
+}
+
+/*
+ * next_file()
+ *	supplies the next file to process in the supplied archd structure.
+ * Return:
+ *	0 when contents of arcn have been set with the next file, -1 when done.
+ */
+
+#ifdef __STDC__
+int
+next_file(register ARCHD *arcn)
+#else
+int
+next_file(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	register int cnt;
+	time_t atime;
+	time_t mtime;
+
+	/*
+	 * ftree_sel() might have set the ftree_skip flag if the user has the
+	 * -n option and a file was selected from this file arg tree. (-n says
+	 * only one member is matched for each pattern) ftree_skip being 1 
+	 * forces us to go to the next arg now.
+	 */
+	if (ftree_skip) {
+		/*
+		 * clear and go to next arg
+		 */
+		ftree_skip = 0;
+		if (ftree_arg() < 0)
+			return(-1);
+	}
+
+	/*
+	 * loop until we get a valid file to process
+	 */
+	for(;;) {
+		if ((ftent = fts_read(ftsp)) == NULL) {
+			/*
+			 * out of files in this tree, go to next arg, if none
+			 * we are done
+			 */
+			if (ftree_arg() < 0)
+				return(-1);
+			continue;
+		}
+
+		/*
+		 * handle each type of fts_read() flag
+		 */
+		switch(ftent->fts_info) {
+		case FTS_D:
+		case FTS_DEFAULT:
+		case FTS_F:
+		case FTS_SL:
+		case FTS_SLNONE:
+			/*
+			 * these are all ok
+			 */
+			break;
+		case FTS_DP:
+			/*
+			 * already saw this directory. If the user wants file
+			 * access times reset, we use this to restore the
+			 * access time for this directory since this is the
+			 * last time we will see it in this file subtree
+			 * remember to force the time (this is -t on a read
+			 * directory, not a created directory).
+			 */
+#			ifdef NET2_FTS
+			if (!tflag || (get_atdir(ftent->fts_statb.st_dev,
+			    ftent->fts_statb.st_ino, &mtime, &atime) < 0))
+#			else
+			if (!tflag || (get_atdir(ftent->fts_statp->st_dev,
+			    ftent->fts_statp->st_ino, &mtime, &atime) < 0))
+#			endif
+				continue;
+			set_ftime(ftent->fts_path, mtime, atime, 1);
+			continue;
+		case FTS_DC:
+			/*
+			 * fts claims a file system cycle
+			 */
+			paxwarn(1,"File system cycle found at %s",ftent->fts_path);
+			continue;
+		case FTS_DNR:
+#			ifdef NET2_FTS
+			syswarn(1, errno,
+#			else
+			syswarn(1, ftent->fts_errno,
+#			endif
+			    "Unable to read directory %s", ftent->fts_path);
+			continue;
+		case FTS_ERR:
+#			ifdef NET2_FTS
+			syswarn(1, errno,
+#			else
+			syswarn(1, ftent->fts_errno,
+#			endif
+			    "File system traversal error");
+			continue;
+		case FTS_NS:
+		case FTS_NSOK:
+#			ifdef NET2_FTS
+			syswarn(1, errno,
+#			else
+			syswarn(1, ftent->fts_errno,
+#			endif
+			    "Unable to access %s", ftent->fts_path);
+			continue;
+		}
+
+		/*
+		 * ok got a file tree node to process. copy info into arcn
+		 * structure (initialize as required)
+		 */
+		arcn->skip = 0;
+		arcn->pad = 0;
+		arcn->ln_nlen = 0;
+		arcn->ln_name[0] = '\0';
+#		ifdef NET2_FTS
+		arcn->sb = ftent->fts_statb;
+#		else
+		arcn->sb = *(ftent->fts_statp);
+#		endif
+
+		/*
+		 * file type based set up and copy into the arcn struct
+		 * SIDE NOTE:
+		 * we try to reset the access time on all files and directories
+		 * we may read when the -t flag is specified. files are reset
+		 * when we close them after copying. we reset the directories
+		 * when we are done with their file tree (we also clean up at
+		 * end in case we cut short a file tree traversal). However
+		 * there is no way to reset access times on symlinks.
+		 */
+		switch(S_IFMT & arcn->sb.st_mode) {
+		case S_IFDIR:
+			arcn->type = PAX_DIR;
+			if (!tflag)
+				break;
+			add_atdir(ftent->fts_path, arcn->sb.st_dev,
+			    arcn->sb.st_ino, arcn->sb.st_mtime,
+			    arcn->sb.st_atime);
+			break;
+		case S_IFCHR:
+			arcn->type = PAX_CHR;
+			break;
+		case S_IFBLK:
+			arcn->type = PAX_BLK;
+			break;
+		case S_IFREG:
+			/*
+			 * only regular files with have data to store on the
+			 * archive. all others will store a zero length skip.
+			 * the skip field is used by pax for actual data it has
+			 * to read (or skip over).
+			 */
+			arcn->type = PAX_REG;
+			arcn->skip = arcn->sb.st_size;
+			break;
+		case S_IFLNK:
+			arcn->type = PAX_SLK;
+			/*
+			 * have to read the symlink path from the file
+			 */
+			if ((cnt = readlink(ftent->fts_path, arcn->ln_name,
+			    PAXPATHLEN)) < 0) {
+				syswarn(1, errno, "Unable to read symlink %s",
+				    ftent->fts_path);
+				continue;
+			}
+			/*
+			 * set link name length, watch out readlink does not
+			 * allways null terminate the link path
+			 */
+			arcn->ln_name[cnt] = '\0';
+			arcn->ln_nlen = cnt;
+			break;
+		case S_IFSOCK:
+			/*
+			 * under BSD storing a socket is senseless but we will
+			 * let the format specific write function make the
+			 * decision of what to do with it.
+			 */
+			arcn->type = PAX_SCK;
+			break;
+		case S_IFIFO:
+			arcn->type = PAX_FIF;
+			break;
+		}
+		break;
+	}
+
+	/*
+	 * copy file name, set file name length
+	 */
+	arcn->nlen = l_strncpy(arcn->name, ftent->fts_path, sizeof(arcn->name) - 1);
+	arcn->name[arcn->nlen] = '\0';
+	arcn->org_name = ftent->fts_path;
+	return(0);
+}
diff --git a/pax/ftree.h b/pax/ftree.h
new file mode 100644
index 0000000..5ac8ff9
--- /dev/null
+++ b/pax/ftree.h
@@ -0,0 +1,54 @@
+/*	$OpenBSD: ftree.h,v 1.3 1996/10/27 06:45:11 downsj Exp $	*/
+/*	$NetBSD: ftree.h,v 1.3 1995/03/21 09:07:23 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)ftree.h	8.1 (Berkeley) 5/31/93
+ */
+
+/*
+ * Data structure used by the ftree.c routines to store the file args to be
+ * handed to fts(). It keeps a reference count of which args generated a
+ * "selected" member
+ */
+
+typedef struct ftree {
+	char		*fname;		/* file tree name */
+	int		refcnt;		/* has tree had a selected file? */
+	int		chflg;		/* change directory flag */
+	struct ftree	*fow;		/* pointer to next entry on list */
+} FTREE;
diff --git a/pax/gen_subs.c b/pax/gen_subs.c
new file mode 100644
index 0000000..4f5f898
--- /dev/null
+++ b/pax/gen_subs.c
@@ -0,0 +1,467 @@
+/*	$OpenBSD: gen_subs.c,v 1.8 1997/09/01 18:29:51 deraadt Exp $	*/
+/*	$NetBSD: gen_subs.c,v 1.5 1995/03/21 09:07:26 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)gen_subs.c	8.1 (Berkeley) 5/31/93";
+#else
+static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: gen_subs.c,v 1.8 1997/09/01 18:29:51 deraadt Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <tzfile.h>
+#include <utmp.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include "pax.h"
+#include "extern.h"
+
+/*
+ * a collection of general purpose subroutines used by pax
+ */
+
+/*
+ * constants used by ls_list() when printing out archive members
+ */
+#define MODELEN 20
+#define DATELEN 64
+#define SIXMONTHS	 ((DAYSPERNYEAR / 2) * SECSPERDAY)
+#define CURFRMT		"%b %e %H:%M"
+#define OLDFRMT		"%b %e  %Y"
+#ifndef UT_NAMESIZE
+#define UT_NAMESIZE	8
+#endif
+#define UT_GRPSIZE	6
+
+/*
+ * ls_list()
+ *	list the members of an archive in ls format
+ */
+
+#ifdef __STDC__
+void
+ls_list(register ARCHD *arcn, time_t now, FILE *fp)
+#else
+void
+ls_list(arcn, now, fp)
+	register ARCHD *arcn;
+	time_t now;
+	FILE *fp;
+#endif
+{
+	register struct stat *sbp;
+	char f_mode[MODELEN];
+	char f_date[DATELEN];
+	char *timefrmt;
+
+	/*
+	 * if not verbose, just print the file name
+	 */
+	if (!vflag) {
+		(void)fprintf(fp, "%s\n", arcn->name);
+		(void)fflush(fp);
+		return;
+	}
+
+	/*
+	 * user wants long mode
+	 */
+	sbp = &(arcn->sb);
+	strmode(sbp->st_mode, f_mode);
+
+	if (ltmfrmt == NULL) {
+		/*
+		 * no locale specified format. time format based on age
+		 * compared to the time pax was started.
+		 */
+		if ((sbp->st_mtime + SIXMONTHS) <= now)
+			timefrmt = OLDFRMT;
+		else
+			timefrmt = CURFRMT;
+	} else
+		timefrmt = ltmfrmt;
+
+	/*
+	 * print file mode, link count, uid, gid and time
+	 */
+	if (strftime(f_date,DATELEN,timefrmt,localtime((const time_t *)&(sbp->st_mtime))) == 0)
+		f_date[0] = '\0';
+	(void)fprintf(fp, "%s%2u %-*s %-*s ", f_mode, sbp->st_nlink,
+		UT_NAMESIZE, name_uid(sbp->st_uid, 1), UT_GRPSIZE,
+		name_gid(sbp->st_gid, 1));
+
+	/*
+	 * print device id's for devices, or sizes for other nodes
+	 */
+	if ((arcn->type == PAX_CHR) || (arcn->type == PAX_BLK))
+#		ifdef NET2_STAT
+		(void)fprintf(fp, "%4u,%4u ", MAJOR(sbp->st_rdev),
+#		else
+		(void)fprintf(fp, "%4lu,%4lu ", (unsigned long)MAJOR(sbp->st_rdev),
+#		endif
+		    (unsigned long)MINOR(sbp->st_rdev));
+	else {
+#		ifdef NET2_STAT
+		(void)fprintf(fp, "%9lu ", sbp->st_size);
+#		else
+		(void)fprintf(fp, "%9qu ", sbp->st_size);
+#		endif
+	}
+
+	/*
+	 * print name and link info for hard and soft links
+	 */
+	(void)fprintf(fp, "%s %s", f_date, arcn->name);
+	if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG))
+		(void)fprintf(fp, " == %s\n", arcn->ln_name);
+	else if (arcn->type == PAX_SLK)
+		(void)fprintf(fp, " => %s\n", arcn->ln_name);
+	else
+		(void)putc('\n', fp);
+	(void)fflush(fp);
+	return;
+}
+
+/*
+ * tty_ls()
+ * 	print a short summary of file to tty.
+ */
+
+#ifdef __STDC__
+void
+ls_tty(register ARCHD *arcn)
+#else
+void
+ls_tty(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	char f_date[DATELEN];
+	char f_mode[MODELEN];
+	char *timefrmt;
+
+	if (ltmfrmt == NULL) {
+		/*
+		 * no locale specified format
+		 */
+		if ((arcn->sb.st_mtime + SIXMONTHS) <= time(NULL))
+			timefrmt = OLDFRMT;
+		else
+			timefrmt = CURFRMT;
+	} else
+		timefrmt = ltmfrmt;
+
+	/*
+	 * convert time to string, and print
+	 */
+	if (strftime(f_date, DATELEN, timefrmt,
+	    localtime((const time_t *)&(arcn->sb.st_mtime))) == 0)
+		f_date[0] = '\0';
+	strmode(arcn->sb.st_mode, f_mode);
+	tty_prnt("%s%s %s\n", f_mode, f_date, arcn->name);
+	return;
+}
+
+/*
+ * l_strncpy()
+ *	copy src to dest up to len chars (stopping at first '\0').
+ *	when src is shorter than len, pads to len with '\0'. 
+ * Return:
+ *	number of chars copied. (Note this is a real performance win over
+ *	doing a strncpy(), a strlen(), and then a possible memset())
+ */
+
+#ifdef __STDC__
+int
+l_strncpy(register char *dest, register char *src, int len)
+#else
+int
+l_strncpy(dest, src, len)
+	register char *dest;
+	register char *src;
+	int len;
+#endif
+{
+	register char *stop;
+	register char *start;
+
+	stop = dest + len;
+	start = dest;
+	while ((dest < stop) && (*src != '\0'))
+		*dest++ = *src++;
+	len = dest - start;
+	while (dest < stop)
+		*dest++ = '\0';
+	return(len);
+}
+
+/*
+ * asc_ul()
+ *	convert hex/octal character string into a u_long. We do not have to
+ *	check for overflow! (the headers in all supported formats are not large
+ *	enough to create an overflow).
+ *	NOTE: strings passed to us are NOT TERMINATED.
+ * Return:
+ *	unsigned long value
+ */
+
+#ifdef __STDC__
+u_long
+asc_ul(register char *str, int len, register int base)
+#else
+u_long
+asc_ul(str, len, base)
+	register char *str;
+	int len;
+	register int base;
+#endif
+{
+	register char *stop;
+	u_long tval = 0;
+
+	stop = str + len;
+
+	/*
+	 * skip over leading blanks and zeros
+	 */
+	while ((str < stop) && ((*str == ' ') || (*str == '0')))
+		++str;
+
+	/*
+	 * for each valid digit, shift running value (tval) over to next digit
+	 * and add next digit
+	 */
+	if (base == HEX) {
+		while (str < stop) {
+			if ((*str >= '0') && (*str <= '9'))
+				tval = (tval << 4) + (*str++ - '0');
+			else if ((*str >= 'A') && (*str <= 'F'))
+				tval = (tval << 4) + 10 + (*str++ - 'A');
+			else if ((*str >= 'a') && (*str <= 'f'))
+				tval = (tval << 4) + 10 + (*str++ - 'a');
+			else
+				break;
+		}
+	} else {
+ 		while ((str < stop) && (*str >= '0') && (*str <= '7'))
+			tval = (tval << 3) + (*str++ - '0');
+	}
+	return(tval);
+}
+
+/*
+ * ul_asc()
+ *	convert an unsigned long into an hex/oct ascii string. pads with LEADING
+ *	ascii 0's to fill string completely
+ *	NOTE: the string created is NOT TERMINATED.
+ */
+
+#ifdef __STDC__
+int
+ul_asc(u_long val, register char *str, register int len, register int base)
+#else
+int
+ul_asc(val, str, len, base)
+	u_long val;
+	register char *str;
+	register int len;
+	register int base;
+#endif
+{
+	register char *pt;
+	u_long digit;
+
+	/*
+	 * WARNING str is not '\0' terminated by this routine
+	 */
+	pt = str + len - 1;
+
+	/*
+	 * do a tailwise conversion (start at right most end of string to place
+	 * least significant digit). Keep shifting until conversion value goes
+	 * to zero (all digits were converted)
+	 */
+	if (base == HEX) {
+		while (pt >= str) {
+			if ((digit = (val & 0xf)) < 10)
+				*pt-- = '0' + (char)digit;
+			else
+				*pt-- = 'a' + (char)(digit - 10);
+			if ((val = (val >> 4)) == (u_long)0)
+				break;
+		}
+	} else {
+		while (pt >= str) {
+			*pt-- = '0' + (char)(val & 0x7);
+			if ((val = (val >> 3)) == (u_long)0)
+				break;
+		}
+	}
+
+	/*
+	 * pad with leading ascii ZEROS. We return -1 if we ran out of space.
+	 */
+	while (pt >= str)
+		*pt-- = '0';
+	if (val != (u_long)0)
+		return(-1);
+	return(0);
+}
+
+#ifndef NET2_STAT
+/*
+ * asc_uqd()
+ *	convert hex/octal character string into a u_quad_t. We do not have to
+ *	check for overflow! (the headers in all supported formats are not large
+ *	enough to create an overflow).
+ *	NOTE: strings passed to us are NOT TERMINATED.
+ * Return:
+ *	u_quad_t value
+ */
+
+#ifdef __STDC__
+u_quad_t
+asc_uqd(register char *str, int len, register int base)
+#else
+u_quad_t
+asc_uqd(str, len, base)
+	register char *str;
+	int len;
+	register int base;
+#endif
+{
+	register char *stop;
+	u_quad_t tval = 0;
+
+	stop = str + len;
+
+	/*
+	 * skip over leading blanks and zeros
+	 */
+	while ((str < stop) && ((*str == ' ') || (*str == '0')))
+		++str;
+
+	/*
+	 * for each valid digit, shift running value (tval) over to next digit
+	 * and add next digit
+	 */
+	if (base == HEX) {
+		while (str < stop) {
+			if ((*str >= '0') && (*str <= '9'))
+				tval = (tval << 4) + (*str++ - '0');
+			else if ((*str >= 'A') && (*str <= 'F'))
+				tval = (tval << 4) + 10 + (*str++ - 'A');
+			else if ((*str >= 'a') && (*str <= 'f'))
+				tval = (tval << 4) + 10 + (*str++ - 'a');
+			else
+				break;
+		}
+	} else {
+ 		while ((str < stop) && (*str >= '0') && (*str <= '7'))
+			tval = (tval << 3) + (*str++ - '0');
+	}
+	return(tval);
+}
+
+/*
+ * uqd_asc()
+ *	convert an u_quad_t into a hex/oct ascii string. pads with LEADING
+ *	ascii 0's to fill string completely
+ *	NOTE: the string created is NOT TERMINATED.
+ */
+
+#ifdef __STDC__
+int
+uqd_asc(u_quad_t val, register char *str, register int len, register int base)
+#else
+int
+uqd_asc(val, str, len, base)
+	u_quad_t val;
+	register char *str;
+	register int len;
+	register int base;
+#endif
+{
+	register char *pt;
+	u_quad_t digit;
+
+	/*
+	 * WARNING str is not '\0' terminated by this routine
+	 */
+	pt = str + len - 1;
+
+	/*
+	 * do a tailwise conversion (start at right most end of string to place
+	 * least significant digit). Keep shifting until conversion value goes
+	 * to zero (all digits were converted)
+	 */
+	if (base == HEX) {
+		while (pt >= str) {
+			if ((digit = (val & 0xf)) < 10)
+				*pt-- = '0' + (char)digit;
+			else
+				*pt-- = 'a' + (char)(digit - 10);
+			if ((val = (val >> 4)) == (u_quad_t)0)
+				break;
+		}
+	} else {
+		while (pt >= str) {
+			*pt-- = '0' + (char)(val & 0x7);
+			if ((val = (val >> 3)) == (u_quad_t)0)
+				break;
+		}
+	}
+
+	/*
+	 * pad with leading ascii ZEROS. We return -1 if we ran out of space.
+	 */
+	while (pt >= str)
+		*pt-- = '0';
+	if (val != (u_quad_t)0)
+		return(-1);
+	return(0);
+}
+#endif
diff --git a/pax/getoldopt.c b/pax/getoldopt.c
new file mode 100644
index 0000000..8a15a2f
--- /dev/null
+++ b/pax/getoldopt.c
@@ -0,0 +1,73 @@
+/*	$OpenBSD: getoldopt.c,v 1.3 1997/09/01 18:29:52 deraadt Exp $	*/
+/*	$NetBSD: getoldopt.c,v 1.3 1995/03/21 09:07:28 cgd Exp $	*/
+
+/*
+ * Plug-compatible replacement for getopt() for parsing tar-like
+ * arguments.  If the first argument begins with "-", it uses getopt;
+ * otherwise, it uses the old rules used by tar, dump, and ps.
+ *
+ * Written 25 August 1985 by John Gilmore (ihnp4!hoptoad!gnu) and placed
+ * in the Pubic Domain for your edification and enjoyment.
+ */
+
+#ifndef lint
+static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: getoldopt.c,v 1.3 1997/09/01 18:29:52 deraadt Exp $";
+#endif /* not lint */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int
+getoldopt(argc, argv, optstring)
+	int	argc;
+	char	**argv;
+	char	*optstring;
+{
+	extern char	*optarg;	/* Points to next arg */
+	extern int	optind;		/* Global argv index */
+	static char	*key;		/* Points to next keyletter */
+	static char	use_getopt;	/* !=0 if argv[1][0] was '-' */
+	char		c;
+	char		*place;
+
+	optarg = NULL;
+
+	if (key == NULL) {		/* First time */
+		if (argc < 2) return EOF;
+		key = argv[1];
+		if (*key == '-')
+			use_getopt++;
+		else
+			optind = 2;
+	}
+
+	if (use_getopt)
+		return getopt(argc, argv, optstring);
+
+	c = *key++;
+	if (c == '\0') {
+		key--;
+		return EOF;
+	}
+	place = strchr(optstring, c);
+
+	if (place == NULL || c == ':') {
+		fprintf(stderr, "%s: unknown option %c\n", argv[0], c);
+		return('?');
+	}
+
+	place++;
+	if (*place == ':') {
+		if (optind < argc) {
+			optarg = argv[optind];
+			optind++;
+		} else {
+			fprintf(stderr, "%s: %c argument missing\n",
+				argv[0], c);
+			return('?');
+		}
+	}
+
+	return(c);
+}
diff --git a/pax/options.c b/pax/options.c
new file mode 100644
index 0000000..9a64e1f
--- /dev/null
+++ b/pax/options.c
@@ -0,0 +1,1515 @@
+/*	$OpenBSD: options.c,v 1.31 1998/01/22 06:21:29 millert Exp $	*/
+/*	$NetBSD: options.c,v 1.6 1996/03/26 23:54:18 mrg Exp $	*/
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)options.c	8.2 (Berkeley) 4/18/94";
+#else
+static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: options.c,v 1.31 1998/01/22 06:21:29 millert Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/mtio.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <paths.h>
+#include "pax.h"
+#include "options.h"
+#include "cpio.h"
+#include "tar.h"
+#include "extern.h"
+
+/*
+ * Routines which handle command line options
+ */
+
+static char flgch[] = FLGCH;	/* list of all possible flags */
+static OPLIST *ophead = NULL;	/* head for format specific options -x */
+static OPLIST *optail = NULL;	/* option tail */
+
+static int no_op __P((void));
+static void printflg __P((unsigned int));
+static int c_frmt __P((const void *, const void *));
+static off_t str_offt __P((char *));
+static void pax_options __P((register int, register char **));
+static void pax_usage __P((void));
+static void tar_options __P((register int, register char **));
+static void tar_usage __P((void));
+static void cpio_options __P((register int, register char **));
+static void cpio_usage __P((void));
+
+#define GZIP_CMD	"gzip"		/* command to run as gzip */
+#define COMPRESS_CMD	"compress"	/* command to run as compress */
+
+/*
+ *	Format specific routine table - MUST BE IN SORTED ORDER BY NAME
+ *	(see pax.h for description of each function)
+ *
+ * 	name, blksz, hdsz, udev, hlk, blkagn, inhead, id, st_read,
+ *	read, end_read, st_write, write, end_write, trail,
+ *	rd_data, wr_data, options
+ */
+
+FSUB fsub[] = {
+/* 0: OLD BINARY CPIO */
+	{"bcpio", 5120, sizeof(HD_BCPIO), 1, 0, 0, 1, bcpio_id, cpio_strd,
+	bcpio_rd, bcpio_endrd, cpio_stwr, bcpio_wr, cpio_endwr, cpio_trail,
+	rd_wrfile, wr_rdfile, bad_opt},
+
+/* 1: OLD OCTAL CHARACTER CPIO */
+	{"cpio", 5120, sizeof(HD_CPIO), 1, 0, 0, 1, cpio_id, cpio_strd,
+	cpio_rd, cpio_endrd, cpio_stwr, cpio_wr, cpio_endwr, cpio_trail,
+	rd_wrfile, wr_rdfile, bad_opt},
+
+/* 2: SVR4 HEX CPIO */
+	{"sv4cpio", 5120, sizeof(HD_VCPIO), 1, 0, 0, 1, vcpio_id, cpio_strd,
+	vcpio_rd, vcpio_endrd, cpio_stwr, vcpio_wr, cpio_endwr, cpio_trail,
+	rd_wrfile, wr_rdfile, bad_opt},
+
+/* 3: SVR4 HEX CPIO WITH CRC */
+	{"sv4crc", 5120, sizeof(HD_VCPIO), 1, 0, 0, 1, crc_id, crc_strd,
+	vcpio_rd, vcpio_endrd, crc_stwr, vcpio_wr, cpio_endwr, cpio_trail,
+	rd_wrfile, wr_rdfile, bad_opt},
+
+/* 4: OLD TAR */
+	{"tar", 10240, BLKMULT, 0, 1, BLKMULT, 0, tar_id, no_op,
+	tar_rd, tar_endrd, no_op, tar_wr, tar_endwr, tar_trail,
+	rd_wrfile, wr_rdfile, tar_opt},
+
+/* 5: POSIX USTAR */
+	{"ustar", 10240, BLKMULT, 0, 1, BLKMULT, 0, ustar_id, ustar_strd,
+	ustar_rd, tar_endrd, ustar_stwr, ustar_wr, tar_endwr, tar_trail,
+	rd_wrfile, wr_rdfile, bad_opt},
+};
+#define	F_OCPIO	0	/* format when called as cpio -6 */
+#define	F_ACPIO	1	/* format when called as cpio -c */
+#define	F_CPIO	3	/* format when called as cpio */
+#define F_OTAR	4	/* format when called as tar -o */
+#define F_TAR	5	/* format when called as tar */
+#define DEFLT	5	/* default write format from list above */
+
+/*
+ * ford is the archive search order used by get_arc() to determine what kind
+ * of archive we are dealing with. This helps to properly id  archive formats
+ * some formats may be subsets of others....
+ */
+int ford[] = {5, 4, 3, 2, 1, 0, -1 };
+
+/*
+ * options()
+ *	figure out if we are pax, tar or cpio. Call the appropriate options
+ *	parser
+ */
+
+#ifdef __STDC__
+void
+options(register int argc, register char **argv)
+#else
+void
+options(argc, argv)
+	register int argc;
+	register char **argv;
+#endif
+{
+
+	/*
+	 * Are we acting like pax, tar or cpio (based on argv[0])
+	 */
+	if ((argv0 = strrchr(argv[0], '/')) != NULL)
+		argv0++;
+	else
+		argv0 = argv[0];
+
+	if (strcmp(NM_TAR, argv0) == 0)
+		return(tar_options(argc, argv));
+	else if (strcmp(NM_CPIO, argv0) == 0)
+		return(cpio_options(argc, argv));
+	/*
+	 * assume pax as the default
+	 */
+	argv0 = NM_PAX;
+	return(pax_options(argc, argv));
+}
+
+/*
+ * pax_options()
+ *	look at the user specified flags. set globals as required and check if
+ *	the user specified a legal set of flags. If not, complain and exit
+ */
+
+#ifdef __STDC__
+static void
+pax_options(register int argc, register char **argv)
+#else
+static void
+pax_options(argc, argv)
+	register int argc;
+	register char **argv;
+#endif
+{
+	register int c;
+	register int i;
+	unsigned int flg = 0;
+	unsigned int bflg = 0;
+	register char *pt;
+	FSUB tmp;
+	extern char *optarg;
+	extern int optind;
+
+	/*
+	 * process option flags
+	 */
+	while ((c=getopt(argc,argv,"ab:cdf:iklno:p:rs:tuvwx:zB:DE:G:HLPT:U:XYZ"))
+	    != EOF) {
+		switch (c) {
+		case 'a':
+			/*
+			 * append
+			 */
+			flg |= AF;
+			break;
+		case 'b':
+			/*
+			 * specify blocksize
+			 */
+			flg |= BF;
+			if ((wrblksz = (int)str_offt(optarg)) <= 0) {
+				paxwarn(1, "Invalid block size %s", optarg);
+				pax_usage();
+			}
+			break;
+		case 'c':
+			/*
+			 * inverse match on patterns
+			 */
+			cflag = 1;
+			flg |= CF;
+			break;
+		case 'd':
+			/*
+			 * match only dir on extract, not the subtree at dir
+			 */
+			dflag = 1;
+			flg |= DF;
+			break;
+		case 'f':
+			/*
+			 * filename where the archive is stored
+			 */
+			arcname = optarg;
+			flg |= FF;
+			break;
+		case 'i':
+			/*
+			 * interactive file rename
+			 */
+			iflag = 1;
+			flg |= IF;
+			break;
+		case 'k':
+			/*
+			 * do not clobber files that exist
+			 */
+			kflag = 1;
+			flg |= KF;
+			break;
+		case 'l':
+			/*
+			 * try to link src to dest with copy (-rw)
+			 */
+			lflag = 1;
+			flg |= LF;
+			break;
+		case 'n':
+			/*
+			 * select first match for a pattern only
+			 */
+			nflag = 1;
+			flg |= NF;
+			break;
+		case 'o':
+			/*
+			 * pass format specific options
+			 */
+			flg |= OF;
+			if (opt_add(optarg) < 0)
+				pax_usage();
+			break;
+		case 'p':
+			/*
+			 * specify file characteristic options
+			 */
+			for (pt = optarg; *pt != '\0'; ++pt) {
+				switch(*pt) {
+				case 'a':
+					/*
+					 * do not preserve access time
+					 */
+					patime = 0;
+					break;
+				case 'e':
+					/*
+					 * preserve user id, group id, file
+					 * mode, access/modification times
+					 */
+					pids = 1;
+					pmode = 1;
+					patime = 1;
+					pmtime = 1;
+					break;
+				case 'm':
+					/*
+					 * do not preserve modification time
+					 */
+					pmtime = 0;
+					break;
+				case 'o':
+					/*
+					 * preserve uid/gid
+					 */
+					pids = 1;
+					break;
+				case 'p':
+					/*
+					 * preserver file mode bits
+					 */
+					pmode = 1;
+					break;
+				default:
+					paxwarn(1, "Invalid -p string: %c", *pt);
+					pax_usage();
+					break;
+				}
+			}
+			flg |= PF;
+			break;
+		case 'r':
+			/*
+			 * read the archive
+			 */
+			flg |= RF;
+			break;
+		case 's':
+			/*
+			 * file name substitution name pattern
+			 */
+			if (rep_add(optarg) < 0) {
+				pax_usage();
+				break;
+			}
+			flg |= SF;
+			break;
+		case 't':
+			/*
+			 * preserve access time on filesystem nodes we read
+			 */
+			tflag = 1;
+			flg |= TF;
+			break;
+		case 'u':
+			/*
+			 * ignore those older files
+			 */
+			uflag = 1;
+			flg |= UF;
+			break;
+		case 'v':
+			/*
+			 * verbose operation mode
+			 */
+			vflag = 1;
+			flg |= VF;
+			break;
+		case 'w':
+			/*
+			 * write an archive
+			 */
+			flg |= WF;
+			break;
+		case 'x':
+			/*
+			 * specify an archive format on write
+			 */
+			tmp.name = optarg;
+			if ((frmt = (FSUB *)bsearch((void *)&tmp, (void *)fsub,
+			    sizeof(fsub)/sizeof(FSUB), sizeof(FSUB), c_frmt)) != NULL) {
+				flg |= XF;
+				break;
+			}
+			paxwarn(1, "Unknown -x format: %s", optarg);
+			(void)fputs("pax: Known -x formats are:", stderr);
+			for (i = 0; i < (sizeof(fsub)/sizeof(FSUB)); ++i)
+				(void)fprintf(stderr, " %s", fsub[i].name);
+			(void)fputs("\n\n", stderr);
+			pax_usage();
+			break;
+		case 'z':
+			/*
+			 * use gzip.  Non standard option.
+			 */
+			zflag = 1;
+			gzip_program = GZIP_CMD;
+			break;
+		case 'B':
+			/*
+			 * non-standard option on number of bytes written on a
+			 * single archive volume.
+			 */
+			if ((wrlimit = str_offt(optarg)) <= 0) {
+				paxwarn(1, "Invalid write limit %s", optarg);
+				pax_usage();
+			}
+			if (wrlimit % BLKMULT) {
+				paxwarn(1, "Write limit is not a %d byte multiple",
+				    BLKMULT);
+				pax_usage();
+			}
+			flg |= CBF;
+			break;
+		case 'D':
+			/*
+			 * On extraction check file inode change time before the
+			 * modification of the file name. Non standard option.
+			 */
+			Dflag = 1;
+			flg |= CDF;
+			break;
+		case 'E':
+			/*
+			 * non-standard limit on read faults
+			 * 0 indicates stop after first error, values
+			 * indicate a limit, "NONE" try forever
+			 */
+			flg |= CEF;
+			if (strcmp(NONE, optarg) == 0)
+				maxflt = -1;
+			else if ((maxflt = atoi(optarg)) < 0) {
+				paxwarn(1, "Error count value must be positive");
+				pax_usage();
+			}
+			break;
+		case 'G':
+			/*
+			 * non-standard option for selecting files within an
+			 * archive by group (gid or name)
+			 */
+			if (grp_add(optarg) < 0) {
+				pax_usage();
+				break;
+			}
+			flg |= CGF;
+			break;
+		case 'H':
+			/*
+			 * follow command line symlinks only
+			 */
+			Hflag = 1;
+			flg |= CHF;
+			break;
+		case 'L':
+			/*
+			 * follow symlinks
+			 */
+			Lflag = 1;
+			flg |= CLF;
+			break;
+		case 'P':
+			/*
+			 * do NOT follow symlinks (default)
+			 */
+			Lflag = 0;
+			flg |= CPF;
+			break;
+		case 'T':
+			/*
+			 * non-standard option for selecting files within an
+			 * archive by modification time range (lower,upper)
+			 */
+			if (trng_add(optarg) < 0) {
+				pax_usage();
+				break;
+			}
+			flg |= CTF;
+			break;
+		case 'U':
+			/*
+			 * non-standard option for selecting files within an
+			 * archive by user (uid or name)
+			 */
+			if (usr_add(optarg) < 0) {
+				pax_usage();
+				break;
+			}
+			flg |= CUF;
+			break;
+		case 'X':
+			/*
+			 * do not pass over mount points in the file system
+			 */
+			Xflag = 1;
+			flg |= CXF;
+			break;
+		case 'Y':
+			/*
+			 * On extraction check file inode change time after the
+			 * modification of the file name. Non standard option.
+			 */
+			Yflag = 1;
+			flg |= CYF;
+			break;
+		case 'Z':
+			/*
+			 * On extraction check modification time after the
+			 * modification of the file name. Non standard option.
+			 */
+			Zflag = 1;
+			flg |= CZF;
+			break;
+		default:
+			pax_usage();
+			break;
+		}
+	}
+
+	/*
+	 * figure out the operation mode of pax read,write,extract,copy,append
+	 * or list. check that we have not been given a bogus set of flags
+	 * for the operation mode.
+	 */
+	if (ISLIST(flg)) {
+		act = LIST;
+		bflg = flg & BDLIST;
+	} else if (ISEXTRACT(flg)) {
+		act = EXTRACT;
+		bflg = flg & BDEXTR;
+	} else if (ISARCHIVE(flg)) {
+		act = ARCHIVE;
+		bflg = flg & BDARCH;
+	} else if (ISAPPND(flg)) {
+		act = APPND;
+		bflg = flg & BDARCH;
+	} else if (ISCOPY(flg)) {
+		act = COPY;
+		bflg = flg & BDCOPY;
+	} else
+		pax_usage();
+	if (bflg) {
+		printflg(flg);
+		pax_usage();
+	}
+
+	/*
+	 * if we are writing (ARCHIVE) we use the default format if the user
+	 * did not specify a format. when we write during an APPEND, we will
+	 * adopt the format of the existing archive if none was supplied.
+	 */
+	if (!(flg & XF) && (act == ARCHIVE))
+		frmt = &(fsub[DEFLT]);
+
+	/*
+	 * process the args as they are interpreted by the operation mode
+	 */
+	switch (act) {
+	case LIST:
+	case EXTRACT:
+		for (; optind < argc; optind++)
+			if (pat_add(argv[optind], NULL) < 0)
+				pax_usage();
+		break;
+	case COPY:
+		if (optind >= argc) {
+			paxwarn(0, "Destination directory was not supplied");
+			pax_usage();
+		}
+		--argc;
+		dirptr = argv[argc];
+		/* FALL THROUGH */
+	case ARCHIVE:
+	case APPND:
+		for (; optind < argc; optind++)
+			if (ftree_add(argv[optind], 0) < 0)
+				pax_usage();
+		/*
+		 * no read errors allowed on updates/append operation!
+		 */
+		maxflt = 0;
+		break;
+	}
+}
+
+
+/*
+ * tar_options()
+ *	look at the user specified flags. set globals as required and check if
+ *	the user specified a legal set of flags. If not, complain and exit
+ */
+
+#ifdef __STDC__
+static void
+tar_options(register int argc, register char **argv)
+#else
+static void
+tar_options(argc, argv)
+	register int argc;
+	register char **argv;
+#endif
+{
+	register int c;
+	int fstdin = 0;
+	int Oflag = 0;
+
+	/*
+	 * Set default values.
+	 */
+	rmleadslash = 1;
+
+	/*
+	 * process option flags
+	 */
+	while ((c = getoldopt(argc, argv,
+	    "b:cef:hmopruts:vwxzBC:HLOPXZ014578"))
+	    != EOF) {
+		switch(c) {
+		case 'b':
+			/*
+			 * specify blocksize in 512-byte blocks
+			 */
+			if ((wrblksz = (int)str_offt(optarg)) <= 0) {
+				paxwarn(1, "Invalid block size %s", optarg);
+				tar_usage();
+			}
+			wrblksz *= 512;		/* XXX - check for int oflow */
+			break;
+		case 'c':
+			/*
+			 * create an archive
+			 */
+			act = ARCHIVE;
+			break;
+		case 'e':
+			/*
+			 * stop after first error
+			 */
+			maxflt = 0;
+			break;
+		case 'f':
+			/*
+			 * filename where the archive is stored
+			 */
+			if ((optarg[0] == '-') && (optarg[1]== '\0')) {
+				/*
+				 * treat a - as stdin
+				 */
+				fstdin = 1;
+				arcname = NULL;
+				break;
+			}
+			fstdin = 0;
+			arcname = optarg;
+			break;
+		case 'h':
+			/*
+			 * follow symlinks
+			 */
+			Lflag = 1;
+			break;
+		case 'm':
+			/*
+			 * do not preserve modification time
+			 */
+			pmtime = 0;
+			break;
+		case 'o':
+			if (opt_add("write_opt=nodir") < 0)
+				tar_usage();
+		case 'O':
+			Oflag = 1;
+			break;
+		case 'p':
+			/*
+			 * preserve user id, group id, file
+			 * mode, access/modification times
+			 */
+			pids = 1;
+			pmode = 1;
+			patime = 1;
+			pmtime = 1;
+			break;
+		case 'r':
+		case 'u':
+			/*
+			 * append to the archive
+			 */
+			act = APPND;
+			break;
+		case 's':
+			/*
+			 * file name substitution name pattern
+			 */
+			if (rep_add(optarg) < 0) {
+				tar_usage();
+				break;
+			}
+			break;
+		case 't':
+			/*
+			 * list contents of the tape
+			 */
+			act = LIST;
+			break;
+		case 'v':
+			/*
+			 * verbose operation mode
+			 */
+			vflag++;
+			break;
+		case 'w':
+			/*
+			 * interactive file rename
+			 */
+			iflag = 1;
+			break;
+		case 'x':
+			/*
+			 * write an archive, preserve ids if root
+			 */
+			act = EXTRACT;
+			if (geteuid() == 0)
+				pids = 1;
+			break;
+		case 'z':
+			/*
+			 * use gzip.  Non standard option.
+			 */
+			zflag = 1;
+			gzip_program = GZIP_CMD;
+			break;
+		case 'B':
+			/*
+			 * Nothing to do here, this is pax default
+			 */
+			break;
+		case 'C':
+			chdname = optarg;
+			break;
+		case 'H':
+			/*
+			 * follow command line symlinks only
+			 */
+			Hflag = 1;
+			break;
+		case 'L':
+			/*
+			 * follow symlinks
+			 */
+			Lflag = 1;
+			break;
+		case 'P':
+			/*
+			 * do not remove leading '/' from pathnames
+			 */
+			rmleadslash = 0;
+			break;
+		case 'X':
+			/*
+			 * do not pass over mount points in the file system
+			 */
+			Xflag = 1;
+			break;
+		case 'Z':
+			/*
+			 * use compress.
+			 */
+			zflag = 1;
+			gzip_program = COMPRESS_CMD;
+			break;
+		case '0':
+			arcname = DEV_0;
+			break;
+		case '1':
+			arcname = DEV_1;
+			break;
+		case '4':
+			arcname = DEV_4;
+			break;
+		case '5':
+			arcname = DEV_5;
+			break;
+		case '7':
+			arcname = DEV_7;
+			break;
+		case '8':
+			arcname = DEV_8;
+			break;
+		default:
+			tar_usage();
+			break;
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	/* Traditional tar behaviour (pax wants to read filelist from stdin) */
+	if ((act == ARCHIVE || act == APPND) && argc == 0)
+		exit(0);
+
+	/*
+	 * if we are writing (ARCHIVE) specify tar, otherwise run like pax
+	 * (unless -o specified)
+	 */
+	if (act == ARCHIVE || act == APPND)
+		frmt = &(fsub[Oflag ? F_OTAR : F_TAR]);
+	else if (Oflag) {
+		paxwarn(1, "The -O/-o options are only valid when writing an archive");
+		tar_usage();		/* only valid when writing */
+	}
+
+	/*
+	 * process the args as they are interpreted by the operation mode
+	 */
+	switch (act) {
+	case LIST:
+	case EXTRACT:
+	default:
+		{
+			int sawpat = 0;
+
+			while (*argv != NULL) {
+				if (strcmp(*argv, "-C") == 0) {
+					if(*++argv == NULL)
+						break;
+					chdname = *argv++;
+
+					continue;
+				}
+				if (pat_add(*argv++, chdname) < 0)
+					tar_usage();
+				sawpat++;
+			}
+			/*
+			 * if patterns were added, we are doing	chdir()
+			 * on a file-by-file basis, else, just one 
+			 * global chdir (if any) after opening input.
+			 */
+			if (sawpat > 0)
+				chdname = NULL;
+		}
+		break;
+	case ARCHIVE:
+	case APPND:
+		if (chdname != NULL) {	/* initial chdir() */
+			if (ftree_add(chdname, 1) < 0)
+				tar_usage();
+		}
+
+		while (*argv != NULL) {
+			if (!strcmp(*argv, "-C")) {
+				if (*++argv == NULL)
+					break;
+				if (ftree_add(*argv++, 1) < 0)
+					tar_usage();
+			} else {
+				if (ftree_add(*argv++, 0) < 0)
+					tar_usage();
+			}
+		}
+		/*
+		 * no read errors allowed on updates/append operation!
+		 */
+		maxflt = 0;
+		break;
+	}
+	if (!fstdin && ((arcname == NULL) || (*arcname == '\0'))) {
+		arcname = getenv("TAPE");
+		if ((arcname == NULL) || (*arcname == '\0'))
+			arcname = _PATH_DEFTAPE;
+	}
+}
+
+int
+mkpath(path)
+	char *path;
+{
+	struct stat sb;
+	register char *slash;
+	int done = 0;
+
+	slash = path;
+
+	while (!done) {
+		slash += strspn(slash, "/");
+		slash += strcspn(slash, "/");
+
+		done = (*slash == '\0');
+		*slash = '\0';
+
+		if (stat(path, &sb)) {
+			if (errno != ENOENT || mkdir(path, 0777)) {
+				paxwarn(1, "%s", path);
+				return (-1);
+			}
+		} else if (!S_ISDIR(sb.st_mode)) {
+			syswarn(1, ENOTDIR, "%s", path);
+			return (-1);
+		}
+
+		if (!done)
+			*slash = '/';
+	}
+
+	return (0);
+}
+/*
+ * cpio_options()
+ *	look at the user specified flags. set globals as required and check if
+ *	the user specified a legal set of flags. If not, complain and exit
+ */
+
+#ifdef __STDC__
+static void
+cpio_options(register int argc, register char **argv)
+#else
+static void
+cpio_options(argc, argv)
+	register int argc;
+	register char **argv;
+#endif
+{
+	register int c, i;
+	size_t len;
+	char *str;
+	FSUB tmp;
+	FILE *fp;
+
+	kflag = 1;
+	pids = 1;
+	pmode = 1;
+	pmtime = 0;
+	arcname = NULL;
+	dflag = 1;
+	act = -1;
+	nodirs = 1;
+	while ((c=getopt(argc,argv,"abcdfiklmoprstuvzABC:E:F:H:I:LO:SZ6")) != EOF)
+		switch (c) {
+			case 'a':
+				/*
+				 * preserve access time on files read
+				 */
+				tflag = 1;
+				break;
+			case 'b':
+				/*
+				 * swap bytes and half-words when reading data
+				 */
+				break;
+			case 'c':
+				/*
+				 * ASCII cpio header
+				 */
+				frmt = &(fsub[F_ACPIO]);
+				break;
+			case 'd':
+				/*
+				 * create directories as needed
+				 */
+				nodirs = 0;
+				break;
+			case 'f':
+				/*
+				 * invert meaning of pattern list
+				 */
+				cflag = 1;
+				break;
+			case 'i':
+				/*
+				 * restore an archive
+				 */
+				act = EXTRACT;
+				break;
+			case 'k':
+				break;
+			case 'l':
+				/*
+				 * use links instead of copies when possible
+				 */
+				lflag = 1;
+				break;
+			case 'm':
+				/*
+				 * preserve modification time
+				 */
+				pmtime = 1;
+				break;
+			case 'o':
+				/*
+				 * create an archive
+				 */
+				act = ARCHIVE;
+				frmt = &(fsub[F_CPIO]);
+				break;
+			case 'p':
+				/*
+				 * copy-pass mode
+				 */
+				act = COPY;
+				break;
+			case 'r':
+				/*
+				 * interactively rename files
+				 */
+				iflag = 1;
+				break;
+			case 's':
+				/*
+				 * swap bytes after reading data
+				 */
+				break;
+			case 't':
+				/*
+				 * list contents of archive
+				 */
+				act = LIST;
+				break;
+			case 'u':
+				/*
+				 * replace newer files
+				 */
+				kflag = 0;
+				break;
+			case 'v':
+				/*
+				 * verbose operation mode
+				 */
+				vflag = 1;
+				break;
+			case 'z':
+				/*
+				 * use gzip.  Non standard option.
+				 */
+				zflag = 1;
+				gzip_program = GZIP_CMD;
+				break;
+			case 'A':
+				/*
+				 * append mode
+				 */
+				act = APPND;
+				break;
+			case 'B':
+				/*
+				 * Use 5120 byte block size
+				 */
+				wrblksz = 5120;
+				break;
+			case 'C':
+				/*
+				 * set block size in bytes
+				 */
+				wrblksz = atoi(optarg);
+				break;
+			case 'E':
+				/*
+				 * file with patterns to extract or list
+				 */
+				if ((fp = fopen(optarg, "r")) == NULL) {
+					paxwarn(1, "Unable to open file '%s' for read", optarg);
+					cpio_usage();
+				}
+				while ((str = fgetln(fp, &len)) != NULL) {
+					str[len - 1] = '\0';
+					pat_add(str, NULL);
+				}
+				fclose(fp);
+				break;
+			case 'F':
+			case 'I':
+			case 'O':
+				/*
+				 * filename where the archive is stored
+				 */
+				if ((optarg[0] == '-') && (optarg[1]== '\0')) {
+					/*
+					 * treat a - as stdin
+					 */
+					arcname = NULL;
+					break;
+				}
+				arcname = optarg;
+				break;
+			case 'H':
+				/*
+				 * specify an archive format on write
+				 */
+				tmp.name = optarg;
+				if ((frmt = (FSUB *)bsearch((void *)&tmp, (void *)fsub,
+				    sizeof(fsub)/sizeof(FSUB), sizeof(FSUB), c_frmt)) != NULL)
+					break;
+				paxwarn(1, "Unknown -H format: %s", optarg);
+				(void)fputs("cpio: Known -H formats are:", stderr);
+				for (i = 0; i < (sizeof(fsub)/sizeof(FSUB)); ++i)
+					(void)fprintf(stderr, " %s", fsub[i].name);
+				(void)fputs("\n\n", stderr);
+				cpio_usage();
+				break;
+			case 'L':
+				/*
+				 * follow symbolic links
+				 */
+				Lflag = 1;
+				break;
+			case 'S':
+				/*
+				 * swap halfwords after reading data
+				 */
+				break;
+			case 'Z':
+				/*
+				 * use compress.  Non standard option.
+				 */
+				zflag = 1;
+				gzip_program = COMPRESS_CMD;
+				break;
+			case '6':
+				/*
+				 * process Version 6 cpio format
+				 */
+				frmt = &(fsub[F_OCPIO]);
+				break;
+			case '?':
+			default:
+				cpio_usage();
+				break;
+		}
+	argc -= optind;
+	argv += optind;
+
+	/*
+	 * process the args as they are interpreted by the operation mode
+	 */
+	switch (act) {
+		case LIST:
+		case EXTRACT:
+			while (*argv != NULL)
+				if (pat_add(*argv++, NULL) < 0)
+					cpio_usage();
+			break;
+		case COPY:
+			if (*argv == NULL) {
+				paxwarn(0, "Destination directory was not supplied");
+				cpio_usage();
+			}
+			dirptr = *argv;
+			if (mkpath(dirptr) < 0)
+				cpio_usage();
+			--argc;
+			++argv;
+			/* FALL THROUGH */
+		case ARCHIVE:
+		case APPND:
+			if (*argv != NULL)
+				cpio_usage();
+			/*
+			 * no read errors allowed on updates/append operation!
+			 */
+			maxflt = 0;
+			while ((str = fgetln(stdin, &len)) != NULL) {
+				str[len - 1] = '\0';
+				ftree_add(strdup(str), NULL);
+			}
+			break;
+		default:
+			cpio_usage();
+			break;
+	}
+}
+
+/*
+ * printflg()
+ *	print out those invalid flag sets found to the user
+ */
+
+#ifdef __STDC__
+static void
+printflg(unsigned int flg)
+#else
+static void
+printflg(flg)
+	unsigned int flg;
+#endif
+{
+	int nxt;
+	int pos = 0;
+
+	(void)fprintf(stderr,"%s: Invalid combination of options:", argv0);
+	while ((nxt = ffs(flg)) != 0) {
+		flg = flg >> nxt;
+		pos += nxt;
+		(void)fprintf(stderr, " -%c", flgch[pos-1]);
+	}
+	(void)putc('\n', stderr);
+}
+
+/*
+ * c_frmt()
+ *	comparison routine used by bsearch to find the format specified
+ *	by the user
+ */
+
+#ifdef __STDC__
+static int
+c_frmt(const void *a, const void *b)
+#else
+static int
+c_frmt(a, b)
+	void *a;
+	void *b;
+#endif
+{
+	return(strcmp(((FSUB *)a)->name, ((FSUB *)b)->name));
+}
+
+/*
+ * opt_next()
+ *	called by format specific options routines to get each format specific
+ *	flag and value specified with -o
+ * Return:
+ *	pointer to next OPLIST entry or NULL (end of list).
+ */
+
+#ifdef __STDC__
+OPLIST *
+opt_next(void)
+#else
+OPLIST *
+opt_next()
+#endif
+{
+	OPLIST *opt;
+
+	if ((opt = ophead) != NULL)
+		ophead = ophead->fow;
+	return(opt);
+}
+
+/*
+ * bad_opt()
+ *	generic routine used to complain about a format specific options
+ *	when the format does not support options.
+ */
+
+#ifdef __STDC__
+int
+bad_opt(void)
+#else
+int
+bad_opt()
+#endif
+{
+	register OPLIST *opt;
+
+	if (ophead == NULL)
+		return(0);
+	/*
+	 * print all we were given
+	 */
+	paxwarn(1,"These format options are not supported");
+	while ((opt = opt_next()) != NULL)
+		(void)fprintf(stderr, "\t%s = %s\n", opt->name, opt->value);
+	pax_usage();
+	return(0);
+}
+
+/*
+ * opt_add()
+ *	breaks the value supplied to -o into a option name and value. options
+ *	are given to -o in the form -o name-value,name=value
+ *	mulltiple -o may be specified.
+ * Return:
+ *	0 if format in name=value format, -1 if -o is passed junk
+ */
+
+#ifdef __STDC__
+int
+opt_add(register char *str)
+#else
+int
+opt_add(str)
+	register char *str;
+#endif
+{
+	register OPLIST *opt;
+	register char *frpt;
+	register char *pt;
+	register char *endpt;
+
+	if ((str == NULL) || (*str == '\0')) {
+		paxwarn(0, "Invalid option name");
+		return(-1);
+	}
+	if ((str = strdup(str)) == NULL) {
+		paxwarn(0, "Unable to allocate space for option list");
+		return(-1);
+	}
+	frpt = endpt = str;
+
+	/*
+	 * break into name and values pieces and stuff each one into a
+	 * OPLIST structure. When we know the format, the format specific
+	 * option function will go through this list
+	 */
+	while ((frpt != NULL) && (*frpt != '\0')) {
+		if ((endpt = strchr(frpt, ',')) != NULL)
+			*endpt = '\0';
+		if ((pt = strchr(frpt, '=')) == NULL) {
+			paxwarn(0, "Invalid options format");
+			free(str);
+			return(-1);
+		}
+		if ((opt = (OPLIST *)malloc(sizeof(OPLIST))) == NULL) {
+			paxwarn(0, "Unable to allocate space for option list");
+			free(str);
+			return(-1);
+		}
+		*pt++ = '\0';
+		opt->name = frpt;
+		opt->value = pt;
+		opt->fow = NULL;
+		if (endpt != NULL)
+			frpt = endpt + 1;
+		else
+			frpt = NULL;
+		if (ophead == NULL) {
+			optail = ophead = opt;
+			continue;
+		}
+		optail->fow = opt;
+		optail = opt;
+	}
+	return(0);
+}
+
+/*
+ * str_offt()
+ *	Convert an expression of the following forms to an off_t > 0.
+ * 	1) A positive decimal number.
+ *	2) A positive decimal number followed by a b (mult by 512).
+ *	3) A positive decimal number followed by a k (mult by 1024).
+ *	4) A positive decimal number followed by a m (mult by 512).
+ *	5) A positive decimal number followed by a w (mult by sizeof int)
+ *	6) Two or more positive decimal numbers (with/without k,b or w).
+ *	   seperated by x (also * for backwards compatibility), specifying
+ *	   the product of the indicated values.
+ * Return:
+ *	0 for an error, a positive value o.w.
+ */
+
+#ifdef __STDC__
+static off_t
+str_offt(char *val)
+#else
+static off_t
+str_offt(val)
+	char *val;
+#endif
+{
+	char *expr;
+	off_t num, t;
+
+#	ifdef NET2_STAT
+	num = strtol(val, &expr, 0);
+	if ((num == LONG_MAX) || (num <= 0) || (expr == val))
+#	else
+	num = strtoq(val, &expr, 0);
+	if ((num == QUAD_MAX) || (num <= 0) || (expr == val))
+#	endif
+		return(0);
+
+	switch(*expr) {
+	case 'b':
+		t = num;
+		num *= 512;
+		if (t > num)
+			return(0);
+		++expr;
+		break;
+	case 'k':
+		t = num;
+		num *= 1024;
+		if (t > num)
+			return(0);
+		++expr;
+		break;
+	case 'm':
+		t = num;
+		num *= 1048576;
+		if (t > num)
+			return(0);
+		++expr;
+		break;
+	case 'w':
+		t = num;
+		num *= sizeof(int);
+		if (t > num)
+			return(0);
+		++expr;
+		break;
+	}
+
+	switch(*expr) {
+		case '\0':
+			break;
+		case '*':
+		case 'x':
+			t = num;
+			num *= str_offt(expr + 1);
+			if (t > num)
+				return(0);
+			break;
+		default:
+			return(0);
+	}
+	return(num);
+}
+
+/*
+ * no_op()
+ *	for those option functions where the archive format has nothing to do.
+ * Return:
+ *	0
+ */
+
+#ifdef __STDC__
+static int
+no_op(void)
+#else
+static int
+no_op()
+#endif
+{
+	return(0);
+}
+
+/*
+ * pax_usage()
+ *	print the usage summary to the user
+ */
+
+#ifdef __STDC__
+void
+pax_usage(void)
+#else
+void
+pax_usage()
+#endif
+{
+	(void)fputs("usage: pax [-cdnv] [-E limit] [-f archive] ", stderr);
+	(void)fputs("[-s replstr] ... [-U user] ...", stderr);
+	(void)fputs("\n           [-G group] ... ", stderr);
+	(void)fputs("[-T [from_date][,to_date]] ... ", stderr);
+	(void)fputs("[pattern ...]\n", stderr);
+	(void)fputs("       pax -r [-cdiknuvDYZ] [-E limit] ", stderr);
+	(void)fputs("[-f archive] [-o options] ... \n", stderr);
+	(void)fputs("           [-p string] ... [-s replstr] ... ", stderr);
+	(void)fputs("[-U user] ... [-G group] ...\n	      ", stderr);
+	(void)fputs("[-T [from_date][,to_date]] ... ", stderr);
+	(void)fputs(" [pattern ...]\n", stderr);
+	(void)fputs("       pax -w [-dituvHLPX] [-b blocksize] ", stderr);
+	(void)fputs("[ [-a] [-f archive] ] [-x format] \n", stderr);
+	(void)fputs("           [-B bytes] [-s replstr] ... ", stderr);
+	(void)fputs("[-o options] ... [-U user] ...", stderr);
+	(void)fputs("\n           [-G group] ... ", stderr);
+	(void)fputs("[-T [from_date][,to_date][/[c][m]]] ... ", stderr);
+	(void)fputs("[file ...]\n", stderr);
+	(void)fputs("       pax -r -w [-diklntuvDHLPXYZ] ", stderr);
+	(void)fputs("[-p string] ... [-s replstr] ...", stderr);
+	(void)fputs("\n           [-U user] ... [-G group] ... ", stderr);
+	(void)fputs("[-T [from_date][,to_date][/[c][m]]] ... ", stderr);
+	(void)fputs("\n           [file ...] directory\n", stderr);
+	exit(1);
+}
+
+/*
+ * tar_usage()
+ *	print the usage summary to the user
+ */
+
+#ifdef __STDC__
+void
+tar_usage(void)
+#else
+void
+tar_usage()
+#endif
+{
+	(void)fputs("usage: tar -{txru}[cevfbmopswzBHLPXZ014578] [tapefile] ",
+		 stderr);
+	(void)fputs("[blocksize] [replstr] [-C directory] file1 file2...\n",
+	    stderr);
+	exit(1);
+}
+
+/*
+ * cpio_usage()
+ *	print the usage summary to the user
+ */
+
+#ifdef __STDC__
+void
+cpio_usage(void)
+#else
+void
+cpio_usage()
+#endif
+{
+	(void)fputs("usage: cpio -o [-aABcLvVzZ] [-C bytes] [-H format] [-O archive]\n", stderr);
+	(void)fputs("               [-F archive] < name-list [> archive]\n", stderr);
+	(void)fputs("       cpio -i [-bBcdfmnrsStuvVzZ6] [-C bytes] [-E file] [-H format]\n", stderr);
+	(void)fputs("               [-I archive] [-F archive] [pattern...] [< archive]\n", stderr);
+	(void)fputs("       cpio -p [-adlLmuvV] destination-directory < name-list\n", stderr);
+	exit(1);
+}
diff --git a/pax/options.h b/pax/options.h
new file mode 100644
index 0000000..d45f54a
--- /dev/null
+++ b/pax/options.h
@@ -0,0 +1,116 @@
+/*	$OpenBSD: options.h,v 1.2 1996/06/23 14:20:37 deraadt Exp $	*/
+/*	$NetBSD: options.h,v 1.3 1995/03/21 09:07:32 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)options.h	8.2 (Berkeley) 4/18/94
+ */
+
+/*
+ * argv[0] names. Used for tar and cpio emulation
+ */
+
+#define NM_TAR  "tar"
+#define NM_CPIO "cpio"
+#define NM_PAX  "pax"
+
+/*
+ * Constants used to specify the legal sets of flags in pax. For each major
+ * operation mode of pax, a set of illegal flags is defined. If any one of
+ * those illegal flags are found set, we scream and exit
+ */
+#define NONE	"none"
+
+/*
+ * flags (one for each option).
+ */
+#define	AF	0x00000001
+#define	BF	0x00000002
+#define	CF	0x00000004
+#define	DF	0x00000008
+#define	FF	0x00000010
+#define	IF	0x00000020
+#define	KF	0x00000040
+#define	LF	0x00000080
+#define	NF	0x00000100
+#define	OF	0x00000200
+#define	PF	0x00000400
+#define	RF	0x00000800
+#define	SF	0x00001000
+#define	TF	0x00002000
+#define	UF	0x00004000
+#define	VF	0x00008000
+#define	WF	0x00010000
+#define	XF	0x00020000
+#define	CBF	0x00040000	/* nonstandard extension */
+#define	CDF	0x00080000	/* nonstandard extension */
+#define	CEF	0x00100000	/* nonstandard extension */
+#define	CGF	0x00200000	/* nonstandard extension */
+#define	CHF	0x00400000	/* nonstandard extension */
+#define	CLF	0x00800000	/* nonstandard extension */
+#define	CPF	0x01000000	/* nonstandard extension */
+#define	CTF	0x02000000	/* nonstandard extension */
+#define	CUF	0x04000000	/* nonstandard extension */
+#define	CXF	0x08000000
+#define	CYF	0x10000000	/* nonstandard extension */
+#define	CZF	0x20000000	/* nonstandard extension */
+
+/*
+ * ascii string indexed by bit position above (alter the above and you must
+ * alter this string) used to tell the user what flags caused us to complain
+ */
+#define FLGCH	"abcdfiklnoprstuvwxBDEGHLPTUXYZ"
+
+/*
+ * legal pax operation bit patterns
+ */
+
+#define ISLIST(x)	(((x) & (RF|WF)) == 0)
+#define	ISEXTRACT(x)	(((x) & (RF|WF)) == RF)
+#define ISARCHIVE(x)	(((x) & (AF|RF|WF)) == WF)
+#define ISAPPND(x)	(((x) & (AF|RF|WF)) == (AF|WF))
+#define	ISCOPY(x)	(((x) & (RF|WF)) == (RF|WF))
+#define	ISWRITE(x)	(((x) & (RF|WF)) == WF)
+
+/*
+ * Illegal option flag subsets based on pax operation
+ */
+
+#define	BDEXTR	(AF|BF|LF|TF|WF|XF|CBF|CHF|CLF|CPF|CXF)
+#define	BDARCH	(CF|KF|LF|NF|PF|RF|CDF|CEF|CYF|CZF)
+#define	BDCOPY	(AF|BF|FF|OF|XF|CBF|CEF)
+#define	BDLIST (AF|BF|IF|KF|LF|OF|PF|RF|TF|UF|WF|XF|CBF|CDF|CHF|CLF|CPF|CXF|CYF|CZF)
diff --git a/pax/pat_rep.c b/pax/pat_rep.c
new file mode 100644
index 0000000..9ff1dca
--- /dev/null
+++ b/pax/pat_rep.c
@@ -0,0 +1,1240 @@
+/*	$OpenBSD: pat_rep.c,v 1.11 1997/09/01 18:29:56 deraadt Exp $	*/
+/*	$NetBSD: pat_rep.c,v 1.4 1995/03/21 09:07:33 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)pat_rep.c	8.2 (Berkeley) 4/18/94";
+#else
+static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: pat_rep.c,v 1.11 1997/09/01 18:29:56 deraadt Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#ifdef NET2_REGEX
+#include <regexp.h>
+#else
+#include <regex.h>
+#endif
+#include "pax.h"
+#include "pat_rep.h"
+#include "extern.h"
+
+/*
+ * routines to handle pattern matching, name modification (regular expression
+ * substitution and interactive renames), and destination name modification for
+ * copy (-rw). Both file name and link names are adjusted as required in these
+ * routines.
+ */
+
+#define MAXSUBEXP	10		/* max subexpressions, DO NOT CHANGE */
+static PATTERN *pathead = NULL;		/* file pattern match list head */
+static PATTERN *pattail = NULL;		/* file pattern match list tail */
+static REPLACE *rephead = NULL;		/* replacement string list head */
+static REPLACE *reptail = NULL;		/* replacement string list tail */
+
+static int rep_name __P((char *, int *, int));
+static int tty_rename __P((register ARCHD *));
+static int fix_path __P((char *, int *, char *, int));
+static int fn_match __P((register char *, register char *, char **));
+static char * range_match __P((register char *, register int));
+#ifdef NET2_REGEX
+static int resub __P((regexp *, char *, char *, register char *));
+#else
+static int resub __P((regex_t *, regmatch_t *, char *, char *, char *));
+#endif
+
+/*
+ * rep_add()
+ *	parses the -s replacement string; compiles the regular expression
+ *	and stores the compiled value and it's replacement string together in
+ *	replacement string list. Input to this function is of the form:
+ *		/old/new/pg 
+ *	The first char in the string specifies the delimiter used by this
+ *	replacement string. "Old" is a regular expression in "ed" format which
+ *	is compiled by regcomp() and is applied to filenames. "new" is the
+ *	substitution string; p and g are options flags for printing and global
+ *	replacement (over the single filename)
+ * Return:
+ *	0 if a proper replacement string and regular expression was added to
+ *	the list of replacement patterns; -1 otherwise.
+ */
+
+#ifdef __STDC__
+int
+rep_add(register char *str)
+#else
+int
+rep_add(str)
+	register char *str;
+#endif
+{
+	register char *pt1;
+	register char *pt2;
+	register REPLACE *rep;
+#	ifndef NET2_REGEX
+	register int res;
+	char rebuf[BUFSIZ];
+#	endif
+
+	/*
+	 * throw out the bad parameters
+	 */
+	if ((str == NULL) || (*str == '\0')) {
+		paxwarn(1, "Empty replacement string");
+		return(-1);
+	}
+
+	/*
+	 * first character in the string specifies what the delimiter is for
+	 * this expression
+	 */
+	if ((pt1 = strchr(str+1, *str)) == NULL) {
+		paxwarn(1, "Invalid replacement string %s", str);
+		return(-1);
+	}
+
+	/*
+	 * allocate space for the node that handles this replacement pattern
+	 * and split out the regular expression and try to compile it
+	 */
+	if ((rep = (REPLACE *)malloc(sizeof(REPLACE))) == NULL) {
+		paxwarn(1, "Unable to allocate memory for replacement string");
+		return(-1);
+	}
+
+	*pt1 = '\0';
+#	ifdef NET2_REGEX
+	if ((rep->rcmp = regcomp(str+1)) == NULL) {
+#	else
+	if ((res = regcomp(&(rep->rcmp), str+1, 0)) != 0) {
+		regerror(res, &(rep->rcmp), rebuf, sizeof(rebuf));
+		paxwarn(1, "%s while compiling regular expression %s", rebuf, str);
+#	endif
+		(void)free((char *)rep);
+		return(-1);
+	}
+
+	/*
+	 * put the delimiter back in case we need an error message and
+	 * locate the delimiter at the end of the replacement string
+	 * we then point the node at the new substitution string
+	 */
+	*pt1++ = *str;
+	if ((pt2 = strchr(pt1, *str)) == NULL) {
+#		ifdef NET2_REGEX
+		(void)free((char *)rep->rcmp);
+#		else
+		regfree(&(rep->rcmp));
+#		endif
+		(void)free((char *)rep);
+		paxwarn(1, "Invalid replacement string %s", str);
+		return(-1);
+	}
+
+	*pt2 = '\0';
+	rep->nstr = pt1;
+	pt1 = pt2++;
+	rep->flgs = 0;
+
+	/*
+	 * set the options if any
+	 */
+	while (*pt2 != '\0') {
+		switch(*pt2) {
+		case 'g':
+		case 'G':
+			rep->flgs  |= GLOB;
+			break;
+		case 'p':
+		case 'P':
+			rep->flgs  |= PRNT;
+			break;
+		default:
+#			ifdef NET2_REGEX
+			(void)free((char *)rep->rcmp);
+#			else
+			regfree(&(rep->rcmp));
+#			endif
+			(void)free((char *)rep);
+			*pt1 = *str;
+			paxwarn(1, "Invalid replacement string option %s", str);
+			return(-1);
+		}
+		++pt2;
+	}
+
+	/*
+	 * all done, link it in at the end
+	 */
+	rep->fow = NULL;
+	if (rephead == NULL) {
+		reptail = rephead = rep;
+		return(0);
+	}
+	reptail->fow = rep;
+	reptail = rep;
+	return(0);
+}
+
+/*
+ * pat_add()
+ *	add a pattern match to the pattern match list. Pattern matches are used
+ *	to select which archive members are extracted. (They appear as
+ *	arguments to pax in the list and read modes). If no patterns are
+ *	supplied to pax, all members in the archive will be selected (and the
+ *	pattern match list is empty).
+ * Return:
+ *	0 if the pattern was added to the list, -1 otherwise
+ */
+
+#ifdef __STDC__
+int
+pat_add(char *str, char *chdname)
+#else
+int
+pat_add(str, chdname)
+	char *str;
+	char *chdname;
+#endif
+{
+	register PATTERN *pt;
+
+	/*
+	 * throw out the junk
+	 */
+	if ((str == NULL) || (*str == '\0')) {
+		paxwarn(1, "Empty pattern string");
+		return(-1);
+	}
+
+	/*
+	 * allocate space for the pattern and store the pattern. the pattern is
+	 * part of argv so do not bother to copy it, just point at it. Add the
+	 * node to the end of the pattern list
+	 */
+	if ((pt = (PATTERN *)malloc(sizeof(PATTERN))) == NULL) {
+		paxwarn(1, "Unable to allocate memory for pattern string");
+		return(-1);
+	}
+
+	pt->pstr = str;
+	pt->pend = NULL;
+	pt->plen = strlen(str);
+	pt->fow = NULL;
+	pt->flgs = 0;
+	pt->chdname = chdname;
+
+	if (pathead == NULL) {
+		pattail = pathead = pt;
+		return(0);
+	}
+	pattail->fow = pt;
+	pattail = pt;
+	return(0);
+}
+
+/*
+ * pat_chk()
+ *	complain if any the user supplied pattern did not result in a match to
+ *	a selected archive member.
+ */
+
+#ifdef __STDC__
+void
+pat_chk(void)
+#else
+void
+pat_chk()
+#endif
+{
+	register PATTERN *pt;
+	register int wban = 0;
+
+	/*
+	 * walk down the list checking the flags to make sure MTCH was set,
+	 * if not complain
+	 */
+	for (pt = pathead; pt != NULL; pt = pt->fow) {
+		if (pt->flgs & MTCH)
+			continue;
+		if (!wban) {
+			paxwarn(1, "WARNING! These patterns were not matched:");
+			++wban;
+		}
+		(void)fprintf(stderr, "%s\n", pt->pstr);
+	}
+}
+
+/*
+ * pat_sel()
+ *	the archive member which matches a pattern was selected. Mark the
+ *	pattern as having selected an archive member. arcn->pat points at the
+ *	pattern that was matched. arcn->pat is set in pat_match()
+ *
+ *	NOTE: When the -c option is used, we are called when there was no match
+ *	by pat_match() (that means we did match before the inverted sense of
+ *	the logic). Now this seems really strange at first, but with -c  we
+ *	need to keep track of those patterns that cause a archive member to NOT
+ *	be selected (it found an archive member with a specified pattern)
+ * Return:
+ *	0 if the pattern pointed at by arcn->pat was tagged as creating a
+ *	match, -1 otherwise.
+ */
+
+#ifdef __STDC__
+int
+pat_sel(register ARCHD *arcn)
+#else
+int
+pat_sel(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	register PATTERN *pt;
+	register PATTERN **ppt;
+	register int len;
+
+	/*
+	 * if no patterns just return
+	 */
+	if ((pathead == NULL) || ((pt = arcn->pat) == NULL))
+		return(0);
+
+	/*
+	 * when we are NOT limited to a single match per pattern mark the
+	 * pattern and return
+	 */
+	if (!nflag) {
+		pt->flgs |= MTCH;
+		return(0);
+	}
+
+	/*
+	 * we reach this point only when we allow a single selected match per
+	 * pattern, if the pattern matches a directory and we do not have -d 
+	 * (dflag) we are done with this pattern. We may also be handed a file
+	 * in the subtree of a directory. in that case when we are operating
+	 * with -d, this pattern was already selected and we are done
+	 */
+	if (pt->flgs & DIR_MTCH)
+		return(0);
+
+	if (!dflag && ((pt->pend != NULL) || (arcn->type == PAX_DIR))) {
+		/*
+		 * ok we matched a directory and we are allowing
+		 * subtree matches but because of the -n only its children will
+		 * match. This is tagged as a DIR_MTCH type.
+		 * WATCH IT, the code assumes that pt->pend points
+		 * into arcn->name and arcn->name has not been modified.
+		 * If not we will have a big mess. Yup this is another kludge
+		 */
+
+		/*
+		 * if this was a prefix match, remove trailing part of path
+		 * so we can copy it. Future matches will be exact prefix match
+		 */
+		if (pt->pend != NULL)
+			*pt->pend = '\0';
+
+		if ((pt->pstr = strdup(arcn->name)) == NULL) {
+			paxwarn(1, "Pattern select out of memory");
+			if (pt->pend != NULL)
+				*pt->pend = '/';
+			pt->pend = NULL;
+			return(-1);
+		}
+
+		/*
+		 * put the trailing / back in the source string
+		 */
+		if (pt->pend != NULL) {
+			*pt->pend = '/';
+			pt->pend = NULL;
+		}
+		pt->plen = strlen(pt->pstr);
+
+		/*
+		 * strip off any trailing /, this should really never happen
+		 */
+		len = pt->plen - 1;
+		if (*(pt->pstr + len) == '/') {
+			*(pt->pstr + len) = '\0';
+			pt->plen = len;
+		}
+		pt->flgs = DIR_MTCH | MTCH;
+		arcn->pat = pt;
+		return(0);
+	}
+
+	/*
+	 * we are then done with this pattern, so we delete it from the list
+	 * because it can never be used for another match.
+	 * Seems kind of strange to do for a -c, but the pax spec is really
+	 * vague on the interaction of -c -n and -d. We assume that when -c
+	 * and the pattern rejects a member (i.e. it matched it) it is done.
+	 * In effect we place the order of the flags as having -c last.
+	 */
+	pt = pathead;
+	ppt = &pathead;
+	while ((pt != NULL) && (pt != arcn->pat)) {
+		ppt = &(pt->fow);
+		pt = pt->fow;
+	}
+
+	if (pt == NULL) {
+		/*
+		 * should never happen....
+		 */
+		paxwarn(1, "Pattern list inconsistant");
+		return(-1);
+	}
+	*ppt = pt->fow;
+	(void)free((char *)pt);
+	arcn->pat = NULL;
+	return(0);
+}
+
+/*
+ * pat_match()
+ *	see if this archive member matches any supplied pattern, if a match
+ *	is found, arcn->pat is set to point at the potential pattern. Later if
+ *	this archive member is "selected" we process and mark the pattern as
+ *	one which matched a selected archive member (see pat_sel())
+ * Return:
+ *	0 if this archive member should be processed, 1 if it should be 
+ *	skipped and -1 if we are done with all patterns (and pax should quit
+ *	looking for more members)
+ */
+
+#ifdef __STDC__
+int
+pat_match(register ARCHD *arcn)
+#else
+int
+pat_match(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	register PATTERN *pt;
+
+	arcn->pat = NULL;
+
+	/*
+	 * if there are no more patterns and we have -n (and not -c) we are
+	 * done. otherwise with no patterns to match, matches all
+	 */
+	if (pathead == NULL) {
+		if (nflag && !cflag)
+			return(-1);
+		return(0);
+	}
+
+	/*
+	 * have to search down the list one at a time looking for a match.
+	 */
+	pt = pathead;
+	while (pt != NULL) {
+		/*
+		 * check for a file name match unless we have DIR_MTCH set in
+		 * this pattern then we want a prefix match
+		 */
+		if (pt->flgs & DIR_MTCH) {
+			/*
+			 * this pattern was matched before to a directory
+			 * as we must have -n set for this (but not -d). We can
+			 * only match CHILDREN of that directory so we must use
+			 * an exact prefix match (no wildcards).
+			 */
+			if ((arcn->name[pt->plen] == '/') &&
+			    (strncmp(pt->pstr, arcn->name, pt->plen) == 0))
+				break;
+		} else if (fn_match(pt->pstr, arcn->name, &pt->pend) == 0)
+			break;
+		pt = pt->fow;
+	}
+
+	/*
+	 * return the result, remember that cflag (-c) inverts the sense of a
+	 * match
+	 */
+	if (pt == NULL)
+		return(cflag ? 0 : 1);
+
+	/*
+	 * we had a match, now when we invert the sense (-c) we reject this
+	 * member. However we have to tag the pattern a being successful, (in a
+	 * match, not in selecting a archive member) so we call pat_sel() here.
+	 */
+	arcn->pat = pt;
+	if (!cflag)
+		return(0);
+
+	if (pat_sel(arcn) < 0)
+		return(-1);
+	arcn->pat = NULL;
+	return(1);
+}
+
+/*
+ * fn_match()
+ * Return:
+ *	0 if this archive member should be processed, 1 if it should be 
+ *	skipped and -1 if we are done with all patterns (and pax should quit
+ *	looking for more members)
+ *	Note: *pend may be changed to show where the prefix ends.
+ */
+
+#ifdef __STDC__
+static int
+fn_match(register char *pattern, register char *string, char **pend)
+#else
+static int
+fn_match(pattern, string, pend)
+	register char *pattern;
+	register char *string;
+	char **pend;
+#endif
+{
+	register char c;
+	char test;
+
+	*pend = NULL;
+	for (;;) {
+		switch (c = *pattern++) {
+		case '\0':
+			/*
+			 * Ok we found an exact match
+			 */
+			if (*string == '\0')
+				return(0);
+
+			/*
+			 * Check if it is a prefix match
+			 */
+			if ((dflag == 1) || (*string != '/'))
+				return(-1);
+
+			/*
+			 * It is a prefix match, remember where the trailing
+			 * / is located
+			 */
+			*pend = string;
+			return(0);
+		case '?':
+			if ((test = *string++) == '\0')
+				return (-1);
+			break;
+		case '*':
+			c = *pattern;
+			/*
+			 * Collapse multiple *'s. 
+			 */
+			while (c == '*')
+				c = *++pattern;
+
+			/*
+			 * Optimized hack for pattern with a * at the end
+			 */
+			if (c == '\0')
+				return (0);
+
+			/*
+			 * General case, use recursion.
+			 */
+			while ((test = *string) != '\0') {
+				if (!fn_match(pattern, string, pend))
+					return (0);
+				++string;
+			}
+			return (-1);
+		case '[':
+			/*
+			 * range match
+			 */
+			if (((test = *string++) == '\0') ||
+			    ((pattern = range_match(pattern, test)) == NULL))
+				return (-1);
+			break;
+		case '\\':
+		default:
+			if (c != *string++)
+				return (-1);
+			break;
+		}
+	}
+	/* NOTREACHED */
+}
+
+#ifdef __STDC__
+static char *
+range_match(register char *pattern, register int test)
+#else
+static char *
+range_match(pattern, test)
+	register char *pattern;
+	register int test;
+#endif
+{
+	register char c;
+	register char c2;
+	int negate;
+	int ok = 0;
+
+	if ((negate = (*pattern == '!')) != 0)
+		++pattern;
+
+	while ((c = *pattern++) != ']') {
+		/*
+		 * Illegal pattern
+		 */
+		if (c == '\0')
+			return (NULL);
+
+		if ((*pattern == '-') && ((c2 = pattern[1]) != '\0') &&
+		    (c2 != ']')) {
+			if ((c <= test) && (test <= c2))
+				ok = 1;
+			pattern += 2;
+		} else if (c == test)
+			ok = 1;
+	}
+	return (ok == negate ? NULL : pattern);
+}
+
+/*
+ * mod_name()
+ *	modify a selected file name. first attempt to apply replacement string
+ *	expressions, then apply interactive file rename. We apply replacement
+ *	string expressions to both filenames and file links (if we didn't the
+ *	links would point to the wrong place, and we could never be able to
+ *	move an archive that has a file link in it). When we rename files
+ *	interactively, we store that mapping (old name to user input name) so
+ *	if we spot any file links to the old file name in the future, we will
+ *	know exactly how to fix the file link.
+ * Return:
+ *	0 continue to  process file, 1 skip this file, -1 pax is finished 
+ */
+
+#ifdef __STDC__
+int
+mod_name(register ARCHD *arcn)
+#else
+int
+mod_name(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	register int res = 0;
+
+	/*
+	 * Strip off leading '/' if appropriate.
+	 * Currently, this option is only set for the tar format.
+	 */
+	if (rmleadslash && arcn->name[0] == '/') {
+		if (arcn->name[1] == '\0') {
+			arcn->name[0] = '.';
+		} else {
+			(void)memmove(arcn->name, &arcn->name[1],
+			    strlen(arcn->name));
+			arcn->nlen--;
+		}
+		if (rmleadslash < 2) {
+			rmleadslash = 2;
+			paxwarn(0, "Removing leading / from absolute path names in the archive");
+		}
+	}
+	if (rmleadslash && arcn->ln_name[0] == '/' &&
+	    (arcn->type == PAX_HLK || arcn->type == PAX_HRG)) {
+		if (arcn->ln_name[1] == '\0') {
+			arcn->ln_name[0] = '.';
+		} else {
+			(void)memmove(arcn->ln_name, &arcn->ln_name[1],
+			    strlen(arcn->ln_name));
+			arcn->ln_nlen--;
+		}
+		if (rmleadslash < 2) {
+			rmleadslash = 2;
+			paxwarn(0, "Removing leading / from absolute path names in the archive");
+		}
+	}
+
+	/*
+	 * IMPORTANT: We have a problem. what do we do with symlinks?
+	 * Modifying a hard link name makes sense, as we know the file it
+	 * points at should have been seen already in the archive (and if it
+	 * wasn't seen because of a read error or a bad archive, we lose
+	 * anyway). But there are no such requirements for symlinks. On one
+	 * hand the symlink that refers to a file in the archive will have to
+	 * be modified to so it will still work at its new location in the
+	 * file system. On the other hand a symlink that points elsewhere (and
+	 * should continue to do so) should not be modified. There is clearly
+	 * no perfect solution here. So we handle them like hardlinks. Clearly
+	 * a replacement made by the interactive rename mapping is very likely
+	 * to be correct since it applies to a single file and is an exact
+	 * match. The regular expression replacements are a little harder to
+	 * justify though. We claim that the symlink name is only likely
+	 * to be replaced when it points within the file tree being moved and
+	 * in that case it should be modified. what we really need to do is to
+	 * call an oracle here. :)
+	 */
+	if (rephead != NULL) {
+		/*
+		 * we have replacement strings, modify the name and the link
+		 * name if any.
+		 */
+		if ((res = rep_name(arcn->name, &(arcn->nlen), 1)) != 0)
+			return(res);
+
+		if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) ||
+		    (arcn->type == PAX_HRG)) &&
+		    ((res = rep_name(arcn->ln_name, &(arcn->ln_nlen), 0)) != 0))
+			return(res);
+	}
+
+	if (iflag) {
+		/*
+		 * perform interactive file rename, then map the link if any
+		 */
+		if ((res = tty_rename(arcn)) != 0)
+			return(res);
+		if ((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) ||
+		    (arcn->type == PAX_HRG))
+			sub_name(arcn->ln_name, &(arcn->ln_nlen), sizeof(arcn->ln_name));
+	}
+	return(res);
+}
+
+/*
+ * tty_rename()
+ *	Prompt the user for a replacement file name. A "." keeps the old name,
+ *	a empty line skips the file, and an EOF on reading the tty, will cause
+ *	pax to stop processing and exit. Otherwise the file name input, replaces
+ *	the old one.
+ * Return:
+ *	0 process this file, 1 skip this file, -1 we need to exit pax
+ */
+
+#ifdef __STDC__
+static int
+tty_rename(register ARCHD *arcn)
+#else
+static int
+tty_rename(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	char tmpname[PAXPATHLEN+2];
+	int res;
+
+	/*
+	 * prompt user for the replacement name for a file, keep trying until
+	 * we get some reasonable input. Archives may have more than one file
+	 * on them with the same name (from updates etc). We print verbose info
+	 * on the file so the user knows what is up.
+	 */
+	tty_prnt("\nATTENTION: %s interactive file rename operation.\n", argv0);
+
+	for (;;) {
+		ls_tty(arcn);
+		tty_prnt("Input new name, or a \".\" to keep the old name, ");
+		tty_prnt("or a \"return\" to skip this file.\n");
+		tty_prnt("Input > ");
+		if (tty_read(tmpname, sizeof(tmpname)) < 0)
+			return(-1);
+		if (strcmp(tmpname, "..") == 0) {
+			tty_prnt("Try again, illegal file name: ..\n");
+			continue;
+		}
+		if (strlen(tmpname) > PAXPATHLEN) {
+			tty_prnt("Try again, file name too long\n");
+			continue;
+		}
+		break;
+	}
+
+	/*
+	 * empty file name, skips this file. a "." leaves it alone
+	 */
+	if (tmpname[0] == '\0') {
+		tty_prnt("Skipping file.\n");
+		return(1);
+	}
+	if ((tmpname[0] == '.') && (tmpname[1] == '\0')) {
+		tty_prnt("Processing continues, name unchanged.\n");
+		return(0);
+	}
+
+	/*
+	 * ok the name changed. We may run into links that point at this
+	 * file later. we have to remember where the user sent the file
+	 * in order to repair any links.
+	 */
+	tty_prnt("Processing continues, name changed to: %s\n", tmpname);
+	res = add_name(arcn->name, arcn->nlen, tmpname);
+	arcn->nlen = l_strncpy(arcn->name, tmpname, sizeof(arcn->name) - 1);
+	arcn->name[arcn->nlen] = '\0';
+	if (res < 0)
+		return(-1);
+	return(0);
+}
+
+/*
+ * set_dest()
+ *	fix up the file name and the link name (if any) so this file will land
+ *	in the destination directory (used during copy() -rw).
+ * Return:
+ *	0 if ok, -1 if failure (name too long)
+ */
+
+#ifdef __STDC__
+int
+set_dest(register ARCHD *arcn, char *dest_dir, int dir_len)
+#else
+int
+set_dest(arcn, dest_dir, dir_len)
+	register ARCHD *arcn;
+	char *dest_dir;
+	int dir_len;
+#endif
+{
+	if (fix_path(arcn->name, &(arcn->nlen), dest_dir, dir_len) < 0)
+		return(-1);
+
+	/*
+	 * It is really hard to deal with symlinks here, we cannot be sure
+	 * if the name they point was moved (or will be moved). It is best to
+	 * leave them alone.
+	 */
+	if ((arcn->type != PAX_HLK) && (arcn->type != PAX_HRG))
+		return(0);
+
+	if (fix_path(arcn->ln_name, &(arcn->ln_nlen), dest_dir, dir_len) < 0)
+		return(-1);
+	return(0);
+}
+
+/*
+ * fix_path
+ *	concatenate dir_name and or_name and store the result in or_name (if
+ *	it fits). This is one ugly function.
+ * Return:
+ *	0 if ok, -1 if the final name is too long
+ */
+
+#ifdef __STDC__
+static int
+fix_path( char *or_name, int *or_len, char *dir_name, int dir_len)
+#else
+static int
+fix_path(or_name, or_len, dir_name, dir_len)
+	char *or_name;
+	int *or_len;
+	char *dir_name;
+	int dir_len;
+#endif
+{
+	register char *src;
+	register char *dest;
+	register char *start;
+	int len;
+
+	/*
+	 * we shift the or_name to the right enough to tack in the dir_name
+	 * at the front. We make sure we have enough space for it all before
+	 * we start. since dest always ends in a slash, we skip of or_name
+	 * if it also starts with one.
+	 */
+	start = or_name;
+	src = start + *or_len;
+	dest = src + dir_len;
+	if (*start == '/') {
+		++start;
+		--dest;
+	}
+	if ((len = dest - or_name) > PAXPATHLEN) {
+		paxwarn(1, "File name %s/%s, too long", dir_name, start);
+		return(-1);
+	}
+	*or_len = len;
+
+	/*
+	 * enough space, shift 
+	 */
+	while (src >= start)
+		*dest-- = *src--;
+	src = dir_name + dir_len - 1;
+
+	/*
+	 * splice in the destination directory name
+	 */
+	while (src >= dir_name)
+		*dest-- = *src--;
+
+	*(or_name + len) = '\0';
+	return(0);
+}
+
+/*
+ * rep_name()
+ *	walk down the list of replacement strings applying each one in order.
+ *	when we find one with a successful substitution, we modify the name
+ *	as specified. if required, we print the results. if the resulting name
+ *	is empty, we will skip this archive member. We use the regexp(3)
+ *	routines (regexp() ought to win a prize as having the most cryptic
+ *	library function manual page).
+ *	--Parameters--
+ *	name is the file name we are going to apply the regular expressions to
+ *	(and may be modified)
+ *	nlen is the length of this name (and is modified to hold the length of
+ *	the final string).
+ *	prnt is a flag that says whether to print the final result.
+ * Return:
+ *	0 if substitution was successful, 1 if we are to skip the file (the name
+ *	ended up empty)
+ */
+
+#ifdef __STDC__
+static int
+rep_name(char *name, int *nlen, int prnt)
+#else
+static int
+rep_name(name, nlen, prnt)
+	char *name;
+	int *nlen;
+	int prnt;
+#endif
+{
+	register REPLACE *pt;
+	register char *inpt;
+	register char *outpt;
+	register char *endpt;
+	register char *rpt;
+	register int found = 0;
+	register int res;
+#	ifndef NET2_REGEX
+	regmatch_t pm[MAXSUBEXP];
+#	endif
+	char nname[PAXPATHLEN+1];	/* final result of all replacements */
+	char buf1[PAXPATHLEN+1];	/* where we work on the name */
+
+	/*
+	 * copy the name into buf1, where we will work on it. We need to keep
+	 * the orig string around so we can print out the result of the final
+	 * replacement. We build up the final result in nname. inpt points at
+	 * the string we apply the regular expression to. prnt is used to
+	 * suppress printing when we handle replacements on the link field
+	 * (the user already saw that substitution go by)
+	 */
+	pt = rephead;
+	(void)strcpy(buf1, name);
+	inpt = buf1;
+	outpt = nname;
+	endpt = outpt + PAXPATHLEN;
+
+	/*
+	 * try each replacement string in order
+	 */
+	while (pt != NULL) {
+		do {
+			/*
+			 * check for a successful substitution, if not go to
+			 * the next pattern, or cleanup if we were global
+			 */
+#			ifdef NET2_REGEX
+			if (regexec(pt->rcmp, inpt) == 0)
+#			else
+			if (regexec(&(pt->rcmp), inpt, MAXSUBEXP, pm, 0) != 0)
+#			endif
+				break;
+
+			/*
+			 * ok we found one. We have three parts, the prefix
+			 * which did not match, the section that did and the
+			 * tail (that also did not match). Copy the prefix to
+			 * the final output buffer (watching to make sure we
+			 * do not create a string too long).
+			 */
+			found = 1;
+#			ifdef NET2_REGEX
+			rpt = pt->rcmp->startp[0];
+#			else
+			rpt = inpt + pm[0].rm_so;
+#			endif
+
+			while ((inpt < rpt) && (outpt < endpt))
+				*outpt++ = *inpt++;
+			if (outpt == endpt)
+				break;
+
+			/*
+			 * for the second part (which matched the regular
+			 * expression) apply the substitution using the
+			 * replacement string and place it the prefix in the
+			 * final output. If we have problems, skip it.
+			 */
+#			ifdef NET2_REGEX
+			if ((res = resub(pt->rcmp,pt->nstr,outpt,endpt)) < 0) {
+#			else
+			if ((res = resub(&(pt->rcmp),pm,pt->nstr,outpt,endpt))
+			    < 0) {
+#			endif
+				if (prnt)
+					paxwarn(1, "Replacement name error %s",
+					    name);
+				return(1);
+			}
+			outpt += res;
+
+			/*
+			 * we set up to look again starting at the first
+			 * character in the tail (of the input string right
+			 * after the last character matched by the regular
+			 * expression (inpt always points at the first char in
+			 * the string to process). If we are not doing a global
+			 * substitution, we will use inpt to copy the tail to
+			 * the final result. Make sure we do not overrun the
+			 * output buffer
+			 */
+#			ifdef NET2_REGEX
+			inpt = pt->rcmp->endp[0];
+#			else
+			inpt += pm[0].rm_eo - pm[0].rm_so;
+#			endif
+
+			if ((outpt == endpt) || (*inpt == '\0'))
+				break;
+
+			/*
+			 * if the user wants global we keep trying to
+			 * substitute until it fails, then we are done.
+			 */
+		} while (pt->flgs & GLOB);
+
+		if (found)
+			break;
+
+		/*
+		 * a successful substitution did NOT occur, try the next one
+		 */
+		pt = pt->fow;
+	}
+
+	if (found) {
+		/*
+		 * we had a substitution, copy the last tail piece (if there is
+		 * room) to the final result
+		 */
+		while ((outpt < endpt) && (*inpt != '\0'))
+			*outpt++ = *inpt++;
+
+		*outpt = '\0';
+		if ((outpt == endpt) && (*inpt != '\0')) {
+			if (prnt)
+				paxwarn(1,"Replacement name too long %s >> %s",
+				    name, nname);
+			return(1);
+		}
+
+		/*
+		 * inform the user of the result if wanted
+		 */
+		if (prnt && (pt->flgs & PRNT)) {
+			if (*nname == '\0')
+				(void)fprintf(stderr,"%s >> <empty string>\n",
+				    name);
+			else
+				(void)fprintf(stderr,"%s >> %s\n", name, nname);
+		}
+
+		/*
+		 * if empty inform the caller this file is to be skipped
+		 * otherwise copy the new name over the orig name and return
+		 */
+		if (*nname == '\0')
+			return(1);
+		*nlen = l_strncpy(name, nname, PAXPATHLEN + 1);
+		name[PAXPATHLEN] = '\0';
+	}
+	return(0);
+}
+
+#ifdef NET2_REGEX
+/*
+ * resub()
+ *	apply the replacement to the matched expression. expand out the old
+ * 	style ed(1) subexpression expansion.
+ * Return:
+ *	-1 if error, or the number of characters added to the destination.
+ */
+
+#ifdef __STDC__
+static int
+resub(regexp *prog, char *src, char *dest, register char *destend)
+#else
+static int
+resub(prog, src, dest, destend)
+	regexp *prog;
+	char *src;
+	char *dest;
+	register char *destend;
+#endif
+{
+	register char *spt;
+	register char *dpt;
+	register char c;
+	register int no;
+	register int len;
+
+	spt = src;
+	dpt = dest;
+	while ((dpt < destend) && ((c = *spt++) != '\0')) {
+		if (c == '&')
+			no = 0;
+		else if ((c == '\\') && (*spt >= '0') && (*spt <= '9'))
+			no = *spt++ - '0';
+		else {
+ 			if ((c == '\\') && ((*spt == '\\') || (*spt == '&')))
+ 				c = *spt++;
+ 			*dpt++ = c;
+			continue;
+		}
+ 		if ((prog->startp[no] == NULL) || (prog->endp[no] == NULL) ||
+		    ((len = prog->endp[no] - prog->startp[no]) <= 0))
+			continue;
+
+		/*
+		 * copy the subexpression to the destination.
+		 * fail if we run out of space or the match string is damaged
+		 */
+		if (len > (destend - dpt))
+			len = destend - dpt;
+		if (l_strncpy(dpt, prog->startp[no], len) != len)
+			return(-1);
+		dpt += len;
+	}
+	return(dpt - dest);
+}
+
+#else
+
+/*
+ * resub()
+ *	apply the replacement to the matched expression. expand out the old
+ * 	style ed(1) subexpression expansion.
+ * Return:
+ *	-1 if error, or the number of characters added to the destination.
+ */
+
+#ifdef __STDC__
+static int
+resub(regex_t *rp, register regmatch_t *pm, char *src, char *dest,
+	register char *destend)
+#else
+static int
+resub(rp, pm, src, dest, destend)
+	regex_t *rp;
+	register regmatch_t *pm;
+	char *src;
+	char *dest;
+	register char *destend;
+#endif
+{
+	register char *spt;
+	register char *dpt;
+	register char c;
+	register regmatch_t *pmpt;
+	register int len;
+	int subexcnt;
+
+	spt =  src;
+	dpt = dest;
+	subexcnt = rp->re_nsub;
+	while ((dpt < destend) && ((c = *spt++) != '\0')) {
+		/*
+		 * see if we just have an ordinary replacement character
+		 * or we refer to a subexpression.
+		 */
+		if (c == '&') {
+			pmpt = pm;
+		} else if ((c == '\\') && (*spt >= '0') && (*spt <= '9')) {
+			/*
+			 * make sure there is a subexpression as specified
+			 */
+			if ((len = *spt++ - '0') > subexcnt)
+				return(-1);
+			pmpt = pm + len;
+		} else {
+ 			/*
+			 * Ordinary character, just copy it
+			 */
+ 			if ((c == '\\') && ((*spt == '\\') || (*spt == '&')))
+ 				c = *spt++;
+ 			*dpt++ = c;
+			continue;
+		}
+
+		/*
+		 * continue if the subexpression is bogus
+		 */
+		if ((pmpt->rm_so < 0) || (pmpt->rm_eo < 0) ||
+		    ((len = pmpt->rm_eo - pmpt->rm_so) <= 0))
+			continue;
+
+		/*
+		 * copy the subexpression to the destination.
+		 * fail if we run out of space or the match string is damaged
+		 */
+		if (len > (destend - dpt))
+			len = destend - dpt;
+		if (l_strncpy(dpt, src + pmpt->rm_so, len) != len)
+			return(-1);
+		dpt += len;
+	}
+	return(dpt - dest);
+}
+#endif
diff --git a/pax/pat_rep.h b/pax/pat_rep.h
new file mode 100644
index 0000000..b41f1e1
--- /dev/null
+++ b/pax/pat_rep.h
@@ -0,0 +1,57 @@
+/*	$OpenBSD: pat_rep.h,v 1.2 1996/06/23 14:20:38 deraadt Exp $	*/
+/*	$NetBSD: pat_rep.h,v 1.3 1995/03/21 09:07:35 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)pat_rep.h	8.1 (Berkeley) 5/31/93
+ */
+
+/*
+ * data structure for storing user supplied replacement strings (-s)
+ */
+typedef struct replace {
+	char		*nstr;	/* the new string we will substitute with */
+#	ifdef NET2_REGEX
+	regexp		*rcmp;	/* compiled regular expression used to match */
+#	else
+	regex_t		rcmp;	/* compiled regular expression used to match */
+#	endif
+	int		flgs;	/* print conversions? global in operation?  */
+#define	PRNT		0x1
+#define	GLOB		0x2
+	struct replace	*fow;	/* pointer to next pattern */
+} REPLACE;
diff --git a/pax/pax.1 b/pax/pax.1
new file mode 100644
index 0000000..590c9df
--- /dev/null
+++ b/pax/pax.1
@@ -0,0 +1,1178 @@
+.\"	$OpenBSD: pax.1,v 1.5 1997/04/06 06:11:13 millert Exp $
+.\"	$NetBSD: pax.1,v 1.3 1995/03/21 09:07:37 cgd Exp $
+.\"
+.\" Copyright (c) 1992 Keith Muller.
+.\" Copyright (c) 1992, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Keith Muller of the University of California, San Diego.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)pax.1	8.4 (Berkeley) 4/18/94
+.\"
+.Dd April 18, 1994
+.Dt PAX 1
+.Os BSD 4.4
+.Sh NAME
+.Nm pax
+.Nd read and write file archives and copy directory hierarchies
+.Sh SYNOPSIS
+.Nm pax
+.Op Fl cdnv
+.Bk -words
+.Op Fl f Ar archive
+.Ek
+.Bk -words
+.Op Fl s Ar replstr
+.Ar ...
+.Ek
+.Bk -words
+.Op Fl U Ar user
+.Ar ...
+.Ek
+.Bk -words
+.Op Fl G Ar group
+.Ar ...
+.Ek
+.Bk -words
+.Oo
+.Fl T
+.Op Ar from_date
+.Op Ar ,to_date
+.Oc
+.Ar ...
+.Ek
+.Op Ar pattern ...
+.Nm pax
+.Fl r
+.Op Fl cdiknuvDYZ
+.Bk -words
+.Op Fl f Ar archive
+.Ek
+.Bk -words
+.Op Fl o Ar options
+.Ar ...
+.Ek
+.Bk -words
+.Op Fl p Ar string
+.Ar ...
+.Ek
+.Bk -words
+.Op Fl s Ar replstr
+.Ar ...
+.Ek
+.Op Fl E Ar limit
+.Bk -words
+.Op Fl U Ar user
+.Ar ...
+.Ek
+.Bk -words
+.Op Fl G Ar group
+.Ar ...
+.Ek
+.Bk -words
+.Oo
+.Fl T
+.Op Ar from_date
+.Op Ar ,to_date
+.Oc
+.Ar ...
+.Ek
+.Op Ar pattern ...
+.Nm pax
+.Fl w
+.Op Fl dituvHLPX
+.Bk -words
+.Op Fl b Ar blocksize
+.Ek
+.Oo
+.Op Fl a
+.Op Fl f Ar archive
+.Oc
+.Bk -words
+.Op Fl x Ar format
+.Ek
+.Bk -words
+.Op Fl s Ar replstr
+.Ar ...
+.Ek
+.Bk -words
+.Op Fl o Ar options
+.Ar ...
+.Ek
+.Bk -words
+.Op Fl U Ar user
+.Ar ...
+.Ek
+.Bk -words
+.Op Fl G Ar group
+.Ar ...
+.Ek
+.Bk -words
+.Op Fl B Ar bytes
+.Ek
+.Bk -words
+.Oo
+.Fl T
+.Op Ar from_date
+.Op Ar ,to_date
+.Op Ar /[c][m]
+.Oc
+.Ar ...
+.Ek
+.Op Ar file ...
+.Nm pax
+.Fl r
+.Fl w
+.Op Fl diklntuvDHLPXYZ
+.Bk -words
+.Op Fl p Ar string
+.Ar ...
+.Ek
+.Bk -words
+.Op Fl s Ar replstr
+.Ar ...
+.Ek
+.Bk -words
+.Op Fl U Ar user
+.Ar ...
+.Ek
+.Bk -words
+.Op Fl G Ar group
+.Ar ...
+.Ek
+.Bk -words
+.Oo
+.Fl T
+.Op Ar from_date
+.Op Ar ,to_date
+.Op Ar /[c][m]
+.Oc
+.Ar ...
+.Ek
+.Op Ar file ...
+.Ar directory
+.Sh DESCRIPTION
+.Nm Pax
+will read, write, and list the members of an archive file,
+and will copy directory hierarchies.
+.Nm Pax 
+operation is independent of the specific archive format,
+and supports a wide variety of different archive formats.
+A list of supported archive formats can be found under the description of the
+.Fl x
+option.
+.Pp
+The presence of the
+.Fl r
+and the
+.Fl w
+options specifies which of the following functional modes
+.Nm pax
+will operate under:
+.Em list , read , write ,
+and
+.Em copy.
+.Bl -tag -width 6n
+.It <none>
+.Em List .
+.Nm Pax
+will write to
+.Dv standard output
+a table of contents of the members of the archive file read from
+.Dv standard input ,
+whose pathnames match the specified
+.Ar patterns.
+The table of contents contains one filename per line
+and is written using single line buffering.
+.It Fl r
+.Em Read .
+.Nm Pax
+extracts the members of the archive file read from the
+.Dv standard input ,
+with pathnames matching the specified 
+.Ar patterns.
+The archive format and blocking is automatically determined on input.
+When an extracted file is a directory, the entire file hierarchy
+rooted at that directory is extracted.
+All extracted files are created relative to the current file hierarchy.
+The setting of ownership, access and modification times, and file mode of
+the extracted files are discussed in more detail under the
+.Fl p
+option.
+.It Fl w
+.Em Write .
+.Nm Pax
+writes an archive containing the 
+.Ar file
+operands to
+.Dv standard output
+using the specified archive format.
+When no 
+.Ar file
+operands are specified, a list of files to copy with one per line is read from 
+.Dv standard input .
+When a 
+.Ar file
+operand is also a directory, the entire file hierarchy rooted
+at that directory will be included.
+.It Fl r Fl w
+.Em Copy .
+.Nm Pax
+copies the
+.Ar file
+operands to the destination
+.Ar directory .
+When no 
+.Ar file
+operands are specified, a list of files to copy with one per line is read from
+the
+.Dv standard input .
+When a
+.Ar file
+operand is also a directory the entire file
+hierarchy rooted at that directory will be included.
+The effect of the
+.Em copy
+is as if the copied files were written to an archive file and then
+subsequently extracted, except that there may be hard links between
+the original and the copied files (see the
+.Fl l
+option below).
+.Pp
+.Em Warning :
+The destination
+.Ar directory
+must not be one of the
+.Ar file
+operands or a member of a file hierarchy rooted at one of the
+.Ar file
+operands.
+The result of a
+.Em copy
+under these conditions is unpredictable.
+.El
+.Pp
+While processing a damaged archive during a
+.Em read
+or
+.Em list
+operation,
+.Nm pax
+will attempt to recover from media defects and will search through the archive
+to locate and process the largest number of archive members possible (see the
+.Fl E
+option for more details on error handling).
+.Sh OPERANDS
+.Pp
+The
+.Ar directory
+operand specifies a destination directory pathname.
+If the
+.Ar directory
+operand does not exist, or it is not writable by the user,
+or it is not of type directory,
+.Nm Pax
+will exit with a non-zero exit status.
+.Pp
+The
+.Ar pattern
+operand is used to select one or more pathnames of archive members.
+Archive members are selected using the pattern matching notation described
+by
+.Xr fnmatch 3 .
+When the 
+.Ar pattern
+operand is not supplied, all members of the archive will be selected.
+When a 
+.Ar pattern
+matches a directory, the entire file hierarchy rooted at that directory will
+be selected.
+When a
+.Ar pattern
+operand does not select at least one archive member,
+.Nm pax
+will write these
+.Ar pattern
+operands in a diagnostic message to
+.Dv standard error
+and then exit with a non-zero exit status.
+.Pp
+The
+.Ar file
+operand specifies the pathname of a file to be copied or archived.
+When a
+.Ar file
+operand does not select at least one archive member,
+.Nm pax
+will write these
+.Ar file
+operand pathnames in a diagnostic message to
+.Dv standard error
+and then exit with a non-zero exit status.
+.Sh OPTIONS
+.Pp
+The following options are supported:
+.Bl -tag -width 4n
+.It Fl r
+Read an archive file from
+.Dv standard input
+and extract the specified
+.Ar files .
+If any intermediate directories are needed in order to extract an archive
+member, these directories will be created as if
+.Xr mkdir 2
+was called with the bitwise inclusive
+.Dv OR 
+of
+.Dv S_IRWXU , S_IRWXG ,
+and
+.Dv S_IRWXO 
+as the mode argument.
+When the selected archive format supports the specification of linked
+files and these files cannot be linked while the archive is being extracted,
+.Nm pax
+will write a diagnostic message to
+.Dv standard error
+and exit with a non-zero exit status at the completion of operation.
+.It Fl w
+Write files to the
+.Dv standard output
+in the specified archive format.
+When no
+.Ar file
+operands are specified,
+.Dv standard input
+is read for a list of pathnames with one per line without any leading or
+trailing
+.Aq blanks .
+.It Fl a
+Append
+.Ar files
+to the end of an archive that was previously written.
+If an archive format is not specified with a
+.Fl x
+option, the format currently being used in the archive will be selected.
+Any attempt to append to an archive in a format different from the
+format already used in the archive will cause 
+.Nm pax
+to exit immediately
+with a non-zero exit status.
+The blocking size used in the archive volume where writing starts
+will continue to be used for the remainder of that archive volume.
+.Pp
+.Em Warning :
+Many storage devices are not able to support the operations necessary
+to perform an append operation.
+Any attempt to append to an archive stored on such a device may damage the
+archive or have other unpredictable results.
+Tape drives in particular are more likely to not support an append operation.
+An archive stored in a regular file system file or on a disk device will
+usually support an append operation.
+.It Fl b Ar blocksize
+When
+.Em writing
+an archive,
+block the output at a positive decimal integer number of
+bytes per write to the archive file.
+The
+.Ar blocksize
+must be a multiple of 512 bytes with a maximum of 64512 bytes.
+Archives larger than 32256 bytes violate the
+.Tn POSIX
+standard and will not be portable to all systems.
+A
+.Ar blocksize
+can end with
+.Li k
+or
+.Li b
+to specify multiplication by 1024 (1K) or 512, respectively.
+A pair of
+.Ar blocksizes
+can be separated by
+.Li x
+to indicate a product.
+A specific archive device may impose additional restrictions on the size
+of blocking it will support.
+When blocking is not specified, the default 
+.Ar blocksize
+is dependent on the specific archive format being used (see the
+.Fl x
+option).
+.It Fl c
+Match all file or archive members
+.Em except
+those specified by the
+.Ar pattern
+and
+.Ar file
+operands.
+.It Fl d
+Cause files of type directory being copied or archived, or archive members of
+type directory being extracted, to match only the directory file or archive
+member and not the file hierarchy rooted at the directory.
+.It Fl f Ar archive
+Specify
+.Ar archive
+as the pathname of the input or output archive, overriding the default
+.Dv standard input
+(for
+.Em list
+and
+.Em read )
+or
+.Dv standard output
+(for
+.Em write ) .
+A single archive may span multiple files and different archive devices.
+When required,
+.Nm pax
+will prompt for the pathname of the file or device of the next volume in the
+archive.
+.It Fl i
+Interactively rename files or archive members.
+For each archive member matching a
+.Ar pattern
+operand or each file matching a
+.Ar file
+operand,
+.Nm pax
+will prompt to
+.Pa /dev/tty
+giving the name of the file, its file mode and its modification time.
+.Nm Pax
+will then read a line from
+.Pa /dev/tty .
+If this line is blank, the file or archive member is skipped.
+If this line consists of a single period, the
+file or archive member is processed with no modification to its name.
+Otherwise, its name is replaced with the contents of the line.
+.Nm Pax
+will immediately exit with a non-zero exit status if 
+.Dv <EOF>
+is encountered when reading a response or if
+.Pa /dev/tty
+cannot be opened for reading and writing.
+.It Fl k
+Do not overwrite existing files.
+.It Fl l
+Link files. (The letter ell).
+In the
+.Em copy
+mode (
+.Fl r
+.Fl w ) ,
+hard links are made between the source and destination file hierarchies
+whenever possible.
+.It Fl n
+Select the first archive member that matches each
+.Ar pattern
+operand.
+No more than one archive member is matched for each
+.Ar pattern .
+When members of type directory are matched, the file hierarchy rooted at that
+directory is also matched (unless
+.Fl d 
+is also specified).
+.It Fl o Ar options
+Information to modify the algorithm for extracting or writing archive files
+which is specific to the archive format specified by
+.Fl x .
+In general,
+.Ar options
+take the form:
+.Cm name=value
+.It Fl p Ar string
+Specify one or more file characteristic options (privileges).
+The
+.Ar string
+option-argument is a string specifying file characteristics to be retained or
+discarded on extraction.
+The string consists of the specification characters
+.Cm a , e , m , o ,
+and
+.Cm p .
+Multiple characteristics can be concatenated within the same string
+and multiple
+.Fl p 
+options can be specified.
+The meaning of the specification characters are as follows:
+.Bl -tag -width 2n
+.It Cm a
+Do not preserve file access times.
+By default, file access times are preserved whenever possible.
+.It Cm e
+.Sq Preserve everything ,
+the user ID, group ID, file mode bits,
+file access time, and file modification time.
+This is intended to be used by
+.Em root ,
+someone with all the appropriate privileges, in order to preserve all
+aspects of the files as they are recorded in the archive.
+The 
+.Cm e
+flag is the sum of the
+.Cm o 
+and
+.Cm p
+flags.
+.It Cm m
+Do not preserve file modification times.
+By default, file modification times are preserved whenever possible.
+.It Cm o
+Preserve the user ID and group ID.
+.It Cm p
+.Sq Preserve
+the file mode bits.
+This intended to be used by a
+.Em user 
+with regular privileges who wants to preserve all aspects of the file other
+than the ownership.
+The file times are preserved by default, but two other flags are offered to
+disable this and use the time of extraction instead.
+.El
+.Pp
+In the preceding list,
+.Sq preserve
+indicates that an attribute stored in the archive is given to the
+extracted file, subject to the permissions of the invoking
+process.
+Otherwise the attribute of the extracted file is determined as
+part of the normal file creation action.
+If neither the 
+.Cm e
+nor the
+.Cm o
+specification character is specified, or the user ID and group ID are not
+preserved for any reason,
+.Nm pax
+will not set the
+.Dv S_ISUID 
+.Em ( setuid )
+and
+.Dv S_ISGID
+.Em ( setgid )
+bits of the file mode.
+If the preservation of any of these items fails for any reason,
+.Nm pax
+will write a diagnostic message to
+.Dv standard error .
+Failure to preserve these items will affect the final exit status,
+but will not cause the extracted file to be deleted.
+If the file characteristic letters in any of the string option-arguments are
+duplicated or conflict with each other, the one(s) given last will take
+precedence.
+For example, if
+.Dl Fl p Ar eme
+is specified, file modification times are still preserved.
+.It Fl s Ar replstr
+Modify the file or archive member names specified by the
+.Ar pattern
+or
+.Ar file
+operands according to the substitution expression
+.Ar replstr ,
+using the syntax of the
+.Xr ed 1
+utility regular expressions.
+The format of these regular expressions are:
+.Dl /old/new/[gp]
+As in
+.Xr ed 1 ,
+.Cm old
+is a basic regular expression and
+.Cm new
+can contain an ampersand (&), \\n (where n is a digit) back-references,
+or subexpression matching.
+The
+.Cm old
+string may also contain
+.Dv <newline>
+characters.
+Any non-null character can be used as a delimiter (/ is shown here).
+Multiple
+.Fl s
+expressions can be specified.
+The expressions are applied in the order they are specified on the
+command line, terminating with the first successful substitution.
+The optional trailing
+.Cm g
+continues to apply the substitution expression to the pathname substring
+which starts with the first character following the end of the last successful
+substitution. The first unsuccessful substitution stops the operation of the
+.Cm g
+option.
+The optional trailing
+.Cm p
+will cause the final result of a successful substitution to be written to
+.Dv standard error
+in the following format:
+.Dl <original pathname> >> <new pathname>
+File or archive member names that substitute to the empty string
+are not selected and will be skipped.
+.It Fl t
+Reset the access times of any file or directory read or accessed by
+.Nm pax
+to be the same as they were before being read or accessed by
+.Nm pax .
+.It Fl u
+Ignore files that are older (having a less recent file modification time)
+than a pre-existing file or archive member with the same name.
+During
+.Em read ,
+an archive member with the same name as a file in the file system will be
+extracted if the archive member is newer than the file.
+During
+.Em write ,
+a file system member with the same name as an archive member will be
+written to the archive if it is newer than the archive member.
+During
+.Em copy ,
+the file in the destination hierarchy is replaced by the file in the source
+hierarchy or by a link to the file in the source hierarchy if the file in
+the source hierarchy is newer.
+.It Fl v
+During a
+.Em list
+operation, produce a verbose table of contents using the format of the
+.Xr ls 1
+utility with the
+.Fl l
+option.
+For pathnames representing a hard link to a previous member of the archive,
+the output has the format:
+.Dl <ls -l listing> == <link name>
+For pathnames representing a symbolic link, the output has the format:
+.Dl <ls -l listing> => <link name>
+Where <ls -l listing> is the output format specified by the 
+.Xr ls 1
+utility when used with the
+.Fl l
+option.
+Otherwise for all the other operational modes (
+.Em read , write ,
+and
+.Em copy ) ,
+pathnames are written and flushed to
+.Dv standard error
+without a trailing
+.Dv <newline>
+as soon as processing begins on that file or
+archive member.
+The trailing
+.Dv <newline> ,
+is not buffered, and is written only after the file has been read or written.
+.It Fl x Ar format
+Specify the output archive format, with the default format being
+.Ar ustar .
+.Nm Pax
+currently supports the following formats:
+.Bl -tag -width "sv4cpio"
+.It Ar cpio
+The extended cpio interchange format specified in the
+.St -p1003.2
+standard.
+The default blocksize for this format is 5120 bytes.
+Inode and device information about a file (used for detecting file hard links
+by this format) which may be truncated by this format is detected by
+.Nm pax
+and is repaired.
+.It Ar bcpio
+The old binary cpio format.
+The default blocksize for this format is 5120 bytes.
+This format is not very portable and should not be used when other formats
+are available.
+Inode and device information about a file (used for detecting file hard links
+by this format) which may be truncated by this format is detected by
+.Nm pax
+and is repaired.
+.It Ar sv4cpio
+The System V release 4 cpio.
+The default blocksize for this format is 5120 bytes.
+Inode and device information about a file (used for detecting file hard links
+by this format) which may be truncated by this format is detected by
+.Nm pax
+and is repaired.
+.It Ar sv4crc
+The System V release 4 cpio with file crc checksums.
+The default blocksize for this format is 5120 bytes.
+Inode and device information about a file (used for detecting file hard links
+by this format) which may be truncated by this format is detected by
+.Nm pax
+and is repaired.
+.It Ar tar
+The old BSD tar format as found in BSD4.3.
+The default blocksize for this format is 10240 bytes.
+Pathnames stored by this format must be 100 characters or less in length.
+Only
+.Em regular
+files,
+.Em  hard links , soft links ,
+and
+.Em  directories
+will be archived (other file system types are not supported).
+For backwards compatibility with even older tar formats, a
+.Fl o
+option can be used when writing an archive to omit the storage of directories.
+This option takes the form:
+.Dl Fl o Cm write_opt=nodir
+.It Ar ustar
+The extended tar interchange format specified in the
+.St -p1003.2
+standard.
+The default blocksize for this format is 10240 bytes.
+Pathnames stored by this format must be 250 characters or less in length.
+.El
+.Pp
+.Nm Pax
+will detect and report any file that it is unable to store or extract
+as the result of any specific archive format restrictions.
+The individual archive formats may impose additional restrictions on use.
+Typical archive format restrictions include (but are not limited to):
+file pathname length, file size, link pathname length and the type of the file.
+.It Fl B Ar bytes
+Limit the number of bytes written to a single archive volume to
+.Ar bytes .
+The
+.Ar bytes
+limit can end with
+.Li m ,
+.Li k ,
+or
+.Li b
+to specify multiplication by 1048576 (1M), 1024 (1K) or 512, respectively.
+A pair of
+.Ar bytes
+limits can be separated by
+.Li x
+to indicate a product.
+.Pp
+.Em Warning :
+Only use this option when writing an archive to a device which supports
+an end of file read condition based on last (or largest) write offset
+(such as a regular file or a tape drive). 
+The use of this option with a floppy or hard disk is not recommended.
+.It Fl D
+This option is the same as the
+.Fl u
+option, except that the file inode change time is checked instead of the
+file modification time.
+The file inode change time can be used to select files whose inode information
+(e.g. uid, gid, etc.) is newer than a copy of the file in the destination
+.Ar directory .
+.It Fl E Ar limit
+Limit the number of consecutive read faults while trying to read a flawed
+archives to
+.Ar limit .
+With a positive
+.Ar limit ,
+.Nm pax
+will attempt to recover from an archive read error and will
+continue processing starting with the next file stored in the archive.
+A
+.Ar limit
+of 0 will cause
+.Nm pax
+to stop operation after the first read error is detected on an archive volume.
+A
+.Ar limit
+of
+.Li NONE
+will cause
+.Nm pax 
+to attempt to recover from read errors forever.
+The default 
+.Ar limit
+is a small positive number of retries.
+.Pp
+.Em Warning: 
+Using this option with
+.Li NONE
+should be used with extreme caution as
+.Nm pax
+may get stuck in an infinite loop on a very badly flawed archive.
+.It Fl G Ar group
+Select a file based on its
+.Ar group
+name, or when starting with a
+.Cm # ,
+a numeric gid.
+A '\\' can be used to escape the
+.Cm # .
+Multiple 
+.Fl G
+options may be supplied and checking stops with the first match.
+.It Fl H
+Follow only command line symbolic links while performing a physical file
+system traversal.
+.It Fl L
+Follow all symbolic links to perform a logical file system traversal.
+.It Fl P
+Do not follow symbolic links, perform a physical file system traversal.
+This is the default mode.
+.It Fl T Ar [from_date][,to_date][/[c][m]]
+Allow files to be selected based on a file modification or inode change
+time falling within a specified time range of 
+.Ar from_date
+to
+.Ar to_date
+(the dates are inclusive).
+If only a 
+.Ar from_date
+is supplied, all files with a modification or inode change time
+equal to or younger are selected.
+If only a
+.Ar to_date
+is supplied, all files with a modification or inode change time
+equal to or older will be selected.
+When the 
+.Ar from_date
+is equal to the
+.Ar to_date ,
+only files with a modification or inode change time of exactly that
+time will be selected.
+.Pp
+When
+.Nm pax
+is in the 
+.Em write
+or
+.Em copy
+mode, the optional trailing field
+.Ar [c][m]
+can be used to determine which file time (inode change, file modification or
+both) are used in the comparison.
+If neither is specified, the default is to use file modification time only.
+The
+.Ar m
+specifies the comparison of file modification time (the time when
+the file was last written).
+The
+.Ar c
+specifies the comparison of inode change time (the time when the file
+inode was last changed; e.g. a change of owner, group, mode, etc).
+When 
+.Ar c
+and
+.Ar m
+are both specified, then the modification and inode change times are
+both compared.
+The inode change time comparison is useful in selecting files whose
+attributes were recently changed or selecting files which were recently
+created and had their modification time reset to an older time (as what
+happens when a file is extracted from an archive and the modification time
+is preserved).
+Time comparisons using both file times is useful when
+.Nm pax
+is used to create a time based incremental archive (only files that were
+changed during a specified time range will be archived).
+.Pp
+A time range is made up of six different fields and each field must contain two
+digits.
+The format is:
+.Dl [yy[mm[dd[hh]]]]mm[.ss]
+Where
+.Cm yy
+is the last two digits of the year,
+the first
+.Cm mm
+is the month (from 01 to 12),
+.Cm dd
+is the day of the month (from 01 to 31),
+.Cm hh
+is the hour of the day (from 00 to 23),
+the second
+.Cm mm
+is the minute (from 00 to 59),
+and
+.Cm ss
+is the seconds (from 00 to 59).
+The minute field
+.Cm mm
+is required, while the other fields are optional and must be added in the
+following order:
+.Dl Cm hh , dd , mm , yy .
+The 
+.Cm ss
+field may be added independently of the other fields.
+Time ranges are relative to the current time, so
+.Dl Fl T Ar 1234/cm
+would select all files with a modification or inode change time
+of 12:34 PM today or later.
+Multiple 
+.Fl T
+time range can be supplied and checking stops with the first match.
+.It Fl U Ar user
+Select a file based on its
+.Ar user
+name, or when starting with a
+.Cm # ,
+a numeric uid.
+A '\\' can be used to escape the
+.Cm # .
+Multiple 
+.Fl U
+options may be supplied and checking stops with the first match.
+.It Fl X
+When traversing the file hierarchy specified by a pathname,
+do not descend into directories that have a different device ID.
+See the
+.Li st_dev 
+field as described in
+.Xr stat 2
+for more information about device ID's.
+.It Fl Y
+This option is the same as the
+.Fl D
+option, except that the inode change time is checked using the
+pathname created after all the file name modifications have completed.
+.It Fl Z
+This option is the same as the
+.Fl u
+option, except that the modification time is checked using the
+pathname created after all the file name modifications have completed.
+.El
+.Pp
+The options that operate on the names of files or archive members (
+.Fl c ,
+.Fl i ,
+.Fl n ,
+.Fl s ,
+.Fl u ,
+.Fl v ,
+.Fl D ,
+.Fl G ,
+.Fl T ,
+.Fl U ,
+.Fl Y ,
+and
+.Fl Z )
+interact as follows.
+.Pp
+When extracting files during a
+.Em read
+operation, archive members are
+.Sq selected ,
+based only on the user specified pattern operands as modified by the
+.Fl c ,
+.Fl n ,
+.Fl u ,
+.Fl D ,
+.Fl G ,
+.Fl T ,
+.Fl U
+options.
+Then any
+.Fl s
+and
+.Fl i
+options will modify in that order, the names of these selected files.
+Then the
+.Fl Y
+and
+.Fl Z
+options will be applied based on the final pathname.
+Finally the 
+.Fl v
+option will write the names resulting from these modifications.
+.Pp
+When archiving files during a
+.Em write
+operation, or copying files during a
+.Em copy
+operation, archive members are
+.Sq selected ,
+based only on the user specified pathnames as modified by the
+.Fl n ,
+.Fl u ,
+.Fl D ,
+.Fl G ,
+.Fl T ,
+and 
+.Fl U
+options (the
+.Fl D
+option only applies during a copy operation).
+Then any
+.Fl s 
+and
+.Fl i
+options will modify in that order, the names of these selected files.
+Then during a
+.Em copy
+operation the
+.Fl Y
+and the
+.Fl Z
+options will be applied based on the final pathname.
+Finally the
+.Fl v
+option will write the names resulting from these modifications.
+.Pp
+When one or both of the
+.Fl u
+or
+.Fl D
+options are specified along with the
+.Fl n
+option, a file is not considered selected unless it is newer
+than the file to which it is compared.
+.Sh EXAMPLES
+The command:
+.Dl pax -w -f /dev/rst0 .\ 
+copies the contents of the current directory to the device
+.Pa /dev/rst0 .
+.Pp
+The command:
+.Dl pax -v -f filename
+gives the verbose table of contents for an archive stored in
+.Pa filename .
+.Pp
+The following commands:
+.Dl mkdir newdir
+.Dl cd olddir
+.Dl pax -rw .\ newdir
+will copy the entire
+.Pa olddir
+directory hierarchy to
+.Pa newdir .
+.Pp
+The command:
+.Dl pax -r -s ',^//*usr//*,,' -f a.pax
+reads the archive 
+.Pa a.pax ,
+with all files rooted in ``/usr'' into the archive extracted relative to the
+current directory.
+.Pp
+The command:
+.Dl pax -rw -i .\ dest_dir
+can be used to interactively select the files to copy from the current
+directory to
+.Pa dest_dir .
+.Pp
+The command:
+.Dl pax -r -pe -U root -G bin -f a.pax
+will extract all files from the archive
+.Pa a.pax
+which are owned by
+.Em root
+with group
+.Em bin
+and will preserve all file permissions.
+.Pp
+The command:
+.Dl pax -r -w -v -Y -Z home /backup
+will update (and list) only those files in the destination directory
+.Pa /backup
+which are older (less recent inode change or file modification times) than
+files with the same name found in the source file tree
+.Pa home .
+.Sh STANDARDS
+The
+.Nm pax
+utility is a superset of the
+.St -p1003.2
+standard.
+The options
+.Fl B ,
+.Fl D ,
+.Fl E ,
+.Fl G ,
+.Fl H ,
+.Fl L ,
+.Fl P ,
+.Fl T ,
+.Fl U ,
+.Fl Y ,
+.Fl Z ,
+the archive formats
+.Ar bcpio ,
+.Ar sv4cpio ,
+.Ar sv4crc ,
+.Ar tar ,
+and the flawed archive handling during
+.Ar list
+and
+.Ar read
+operations are extensions to the
+.Tn POSIX
+standard.
+.Sh SEE ALSO
+.Xr tar 1 ,
+.Xr cpio 1
+.Sh AUTHOR
+Keith Muller at the University of California, San Diego
+.Sh ERRORS
+.Nm pax
+will exit with one of the following values:
+.Bl -tag -width 2n
+.It 0
+All files were processed successfully.
+.It 1 
+An error occurred.
+.El
+.Pp
+Whenever
+.Nm pax
+cannot create a file or a link when reading an archive or cannot
+find a file when writing an archive, or cannot preserve the user ID,
+group ID, or file mode when the
+.Fl p
+option is specified, a diagnostic message is written to
+.Dv standard error
+and a non-zero exit status will be returned, but processing will continue.
+In the case where pax cannot create a link to a file,
+.Nm pax
+will not create a second copy of the file.
+.Pp
+If the extraction of a file from an archive is prematurely terminated by
+a signal or error,
+.Nm pax
+may have only partially extracted a file the user wanted.
+Additionally, the file modes of extracted files and directories
+may have incorrect file bits, and the modification and access times may be
+wrong.
+.Pp
+If the creation of an archive is prematurely terminated by a signal or error,
+.Nm pax
+may have only partially created the archive which may violate the specific
+archive format specification.
+.Pp
+If while doing a
+.Em copy ,
+.Nm pax
+detects a file is about to overwrite itself, the file is not copied,
+a diagnostic message is written to
+.Dv standard error
+and when
+.Nm pax
+completes it will exit with a non-zero exit status.
diff --git a/pax/pax.c b/pax/pax.c
new file mode 100644
index 0000000..574ed5b
--- /dev/null
+++ b/pax/pax.c
@@ -0,0 +1,426 @@
+/*	$OpenBSD: pax.c,v 1.11 1997/09/01 18:29:58 deraadt Exp $	*/
+/*	$NetBSD: pax.c,v 1.5 1996/03/26 23:54:20 mrg Exp $	*/
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] __attribute__((__unused__)) =
+"@(#) Copyright (c) 1992, 1993\n\
+	The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)pax.c	8.2 (Berkeley) 4/18/94";
+#else
+static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: pax.c,v 1.11 1997/09/01 18:29:58 deraadt Exp $";
+#endif
+#endif /* not lint */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include "pax.h"
+#include "extern.h"
+static int gen_init __P((void));
+
+/*
+ * PAX main routines, general globals and some simple start up routines
+ */
+
+/*
+ * Variables that can be accessed by any routine within pax
+ */
+int	act = DEFOP;		/* read/write/append/copy */
+FSUB	*frmt = NULL;		/* archive format type */
+int	cflag;			/* match all EXCEPT pattern/file */
+int	cwdfd;			/* starting cwd */
+int	dflag;			/* directory member match only  */
+int	iflag;			/* interactive file/archive rename */
+int	kflag;			/* do not overwrite existing files */
+int	lflag;			/* use hard links when possible */
+int	nflag;			/* select first archive member match */
+int	tflag;			/* restore access time after read */
+int	uflag;			/* ignore older modification time files */
+int	vflag;			/* produce verbose output */
+int	zflag;			/* use gzip */
+int	Dflag;			/* same as uflag except inode change time */
+int	Hflag;			/* follow command line symlinks (write only) */
+int	Lflag;			/* follow symlinks when writing */
+int	Xflag;			/* archive files with same device id only */
+int	Yflag;			/* same as Dflg except after name mode */
+int	Zflag;			/* same as uflg except after name mode */
+int	vfpart;			/* is partial verbose output in progress */
+int	patime = 1;		/* preserve file access time */
+int	pmtime = 1;		/* preserve file modification times */
+int	nodirs;			/* do not create directories as needed */
+int	pmode;			/* preserve file mode bits */
+int	pids;			/* preserve file uid/gid */
+int	rmleadslash = 0;	/* remove leading '/' from pathnames */
+int	exit_val;		/* exit value */
+int	docrc;			/* check/create file crc */
+char	*dirptr;		/* destination dir in a copy */
+char	*ltmfrmt;		/* -v locale time format (if any) */
+char	*argv0;			/* root of argv[0] */
+sigset_t s_mask;		/* signal mask for cleanup critical sect */
+
+/*
+ *	PAX - Portable Archive Interchange
+ *
+ * 	A utility to read, write, and write lists of the members of archive
+ *	files and copy directory hierarchies. A variety of archive formats
+ *	are supported (some are described in POSIX 1003.1 10.1):
+ *
+ *		ustar - 10.1.1 extended tar interchange format
+ *		cpio  - 10.1.2 extended cpio interchange format
+ *		tar - old BSD 4.3 tar format
+ *		binary cpio - old cpio with binary header format
+ *		sysVR4 cpio -  with and without CRC
+ *
+ * This version is a superset of IEEE Std 1003.2b-d3
+ *
+ * Summary of Extensions to the IEEE Standard:
+ *
+ * 1	READ ENHANCEMENTS
+ * 1.1	Operations which read archives will continue to operate even when
+ *	processing archives which may be damaged, truncated, or fail to meet 
+ *	format specs in several different ways. Damaged sections of archives
+ *	are detected and avoided if possible. Attempts will be made to resync
+ *	archive read operations even with badly damaged media.
+ * 1.2	Blocksize requirements are not strictly enforced on archive read.
+ *	Tapes which have variable sized records can be read without errors.
+ * 1.3	The user can specify via the non-standard option flag -E if error
+ *	resync operation should stop on a media error, try a specified number
+ *	of times to correct, or try to correct forever.
+ * 1.4	Sparse files (lseek holes) stored on the archive (but stored with blocks
+ *	of all zeros will be restored with holes appropriate for the target
+ *	filesystem
+ * 1.5	The user is notified whenever something is found during archive
+ *	read operations which violates spec (but the read will continue).
+ * 1.6	Multiple archive volumes can be read and may span over different
+ *	archive devices 
+ * 1.7	Rigidly restores all file attributes exactly as they are stored on the
+ *	archive.
+ * 1.8	Modification change time ranges can be specified via multiple -T
+ *	options. These allow a user to select files whose modification time
+ *	lies within a specific time range.
+ * 1.9	Files can be selected based on owner (user name or uid) via one or more
+ *	-U options.
+ * 1.10	Files can be selected based on group (group name or gid) via one o
+ *	more -G options.
+ * 1.11	File modification time can be checked against exisiting file after
+ *	name modification (-Z)
+ *
+ * 2	WRITE ENHANCEMENTS
+ * 2.1	Write operation will stop instead of allowing a user to create a flawed
+ *	flawed archive (due to any problem).
+ * 2.2	Archives writtens by pax are forced to strictly conform to both the
+ *	archive and pax the spceific format specifications.
+ * 2.3	Blocking size and format is rigidly enforced on writes.
+ * 2.4	Formats which may exhibit header overflow problems (they have fields
+ *	too small for large file systems, such as inode number storage), use
+ *	routines designed to repair this problem. These techniques still
+ *	conform to both pax and format specifications, but no longer truncate
+ *	these fields. This removes any restrictions on using these archive
+ *	formats on large file systems.
+ * 2.5	Multiple archive volumes can be written and may span over different
+ *	archive devices 
+ * 2.6	A archive volume record limit allows the user to specify the number
+ *	of bytes stored on an archive volume. When reached the user is
+ *	prompted for the next archive volume. This is specified with the
+ *	non-standard -B flag. THe limit is rounded up to the next blocksize.
+ * 2.7	All archive padding during write use zero filled sections. This makes
+ *	it much easier to pull data out of flawed archive during read
+ *	operations.
+ * 2.8	Access time reset with the -t applies to all file nodes (including
+ *	directories).
+ * 2.9	Symbolic links can be followed with -L (optional in the spec).
+ * 2.10	Modification or inode change time ranges can be specified via
+ *	multiple -T options. These allow a user to select files whose
+ *	modification or inode change time lies within a specific time range.
+ * 2.11	Files can be selected based on owner (user name or uid) via one or more
+ *	-U options.
+ * 2.12	Files can be selected based on group (group name or gid) via one o
+ *	more -G options.
+ * 2.13	Symlinks which appear on the command line can be followed (without
+ *	following other symlinks; -H flag)
+ *
+ * 3	COPY ENHANCEMENTS
+ * 3.1	Sparse files (lseek holes) can be copied without expanding the holes
+ *	into zero filled blocks. The file copy is created with holes which are
+ *	appropriate for the target filesystem
+ * 3.2	Access time as well as modification time on copied file trees can be
+ *	preserved with the appropriate -p options.
+ * 3.3	Access time reset with the -t applies to all file nodes (including
+ *	directories).
+ * 3.4	Symbolic links can be followed with -L (optional in the spec).
+ * 3.5	Modification or inode change time ranges can be specified via
+ *	multiple -T options. These allow a user to select files whose
+ *	modification or inode change time lies within a specific time range.
+ * 3.6	Files can be selected based on owner (user name or uid) via one or more
+ *	-U options.
+ * 3.7	Files can be selected based on group (group name or gid) via one o
+ *	more -G options.
+ * 3.8	Symlinks which appear on the command line can be followed (without
+ *	following other symlinks; -H flag)
+ * 3.9  File inode change time can be checked against exisiting file before
+ *	name modification (-D)
+ * 3.10 File inode change time can be checked against exisiting file after
+ *	name modification (-Y)
+ * 3.11	File modification time can be checked against exisiting file after
+ *	name modification (-Z)
+ *
+ * 4	GENERAL ENHANCEMENTS
+ * 4.1	Internal structure is designed to isolate format dependent and 
+ *	independent functions. Formats are selected via a format driver table.
+ *	This encourages the addition of new archive formats by only having to
+ *	write those routines which id, read and write the archive header.
+ */
+
+/*
+ * main()
+ *	parse options, set up and operate as specified by the user.
+ *	any operational flaw will set exit_val to non-zero
+ * Return: 0 if ok, 1 otherwise
+ */
+
+#ifdef __STDC__
+int
+main(int argc, char **argv)
+#else
+int
+main(argc, argv)
+	int argc;
+	char **argv;
+#endif
+{
+	/*
+	 * Keep a reference to cwd, so we can always come back home.
+	 */
+	cwdfd = open(".", O_RDONLY);
+	if (cwdfd < 0) {
+		syswarn(0, errno, "Can't open current working directory.");
+		return(exit_val);
+	}
+
+	/*
+	 * parse options, determine operational mode, general init
+	 */
+	options(argc, argv);
+	if ((gen_init() < 0) || (tty_init() < 0))
+		return(exit_val);
+
+	/*
+	 * select a primary operation mode 
+	 */
+	switch(act) {
+	case EXTRACT:
+		extract();
+		break;
+	case ARCHIVE:
+		archive();
+		break;
+	case APPND:
+		append();
+		break;
+	case COPY:
+		copy();
+		break;
+	default:
+	case LIST:
+		list();
+		break;
+	}
+	return(exit_val);
+}
+
+/*
+ * sig_cleanup()
+ *	when interrupted we try to do whatever delayed processing we can.
+ *	This is not critical, but we really ought to limit our damage when we
+ *	are aborted by the user.
+ * Return:
+ *	never....
+ */
+
+#ifdef __STDC__
+void
+sig_cleanup(int which_sig)
+#else
+void
+sig_cleanup(which_sig)
+	int which_sig;
+#endif
+{
+	/*
+	 * restore modes and times for any dirs we may have created
+	 * or any dirs we may have read. Set vflag and vfpart so the user
+	 * will clearly see the message on a line by itself.
+	 */
+	vflag = vfpart = 1;
+	if (which_sig == SIGXCPU)
+		paxwarn(0, "Cpu time limit reached, cleaning up.");
+	else
+		paxwarn(0, "Signal caught, cleaning up.");
+
+	ar_close();
+	proc_dir();
+	if (tflag)
+		atdir_end();
+	exit(1);
+}
+
+/*
+ * gen_init()
+ *	general setup routines. Not all are required, but they really help
+ *	when dealing with a medium to large sized archives.
+ */
+
+#ifdef __STDC__
+static int
+gen_init(void)
+#else
+static int
+gen_init()
+#endif
+{
+	struct rlimit reslimit;
+	struct sigaction n_hand;
+	struct sigaction o_hand;
+
+	/*
+	 * Really needed to handle large archives. We can run out of memory for
+	 * internal tables really fast when we have a whole lot of files...
+	 */
+	if (getrlimit(RLIMIT_DATA , &reslimit) == 0){
+		reslimit.rlim_cur = reslimit.rlim_max;
+		(void)setrlimit(RLIMIT_DATA , &reslimit);
+	}
+
+	/*
+	 * should file size limits be waived? if the os limits us, this is
+	 * needed if we want to write a large archive
+	 */
+	if (getrlimit(RLIMIT_FSIZE , &reslimit) == 0){
+		reslimit.rlim_cur = reslimit.rlim_max;
+		(void)setrlimit(RLIMIT_FSIZE , &reslimit);
+	}
+
+	/*
+	 * increase the size the stack can grow to
+	 */
+	if (getrlimit(RLIMIT_STACK , &reslimit) == 0){
+		reslimit.rlim_cur = reslimit.rlim_max;
+		(void)setrlimit(RLIMIT_STACK , &reslimit);
+	}
+
+	/*
+	 * not really needed, but doesn't hurt
+	 */
+	if (getrlimit(RLIMIT_RSS , &reslimit) == 0){
+		reslimit.rlim_cur = reslimit.rlim_max;
+		(void)setrlimit(RLIMIT_RSS , &reslimit);
+	}
+
+	/*
+	 * Handle posix locale
+	 *
+	 * set user defines time printing format for -v option 
+	 */
+	ltmfrmt = getenv("LC_TIME");
+
+	/*
+	 * signal handling to reset stored directory times and modes. Since
+	 * we deal with broken pipes via failed writes we ignore it. We also
+	 * deal with any file size limit thorugh failed writes. Cpu time
+	 * limits are caught and a cleanup is forced.
+	 */
+	if ((sigemptyset(&s_mask) < 0) || (sigaddset(&s_mask, SIGTERM) < 0) ||
+	    (sigaddset(&s_mask,SIGINT) < 0)||(sigaddset(&s_mask,SIGHUP) < 0) ||
+	    (sigaddset(&s_mask,SIGPIPE) < 0)||(sigaddset(&s_mask,SIGQUIT)<0) ||
+	    (sigaddset(&s_mask,SIGXCPU) < 0)||(sigaddset(&s_mask,SIGXFSZ)<0)) {
+		paxwarn(1, "Unable to set up signal mask");
+		return(-1);
+	}
+	n_hand.sa_mask = s_mask;
+	n_hand.sa_flags = 0;
+	n_hand.sa_handler = sig_cleanup;
+
+	if ((sigaction(SIGHUP, &n_hand, &o_hand) < 0) &&
+	    (o_hand.sa_handler == SIG_IGN) &&
+	    (sigaction(SIGHUP, &o_hand, &o_hand) < 0))
+		goto out;
+
+	if ((sigaction(SIGTERM, &n_hand, &o_hand) < 0) &&
+	    (o_hand.sa_handler == SIG_IGN) &&
+	    (sigaction(SIGTERM, &o_hand, &o_hand) < 0))
+		goto out;
+
+	if ((sigaction(SIGINT, &n_hand, &o_hand) < 0) &&
+	    (o_hand.sa_handler == SIG_IGN) &&
+	    (sigaction(SIGINT, &o_hand, &o_hand) < 0))
+		goto out;
+
+	if ((sigaction(SIGQUIT, &n_hand, &o_hand) < 0) &&
+	    (o_hand.sa_handler == SIG_IGN) &&
+	    (sigaction(SIGQUIT, &o_hand, &o_hand) < 0))
+		goto out;
+
+	if ((sigaction(SIGXCPU, &n_hand, &o_hand) < 0) &&
+	    (o_hand.sa_handler == SIG_IGN) &&
+	    (sigaction(SIGXCPU, &o_hand, &o_hand) < 0))
+		goto out;
+
+	n_hand.sa_handler = SIG_IGN;
+	if ((sigaction(SIGPIPE, &n_hand, &o_hand) < 0) ||
+	    (sigaction(SIGXFSZ, &n_hand, &o_hand) < 0))
+		goto out;
+	return(0);
+
+    out:
+	syswarn(1, errno, "Unable to set up signal handler");
+	return(-1);
+}
diff --git a/pax/pax.h b/pax/pax.h
new file mode 100644
index 0000000..bdf00a4
--- /dev/null
+++ b/pax/pax.h
@@ -0,0 +1,243 @@
+/*	$OpenBSD: pax.h,v 1.9 1997/07/23 19:15:58 kstailey Exp $	*/
+/*	$NetBSD: pax.h,v 1.3 1995/03/21 09:07:41 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)pax.h	8.2 (Berkeley) 4/18/94
+ */
+
+/*
+ * BSD PAX global data structures and constants.
+ */
+
+#define	MAXBLK		64512	/* MAX blocksize supported (posix SPEC) */
+				/* WARNING: increasing MAXBLK past 32256 */
+				/* will violate posix spec. */
+#define	MAXBLK_POSIX	32256	/* MAX blocksize supported as per POSIX */
+#define BLKMULT		512	/* blocksize must be even mult of 512 bytes */
+				/* Don't even think of changing this */
+#define DEVBLK		8192	/* default read blksize for devices */
+#define FILEBLK		10240	/* default read blksize for files */
+#define PAXPATHLEN	3072	/* maximium path length for pax. MUST be */
+				/* longer than the system MAXPATHLEN */
+
+/*
+ * Pax modes of operation
+ */
+#define	LIST		0	/* List the file in an archive */
+#define	EXTRACT		1	/* extract the files in an archive */
+#define ARCHIVE		2	/* write a new archive */
+#define APPND		3	/* append to the end of an archive */
+#define	COPY		4	/* copy files to destination dir */
+#define DEFOP		LIST	/* if no flags default is to LIST */
+
+/*
+ * Device type of the current archive volume 
+ */
+#define ISREG		0	/* regular file */
+#define ISCHR		1	/* character device */
+#define ISBLK		2	/* block device */
+#define ISTAPE		3	/* tape drive */
+#define ISPIPE		4	/* pipe/socket */
+
+/*
+ * Format Specific Routine Table
+ *
+ * The format specific routine table allows new archive formats to be quickly
+ * added. Overall pax operation is independent of the actual format used to
+ * form the archive. Only those routines which deal directly with the archive 
+ * are tailored to the oddities of the specifc format. All other routines are
+ * independent of the archive format. Data flow in and out of the format
+ * dependent routines pass pointers to ARCHD structure (described below).
+ */
+typedef struct {
+	char *name;		/* name of format, this is the name the user */
+				/* gives to -x option to select it. */
+	int bsz;		/* default block size. used when the user */
+				/* does not specify a blocksize for writing */
+				/* Appends continue to with the blocksize */
+				/* the archive is currently using. */
+	int hsz;		/* Header size in bytes. this is the size of */
+				/* the smallest header this format supports. */
+				/* Headers are assumed to fit in a BLKMULT. */
+				/* If they are bigger, get_head() and */
+				/* get_arc() must be adjusted */
+	int udev;		/* does append require unique dev/ino? some */
+				/* formats use the device and inode fields */
+				/* to specify hard links. when members in */
+				/* the archive have the same inode/dev they */
+				/* are assumed to be hard links. During */
+				/* append we may have to generate unique ids */
+				/* to avoid creating incorrect hard links */
+	int hlk;		/* does archive store hard links info? if */
+				/* not, we do not bother to look for them */
+				/* during archive write operations */
+	int blkalgn;		/* writes must be aligned to blkalgn boundry */
+	int inhead;		/* is the trailer encoded in a valid header? */
+				/* if not, trailers are assumed to be found */
+				/* in invalid headers (i.e like tar) */
+	int (*id)();		/* checks if a buffer is a valid header */
+				/* returns 1 if it is, o.w. returns a 0 */
+	int (*st_rd)();		/* initialize routine for read. so format */
+				/* can set up tables etc before it starts */
+				/* reading an archive */
+	int (*rd)();		/* read header routine. passed a pointer to */
+				/* ARCHD. It must extract the info from the */
+				/* format and store it in the ARCHD struct. */
+				/* This routine is expected to fill all the */
+				/* fields in the ARCHD (including stat buf) */
+				/* 0 is returned when a valid header is */
+				/* found. -1 when not valid. This routine */
+				/* set the skip and pad fields so the format */
+				/* independent routines know the amount of */
+				/* padding and the number of bytes of data */
+				/* which follow the header. This info is */
+				/* used skip to the next file header */
+	off_t (*end_rd)();	/* read cleanup. Allows format to clean up */
+				/* and MUST RETURN THE LENGTH OF THE TRAILER */
+				/* RECORD (so append knows how many bytes */
+				/* to move back to rewrite the trailer) */
+	int (*st_wr)();		/* initialize routine for write operations */
+	int (*wr)();		/* write archive header. Passed an ARCHD */
+				/* filled with the specs on the next file to */
+				/* archived. Returns a 1 if no file data is */
+				/* is to be stored; 0 if file data is to be */
+				/* added. A -1 is returned if a write */
+				/* operation to the archive failed. this */
+				/* function sets the skip and pad fields so */
+				/* the proper padding can be added after */
+				/* file data. This routine must NEVER write */
+				/* a flawed archive header. */
+	int (*end_wr)();	/* end write. write the trailer and do any */
+				/* other format specific functions needed */
+				/* at the ecnd of a archive write */
+	int (*trail)();		/* returns 0 if a valid trailer, -1 if not */
+				/* For formats which encode the trailer */
+				/* outside of a valid header, a return value */
+				/* of 1 indicates that the block passed to */
+				/* it can never contain a valid header (skip */
+				/* this block, no point in looking at it)  */
+				/* CAUTION: parameters to this function are */
+				/* different for trailers inside or outside */
+				/* of headers. See get_head() for details */
+	int (*rd_data)();	/* read/process file data from the archive */
+	int (*wr_data)();	/* write/process file data to the archive */
+	int (*options)();	/* process format specific options (-o) */
+} FSUB;
+
+/*
+ * Pattern matching structure
+ *
+ * Used to store command line patterns
+ */
+typedef struct pattern {
+	char		*pstr;		/* pattern to match, user supplied */
+	char		*pend;		/* end of a prefix match */
+	char		*chdname;	/* the dir to change to if not NULL.  */
+	int		plen;		/* length of pstr */
+	int		flgs;		/* processing/state flags */
+#define MTCH		0x1		/* pattern has been matched */
+#define DIR_MTCH	0x2		/* pattern matched a directory */
+	struct pattern	*fow;		/* next pattern */
+} PATTERN;
+
+/*
+ * General Archive Structure (used internal to pax)
+ *
+ * This structure is used to pass information about archive members between
+ * the format independent routines and the format specific routines. When
+ * new archive formats are added, they must accept requests and supply info
+ * encoded in a structure of this type. The name fields are declared statically
+ * here, as there is only ONE of these floating around, size is not a major
+ * consideration. Eventually converting the name fields to a dynamic length
+ * may be required if and when the supporting operating system removes all
+ * restrictions on the length of pathnames it will resolve.
+ */
+typedef struct {
+	int nlen;			/* file name length */
+	char name[PAXPATHLEN+1];	/* file name */
+	int ln_nlen;			/* link name length */
+	char ln_name[PAXPATHLEN+1];	/* name to link to (if any) */
+	char *org_name;			/* orig name in file system */
+	PATTERN *pat;			/* ptr to pattern match (if any) */
+	struct stat sb;			/* stat buffer see stat(2) */
+	off_t pad;			/* bytes of padding after file xfer */
+	off_t skip;			/* bytes of real data after header */
+					/* IMPORTANT. The st_size field does */
+					/* not always indicate the amount of */
+					/* data following the header. */
+	u_long crc;			/* file crc */
+	int type;			/* type of file node */
+#define PAX_DIR		1		/* directory */
+#define PAX_CHR		2		/* character device */
+#define PAX_BLK		3		/* block device */
+#define PAX_REG		4		/* regular file */
+#define PAX_SLK		5		/* symbolic link */
+#define PAX_SCK		6		/* socket */
+#define PAX_FIF		7		/* fifo */
+#define PAX_HLK		8		/* hard link */
+#define PAX_HRG		9		/* hard link to a regular file */
+#define PAX_CTG		10		/* high performance file */ 
+} ARCHD;
+
+/*
+ * Format Specific Options List
+ *
+ * Used to pass format options to the format options handler
+ */
+typedef struct oplist {
+	char		*name;		/* option variable name e.g. name= */
+	char		*value;		/* value for option variable */
+	struct oplist	*fow;		/* next option */
+} OPLIST;
+
+/*
+ * General Macros
+ */
+#ifndef MIN
+#define	       MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+#define MAJOR(x)	major(x)
+#define MINOR(x)	minor(x)
+#define TODEV(x, y)	makedev((x), (y))
+
+/*
+ * General Defines
+ */
+#define HEX	16
+#define OCT	8
+#define _PAX_	1
diff --git a/pax/sel_subs.c b/pax/sel_subs.c
new file mode 100644
index 0000000..a4e1c22
--- /dev/null
+++ b/pax/sel_subs.c
@@ -0,0 +1,662 @@
+/*	$OpenBSD: sel_subs.c,v 1.7 1997/08/17 23:05:09 millert Exp $	*/
+/*	$NetBSD: sel_subs.c,v 1.5 1995/03/21 09:07:42 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)sel_subs.c	8.1 (Berkeley) 5/31/93";
+#else
+static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: sel_subs.c,v 1.7 1997/08/17 23:05:09 millert Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <pwd.h>
+#include <grp.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "pax.h"
+#include "sel_subs.h"
+#include "extern.h"
+
+static int str_sec __P((register char *, time_t *));
+static int usr_match __P((register ARCHD *));
+static int grp_match __P((register ARCHD *));
+static int trng_match __P((register ARCHD *));
+
+static TIME_RNG *trhead = NULL;		/* time range list head */
+static TIME_RNG *trtail = NULL;		/* time range list tail */
+static USRT **usrtb = NULL;		/* user selection table */
+static GRPT **grptb = NULL;		/* group selection table */
+
+/*
+ * Routines for selection of archive members
+ */
+
+/*
+ * sel_chk()
+ *	check if this file matches a specfied uid, gid or time range
+ * Return:
+ *	0 if this archive member should be processed, 1 if it should be skipped
+ */
+
+#ifdef __STDC__
+int
+sel_chk(register ARCHD *arcn)
+#else
+int
+sel_chk(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	if (((usrtb != NULL) && usr_match(arcn)) ||
+	    ((grptb != NULL) && grp_match(arcn)) ||
+	    ((trhead != NULL) && trng_match(arcn)))
+		return(1);
+	return(0);
+}
+
+/*
+ * User/group selection routines
+ *
+ * Routines to handle user selection of files based on the file uid/gid. To
+ * add an entry, the user supplies either then name or the uid/gid starting with
+ * a # on the command line. A \# will eascape the #.
+ */
+
+/*
+ * usr_add()
+ *	add a user match to the user match hash table
+ * Return:
+ *	0 if added ok, -1 otherwise;
+ */
+
+#ifdef __STDC__
+int
+usr_add(register char *str)
+#else
+int
+usr_add(str)
+	register char *str;
+#endif
+{
+	register u_int indx;
+	register USRT *pt;
+	register struct passwd *pw;
+	register uid_t uid;
+
+	/*
+	 * create the table if it doesn't exist
+	 */
+	if ((str == NULL) || (*str == '\0'))
+		return(-1);
+	if ((usrtb == NULL) &&
+ 	    ((usrtb = (USRT **)calloc(USR_TB_SZ, sizeof(USRT *))) == NULL)) {
+		paxwarn(1, "Unable to allocate memory for user selection table");
+		return(-1);
+	}
+
+	/*
+	 * figure out user spec
+	 */
+	if (str[0] != '#') {
+		/*
+		 * it is a user name, \# escapes # as first char in user name
+		 */
+		if ((str[0] == '\\') && (str[1] == '#'))
+			++str;
+		if ((pw = getpwnam(str)) == NULL) {
+			paxwarn(1, "Unable to find uid for user: %s", str);
+			return(-1);
+		}
+		uid = (uid_t)pw->pw_uid;
+	} else
+#		ifdef NET2_STAT
+		uid = (uid_t)atoi(str+1);
+#		else
+		uid = (uid_t)strtoul(str+1, NULL, 10);
+#		endif
+	endpwent();
+
+	/*
+	 * hash it and go down the hash chain (if any) looking for it
+	 */
+	indx = ((unsigned)uid) % USR_TB_SZ;
+	if ((pt = usrtb[indx]) != NULL) {
+		while (pt != NULL) {
+			if (pt->uid == uid)
+				return(0);
+			pt = pt->fow;
+		}
+	}
+
+	/*
+	 * uid is not yet in the table, add it to the front of the chain
+	 */
+	if ((pt = (USRT *)malloc(sizeof(USRT))) != NULL) {
+		pt->uid = uid;
+		pt->fow = usrtb[indx];
+		usrtb[indx] = pt;
+		return(0);
+	}
+	paxwarn(1, "User selection table out of memory");
+	return(-1);
+}
+
+/*
+ * usr_match()
+ *	check if this files uid matches a selected uid.
+ * Return:
+ *	0 if this archive member should be processed, 1 if it should be skipped
+ */
+
+#ifdef __STDC__
+static int
+usr_match(register ARCHD *arcn)
+#else
+static int
+usr_match(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	register USRT *pt;
+
+	/*
+	 * hash and look for it in the table
+	 */
+	pt = usrtb[((unsigned)arcn->sb.st_uid) % USR_TB_SZ];
+	while (pt != NULL) {
+		if (pt->uid == arcn->sb.st_uid)
+			return(0);
+		pt = pt->fow;
+	}
+
+	/*
+	 * not found
+	 */
+	return(1);
+}
+
+/*
+ * grp_add()
+ *	add a group match to the group match hash table
+ * Return:
+ *	0 if added ok, -1 otherwise;
+ */
+
+#ifdef __STDC__
+int
+grp_add(register char *str)
+#else
+int
+grp_add(str)
+	register char *str;
+#endif
+{
+	register u_int indx;
+	register GRPT *pt;
+	register struct group *gr;
+	register gid_t gid;
+
+	/*
+	 * create the table if it doesn't exist
+	 */
+	if ((str == NULL) || (*str == '\0'))
+		return(-1);
+	if ((grptb == NULL) &&
+ 	    ((grptb = (GRPT **)calloc(GRP_TB_SZ, sizeof(GRPT *))) == NULL)) {
+		paxwarn(1, "Unable to allocate memory fo group selection table");
+		return(-1);
+	}
+
+	/*
+	 * figure out user spec
+	 */
+	if (str[0] != '#') {
+		/*
+		 * it is a group name, \# escapes # as first char in group name
+		 */
+		if ((str[0] == '\\') && (str[1] == '#'))
+			++str;
+		if ((gr = getgrnam(str)) == NULL) {
+			paxwarn(1,"Cannot determine gid for group name: %s", str);
+			return(-1);
+		}
+		gid = (gid_t)gr->gr_gid;
+	} else
+#		ifdef NET2_STAT
+		gid = (gid_t)atoi(str+1);
+#		else
+		gid = (gid_t)strtoul(str+1, NULL, 10);
+#		endif
+	endgrent();
+
+	/*
+	 * hash it and go down the hash chain (if any) looking for it
+	 */
+	indx = ((unsigned)gid) % GRP_TB_SZ;
+	if ((pt = grptb[indx]) != NULL) {
+		while (pt != NULL) {
+			if (pt->gid == gid)
+				return(0);
+			pt = pt->fow;
+		}
+	}
+
+	/*
+	 * gid not in the table, add it to the front of the chain
+	 */
+	if ((pt = (GRPT *)malloc(sizeof(GRPT))) != NULL) {
+		pt->gid = gid;
+		pt->fow = grptb[indx];
+		grptb[indx] = pt;
+		return(0);
+	}
+	paxwarn(1, "Group selection table out of memory");
+	return(-1);
+}
+
+/*
+ * grp_match()
+ *	check if this files gid matches a selected gid.
+ * Return:
+ *	0 if this archive member should be processed, 1 if it should be skipped
+ */
+
+#ifdef __STDC__
+static int
+grp_match(register ARCHD *arcn)
+#else
+static int
+grp_match(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	register GRPT *pt;
+
+	/*
+	 * hash and look for it in the table
+	 */
+	pt = grptb[((unsigned)arcn->sb.st_gid) % GRP_TB_SZ];
+	while (pt != NULL) {
+		if (pt->gid == arcn->sb.st_gid)
+			return(0);
+		pt = pt->fow;
+	}
+
+	/*
+	 * not found
+	 */
+	return(1);
+}
+
+/*
+ * Time range selection routines
+ *
+ * Routines to handle user selection of files based on the modification and/or
+ * inode change time falling within a specified time range (the non-standard
+ * -T flag). The user may specify any number of different file time ranges.
+ * Time ranges are checked one at a time until a match is found (if at all).
+ * If the file has a mtime (and/or ctime) which lies within one of the time
+ * ranges, the file is selected. Time ranges may have a lower and/or a upper
+ * value. These ranges are inclusive. When no time ranges are supplied to pax
+ * with the -T option, all members in the archive will be selected by the time
+ * range routines. When only a lower range is supplied, only files with a
+ * mtime (and/or ctime) equal to or younger are selected. When only a upper
+ * range is supplied, only files with a mtime (and/or ctime) equal to or older
+ * are selected. When the lower time range is equal to the upper time range,
+ * only files with a mtime (or ctime) of exactly that time are selected.
+ */
+
+/*
+ * trng_add()
+ *	add a time range match to the time range list.
+ *	This is a non-standard pax option. Lower and upper ranges are in the
+ *	format: [yy[mm[dd[hh]]]]mm[.ss] and are comma separated.
+ *	Time ranges are based on current time, so 1234 would specify a time of
+ *	12:34 today.
+ * Return:
+ *	0 if the time range was added to the list, -1 otherwise
+ */
+
+#ifdef __STDC__
+int
+trng_add(register char *str)
+#else
+int
+trng_add(str)
+	register char *str;
+#endif
+{
+	register TIME_RNG *pt;
+	register char *up_pt = NULL;
+	register char *stpt;
+	register char *flgpt;
+	register int dot = 0;
+
+	/*
+	 * throw out the badly formed time ranges
+	 */
+	if ((str == NULL) || (*str == '\0')) {
+		paxwarn(1, "Empty time range string");
+		return(-1);
+	}
+
+	/*
+	 * locate optional flags suffix /{cm}.
+	 */
+	if ((flgpt = strrchr(str, '/')) != NULL)
+		*flgpt++ = '\0';
+
+	for (stpt = str; *stpt != '\0'; ++stpt) {
+		if ((*stpt >= '0') && (*stpt <= '9'))
+			continue;
+		if ((*stpt == ',') && (up_pt == NULL)) {
+			*stpt = '\0';
+			up_pt = stpt + 1;
+			dot = 0;
+			continue;
+		}
+
+		/*
+		 * allow only one dot per range (secs)
+		 */
+		if ((*stpt == '.') && (!dot)) {
+			++dot;
+			continue;
+		}
+		paxwarn(1, "Improperly specified time range: %s", str);
+		goto out;
+	}
+
+	/*
+	 * allocate space for the time range and store the limits
+	 */
+	if ((pt = (TIME_RNG *)malloc(sizeof(TIME_RNG))) == NULL) {
+		paxwarn(1, "Unable to allocate memory for time range");
+		return(-1);
+	}
+
+	/*
+	 * by default we only will check file mtime, but usee can specify
+	 * mtime, ctime (inode change time) or both.
+	 */
+	if ((flgpt == NULL) || (*flgpt == '\0'))
+		pt->flgs = CMPMTME;
+	else {
+		pt->flgs = 0;
+		while (*flgpt != '\0') {
+			switch(*flgpt) {
+			case 'M':
+			case 'm':
+				pt->flgs |= CMPMTME;
+				break;
+			case 'C':
+			case 'c':
+				pt->flgs |= CMPCTME;
+				break;
+			default:
+				paxwarn(1, "Bad option %c with time range %s",
+				    *flgpt, str);
+				goto out;
+			}
+			++flgpt;
+		}
+	}
+
+	/*
+	 * start off with the current time
+	 */
+	pt->low_time = pt->high_time = time(NULL);
+	if (*str != '\0') {
+		/*
+		 * add lower limit
+		 */
+		if (str_sec(str, &(pt->low_time)) < 0) {
+			paxwarn(1, "Illegal lower time range %s", str);
+			(void)free((char *)pt);
+			goto out;
+		}
+		pt->flgs |= HASLOW;
+	}
+
+	if ((up_pt != NULL) && (*up_pt != '\0')) {
+		/*
+		 * add upper limit
+		 */
+		if (str_sec(up_pt, &(pt->high_time)) < 0) {
+			paxwarn(1, "Illegal upper time range %s", up_pt);
+			(void)free((char *)pt);
+			goto out;
+		}
+		pt->flgs |= HASHIGH;
+
+		/*
+		 * check that the upper and lower do not overlap
+		 */
+		if (pt->flgs & HASLOW) {
+			if (pt->low_time > pt->high_time) {
+				paxwarn(1, "Upper %s and lower %s time overlap",
+					up_pt, str);
+				(void)free((char *)pt);
+				return(-1);
+			}
+		}
+	}
+
+	pt->fow = NULL;
+	if (trhead == NULL) {
+		trtail = trhead = pt;
+		return(0);
+	}
+	trtail->fow = pt;
+	trtail = pt;
+	return(0);
+
+    out:
+	paxwarn(1, "Time range format is: [yy[mm[dd[hh]]]]mm[.ss][/[c][m]]");
+	return(-1);
+}
+
+/*
+ * trng_match()
+ *	check if this files mtime/ctime falls within any supplied time range.
+ * Return:
+ *	0 if this archive member should be processed, 1 if it should be skipped
+ */
+
+#ifdef __STDC__
+static int
+trng_match(register ARCHD *arcn)
+#else
+static int
+trng_match(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	register TIME_RNG *pt;
+
+	/*
+	 * have to search down the list one at a time looking for a match.
+	 * remember time range limits are inclusive.
+	 */
+	pt = trhead;
+	while (pt != NULL) {
+		switch(pt->flgs & CMPBOTH) {
+		case CMPBOTH:
+			/*
+			 * user wants both mtime and ctime checked for this
+			 * time range
+			 */
+			if (((pt->flgs & HASLOW) &&
+			    (arcn->sb.st_mtime < pt->low_time) &&
+			    (arcn->sb.st_ctime < pt->low_time)) ||
+			    ((pt->flgs & HASHIGH) &&
+			    (arcn->sb.st_mtime > pt->high_time) &&
+			    (arcn->sb.st_ctime > pt->high_time))) {
+				pt = pt->fow;
+				continue;
+			}
+			break;
+		case CMPCTME:
+			/*
+			 * user wants only ctime checked for this time range
+			 */
+			if (((pt->flgs & HASLOW) &&
+			    (arcn->sb.st_ctime < pt->low_time)) ||
+			    ((pt->flgs & HASHIGH) &&
+			    (arcn->sb.st_ctime > pt->high_time))) {
+				pt = pt->fow;
+				continue;
+			}
+			break;
+		case CMPMTME:
+		default:
+			/*
+			 * user wants only mtime checked for this time range
+			 */
+			if (((pt->flgs & HASLOW) &&
+			    (arcn->sb.st_mtime < pt->low_time)) ||
+			    ((pt->flgs & HASHIGH) &&
+			    (arcn->sb.st_mtime > pt->high_time))) {
+				pt = pt->fow;
+				continue;
+			}
+			break;
+		}
+		break;
+	}
+
+	if (pt == NULL)
+		return(1);
+	return(0);
+}
+
+/*
+ * str_sec()
+ *	Convert a time string in the format of [yy[mm[dd[hh]]]]mm[.ss] to gmt
+ *	seconds. Tval already has current time loaded into it at entry.
+ * Return:
+ *	0 if converted ok, -1 otherwise
+ */
+
+#ifdef __STDC__
+static int
+str_sec(register char *str, time_t *tval)
+#else
+static int
+str_sec(str, tval)
+	register char *str;
+	time_t *tval;
+#endif
+{
+	register struct tm *lt;
+	register char *dot = NULL;
+
+	lt = localtime(tval);
+	if ((dot = strchr(str, '.')) != NULL) {
+		/*
+		 * seconds (.ss)
+		 */
+		*dot++ = '\0';
+		if (strlen(dot) != 2)
+			return(-1);
+		if ((lt->tm_sec = ATOI2(dot)) > 61)
+			return(-1);
+	} else
+		lt->tm_sec = 0;
+
+	switch (strlen(str)) {
+	case 10:
+		/*
+		 * year (yy)
+		 * watch out for year 2000
+		 */
+		if ((lt->tm_year = ATOI2(str)) < 69)
+			lt->tm_year += 100;
+		str += 2;
+		/* FALLTHROUGH */
+	case 8:
+		/*
+		 * month (mm)
+		 * watch out months are from 0 - 11 internally
+		 */
+		if ((lt->tm_mon = ATOI2(str)) > 12)
+			return(-1);
+		--lt->tm_mon;
+		str += 2;
+		/* FALLTHROUGH */
+	case 6:
+		/*
+		 * day (dd)
+		 */
+		if ((lt->tm_mday = ATOI2(str)) > 31)
+			return(-1);
+		str += 2;
+		/* FALLTHROUGH */
+	case 4:
+		/*
+		 * hour (hh)
+		 */
+		if ((lt->tm_hour = ATOI2(str)) > 23)
+			return(-1);
+		str += 2;
+		/* FALLTHROUGH */
+	case 2:
+		/*
+		 * minute (mm)
+		 */
+		if ((lt->tm_min = ATOI2(str)) > 59)
+			return(-1);
+		break;
+	default:
+		return(-1);
+	}
+	/*
+	 * convert broken-down time to GMT clock time seconds
+	 */
+	if ((*tval = mktime(lt)) == -1)
+		return(-1);
+	return(0);
+}
diff --git a/pax/sel_subs.h b/pax/sel_subs.h
new file mode 100644
index 0000000..fc86e9d
--- /dev/null
+++ b/pax/sel_subs.h
@@ -0,0 +1,76 @@
+/*	$OpenBSD: sel_subs.h,v 1.2 1996/06/23 14:20:41 deraadt Exp $	*/
+/*	$NetBSD: sel_subs.h,v 1.3 1995/03/21 09:07:44 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)sel_subs.h	8.1 (Berkeley) 5/31/93
+ */
+
+/*
+ * data structure for storing uid/grp selects (-U, -G non standard options)
+ */
+
+#define USR_TB_SZ	317		/* user selection table size */
+#define GRP_TB_SZ	317		/* user selection table size */
+
+typedef struct usrt {
+	uid_t uid;
+	struct usrt *fow;		/* next uid */
+} USRT;
+
+typedef struct grpt {
+	gid_t gid;
+	struct grpt *fow;		/* next gid */
+} GRPT;
+
+/*
+ * data structure for storing user supplied time ranges (-T option)
+ */
+
+#define ATOI2(s)	((((s)[0] - '0') * 10) + ((s)[1] - '0'))
+
+typedef struct time_rng {
+	time_t		low_time;	/* lower inclusive time limit */
+	time_t		high_time;	/* higher inclusive time limit */
+	int		flgs;		/* option flags */
+#define	HASLOW		0x01		/* has lower time limit */
+#define HASHIGH		0x02		/* has higher time limit */
+#define CMPMTME		0x04		/* compare file modification time */
+#define CMPCTME		0x08		/* compare inode change time */
+#define CMPBOTH	(CMPMTME|CMPCTME)	/* compare inode and mod time */
+	struct time_rng	*fow;		/* next pattern */
+} TIME_RNG;
diff --git a/pax/tables.c b/pax/tables.c
new file mode 100644
index 0000000..a0a964e
--- /dev/null
+++ b/pax/tables.c
@@ -0,0 +1,1434 @@
+/*	$OpenBSD: tables.c,v 1.9 1997/09/01 18:30:00 deraadt Exp $	*/
+/*	$NetBSD: tables.c,v 1.4 1995/03/21 09:07:45 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)tables.c	8.1 (Berkeley) 5/31/93";
+#else
+static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: tables.c,v 1.9 1997/09/01 18:30:00 deraadt Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "pax.h"
+#include "tables.h"
+#include "extern.h"
+
+/*
+ * Routines for controlling the contents of all the different databases pax
+ * keeps. Tables are dynamically created only when they are needed. The
+ * goal was speed and the ability to work with HUGE archives. The databases
+ * were kept simple, but do have complex rules for when the contents change.
+ * As of this writing, the posix library functions were more complex than
+ * needed for this application (pax databases have very short lifetimes and
+ * do not survive after pax is finished). Pax is required to handle very
+ * large archives. These database routines carefully combine memory usage and
+ * temporary file storage in ways which will not significantly impact runtime
+ * performance while allowing the largest possible archives to be handled.
+ * Trying to force the fit to the posix databases routines was not considered
+ * time well spent.
+ */
+
+static HRDLNK **ltab = NULL;	/* hard link table for detecting hard links */
+static FTM **ftab = NULL;	/* file time table for updating arch */
+static NAMT **ntab = NULL;	/* interactive rename storage table */
+static DEVT **dtab = NULL;	/* device/inode mapping tables */
+static ATDIR **atab = NULL;	/* file tree directory time reset table */
+static int dirfd = -1;		/* storage for setting created dir time/mode */
+static u_long dircnt;		/* entries in dir time/mode storage */
+static int ffd = -1;		/* tmp file for file time table name storage */
+
+static DEVT *chk_dev __P((dev_t, int));
+
+/*
+ * hard link table routines
+ *
+ * The hard link table tries to detect hard links to files using the device and
+ * inode values. We do this when writing an archive, so we can tell the format
+ * write routine that this file is a hard link to another file. The format
+ * write routine then can store this file in whatever way it wants (as a hard
+ * link if the format supports that like tar, or ignore this info like cpio).
+ * (Actually a field in the format driver table tells us if the format wants
+ * hard link info. if not, we do not waste time looking for them). We also use
+ * the same table when reading an archive. In that situation, this table is
+ * used by the format read routine to detect hard links from stored dev and
+ * inode numbers (like cpio). This will allow pax to create a link when one
+ * can be detected by the archive format.
+ */
+
+/*
+ * lnk_start
+ *	Creates the hard link table.
+ * Return:
+ *	0 if created, -1 if failure
+ */
+
+#ifdef __STDC__
+int
+lnk_start(void)
+#else
+int
+lnk_start()
+#endif
+{
+	if (ltab != NULL)
+		return(0);
+ 	if ((ltab = (HRDLNK **)calloc(L_TAB_SZ, sizeof(HRDLNK *))) == NULL) {
+		paxwarn(1, "Cannot allocate memory for hard link table");
+		return(-1);
+	}
+	return(0);
+}
+
+/*
+ * chk_lnk()
+ *	Looks up entry in hard link hash table. If found, it copies the name
+ *	of the file it is linked to (we already saw that file) into ln_name.
+ *	lnkcnt is decremented and if goes to 1 the node is deleted from the
+ *	database. (We have seen all the links to this file). If not found,
+ *	we add the file to the database if it has the potential for having
+ *	hard links to other files we may process (it has a link count > 1)
+ * Return:
+ *	if found returns 1; if not found returns 0; -1 on error
+ */
+
+#ifdef __STDC__
+int
+chk_lnk(register ARCHD *arcn)
+#else
+int
+chk_lnk(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	register HRDLNK *pt;
+	register HRDLNK **ppt;
+	register u_int indx;
+
+	if (ltab == NULL)
+		return(-1);
+	/*
+	 * ignore those nodes that cannot have hard links
+	 */
+	if ((arcn->type == PAX_DIR) || (arcn->sb.st_nlink <= 1))
+		return(0);
+
+	/*
+	 * hash inode number and look for this file
+	 */
+	indx = ((unsigned)arcn->sb.st_ino) % L_TAB_SZ;
+	if ((pt = ltab[indx]) != NULL) {
+		/*
+		 * it's hash chain in not empty, walk down looking for it
+		 */
+		ppt = &(ltab[indx]);
+		while (pt != NULL) {
+			if ((pt->ino == arcn->sb.st_ino) &&
+			    (pt->dev == arcn->sb.st_dev))
+				break;
+			ppt = &(pt->fow);
+			pt = pt->fow;
+		}
+
+		if (pt != NULL) {
+			/*
+			 * found a link. set the node type and copy in the
+			 * name of the file it is to link to. we need to
+			 * handle hardlinks to regular files differently than
+			 * other links.
+			 */
+			arcn->ln_nlen = l_strncpy(arcn->ln_name, pt->name,
+				sizeof(arcn->ln_name) - 1);
+			arcn->ln_name[arcn->ln_nlen] = '\0';
+			if (arcn->type == PAX_REG)
+				arcn->type = PAX_HRG;
+			else
+				arcn->type = PAX_HLK;
+
+			/*
+			 * if we have found all the links to this file, remove
+			 * it from the database
+			 */
+			if (--pt->nlink <= 1) {
+				*ppt = pt->fow;
+				(void)free((char *)pt->name);
+				(void)free((char *)pt);
+			}
+			return(1);
+		}
+	}
+
+	/*
+	 * we never saw this file before. It has links so we add it to the
+	 * front of this hash chain
+	 */
+	if ((pt = (HRDLNK *)malloc(sizeof(HRDLNK))) != NULL) {
+		if ((pt->name = strdup(arcn->name)) != NULL) {
+			pt->dev = arcn->sb.st_dev;
+			pt->ino = arcn->sb.st_ino;
+			pt->nlink = arcn->sb.st_nlink;
+			pt->fow = ltab[indx];
+			ltab[indx] = pt;
+			return(0);
+		}
+		(void)free((char *)pt);
+	}
+
+	paxwarn(1, "Hard link table out of memory");
+	return(-1);
+}
+
+/*
+ * purg_lnk
+ *	remove reference for a file that we may have added to the data base as
+ *	a potential source for hard links. We ended up not using the file, so
+ *	we do not want to accidently point another file at it later on.
+ */
+
+#ifdef __STDC__
+void
+purg_lnk(register ARCHD *arcn)
+#else
+void
+purg_lnk(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	register HRDLNK *pt;
+	register HRDLNK **ppt;
+	register u_int indx;
+
+	if (ltab == NULL)
+		return;
+	/*
+	 * do not bother to look if it could not be in the database
+	 */
+	if ((arcn->sb.st_nlink <= 1) || (arcn->type == PAX_DIR) ||
+	    (arcn->type == PAX_HLK) || (arcn->type == PAX_HRG))
+		return;
+
+	/*
+	 * find the hash chain for this inode value, if empty return
+	 */
+	indx = ((unsigned)arcn->sb.st_ino) % L_TAB_SZ;
+	if ((pt = ltab[indx]) == NULL)
+		return;
+
+	/*
+	 * walk down the list looking for the inode/dev pair, unlink and
+	 * free if found
+	 */
+	ppt = &(ltab[indx]);
+	while (pt != NULL) {
+		if ((pt->ino == arcn->sb.st_ino) &&
+		    (pt->dev == arcn->sb.st_dev))
+			break;
+		ppt = &(pt->fow);
+		pt = pt->fow;
+	}
+	if (pt == NULL)
+		return;
+
+	/*
+	 * remove and free it
+	 */
+	*ppt = pt->fow;
+	(void)free((char *)pt->name);
+	(void)free((char *)pt);
+}
+
+/*
+ * lnk_end()
+ *	pull apart a existing link table so we can reuse it. We do this between
+ *	read and write phases of append with update. (The format may have
+ *	used the link table, and we need to start with a fresh table for the
+ *	write phase
+ */
+
+#ifdef __STDC__
+void
+lnk_end(void)
+#else
+void
+lnk_end()
+#endif
+{
+	register int i;
+	register HRDLNK *pt;
+	register HRDLNK *ppt;
+
+	if (ltab == NULL)
+		return;
+
+	for (i = 0; i < L_TAB_SZ; ++i) {
+		if (ltab[i] == NULL)
+			continue;
+		pt = ltab[i];
+		ltab[i] = NULL;
+
+		/*
+		 * free up each entry on this chain
+		 */
+		while (pt != NULL) {
+			ppt = pt;
+			pt = ppt->fow;
+			(void)free((char *)ppt->name);
+			(void)free((char *)ppt);
+		}
+	}
+	return;
+}
+
+/*
+ * modification time table routines
+ *
+ * The modification time table keeps track of last modification times for all
+ * files stored in an archive during a write phase when -u is set. We only
+ * add a file to the archive if it is newer than a file with the same name
+ * already stored on the archive (if there is no other file with the same
+ * name on the archive it is added). This applies to writes and appends.
+ * An append with an -u must read the archive and store the modification time
+ * for every file on that archive before starting the write phase. It is clear
+ * that this is one HUGE database. To save memory space, the actual file names
+ * are stored in a scatch file and indexed by an in memory hash table. The
+ * hash table is indexed by hashing the file path. The nodes in the table store
+ * the length of the filename and the lseek offset within the scratch file
+ * where the actual name is stored. Since there are never any deletions to this
+ * table, fragmentation of the scratch file is never a issue. Lookups seem to
+ * not exhibit any locality at all (files in the database are rarely
+ * looked up more than once...). So caching is just a waste of memory. The
+ * only limitation is the amount of scatch file space available to store the
+ * path names.
+ */
+
+/*
+ * ftime_start()
+ *	create the file time hash table and open for read/write the scratch
+ *	file. (after created it is unlinked, so when we exit we leave
+ *	no witnesses).
+ * Return:
+ *	0 if the table and file was created ok, -1 otherwise
+ */
+
+#ifdef __STDC__
+int
+ftime_start(void)
+#else
+int
+ftime_start()
+#endif
+{
+	char *pt;
+
+	if (ftab != NULL)
+		return(0);
+ 	if ((ftab = (FTM **)calloc(F_TAB_SZ, sizeof(FTM *))) == NULL) {
+		paxwarn(1, "Cannot allocate memory for file time table");
+		return(-1);
+	}
+
+	/*
+	 * get random name and create temporary scratch file, unlink name
+	 * so it will get removed on exit
+	 */
+	pt = strdup("/tmp/paxXXXXXX");
+	if ((ffd = mkstemp(pt)) < 0) {
+		syswarn(1, errno, "Unable to create temporary file: %s", pt);
+		free(pt);
+		return(-1);
+	}
+	(void)unlink(pt);
+	free(pt);
+
+	return(0);
+}
+
+/*
+ * chk_ftime()
+ *	looks up entry in file time hash table. If not found, the file is
+ *	added to the hash table and the file named stored in the scratch file.
+ *	If a file with the same name is found, the file times are compared and
+ *	the most recent file time is retained. If the new file was younger (or
+ *	was not in the database) the new file is selected for storage.
+ * Return:
+ *	0 if file should be added to the archive, 1 if it should be skipped,
+ *	-1 on error
+ */
+
+#ifdef __STDC__
+int
+chk_ftime(register ARCHD *arcn)
+#else
+int
+chk_ftime(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	register FTM *pt;
+	register int namelen;
+	register u_int indx;
+	char ckname[PAXPATHLEN+1];
+
+	/*
+	 * no info, go ahead and add to archive
+	 */
+	if (ftab == NULL)
+		return(0);
+
+	/*
+	 * hash the pathname and look up in table
+	 */
+	namelen = arcn->nlen;
+	indx = st_hash(arcn->name, namelen, F_TAB_SZ);
+	if ((pt = ftab[indx]) != NULL) {
+		/*
+		 * the hash chain is not empty, walk down looking for match
+		 * only read up the path names if the lengths match, speeds
+		 * up the search a lot
+		 */
+		while (pt != NULL) {
+			if (pt->namelen == namelen) {
+				/*
+				 * potential match, have to read the name
+				 * from the scratch file.
+				 */
+				if (lseek(ffd,pt->seek,SEEK_SET) != pt->seek) {
+					syswarn(1, errno,
+					    "Failed ftime table seek");
+					return(-1);
+				}
+				if (read(ffd, ckname, namelen) != namelen) {
+					syswarn(1, errno,
+					    "Failed ftime table read");
+					return(-1);
+				}
+
+				/*
+				 * if the names match, we are done
+				 */
+				if (!strncmp(ckname, arcn->name, namelen))
+					break;
+			}
+
+			/*
+			 * try the next entry on the chain
+			 */
+			pt = pt->fow;
+		}
+
+		if (pt != NULL) {
+			/*
+			 * found the file, compare the times, save the newer
+			 */
+			if (arcn->sb.st_mtime > pt->mtime) {
+				/*
+				 * file is newer
+				 */
+				pt->mtime = arcn->sb.st_mtime;
+				return(0);
+			}
+			/*
+			 * file is older
+			 */
+			return(1);
+		}
+	}
+
+	/*
+	 * not in table, add it
+	 */
+	if ((pt = (FTM *)malloc(sizeof(FTM))) != NULL) {
+		/*
+		 * add the name at the end of the scratch file, saving the
+		 * offset. add the file to the head of the hash chain
+		 */
+		if ((pt->seek = lseek(ffd, (off_t)0, SEEK_END)) >= 0) {
+			if (write(ffd, arcn->name, namelen) == namelen) {
+				pt->mtime = arcn->sb.st_mtime;
+				pt->namelen = namelen;
+				pt->fow = ftab[indx];
+				ftab[indx] = pt;
+				return(0);
+			}
+			syswarn(1, errno, "Failed write to file time table");
+		} else
+			syswarn(1, errno, "Failed seek on file time table");
+	} else
+		paxwarn(1, "File time table ran out of memory");
+
+	if (pt != NULL)
+		(void)free((char *)pt);
+	return(-1);
+}
+
+/*
+ * Interactive rename table routines
+ *
+ * The interactive rename table keeps track of the new names that the user
+ * assignes to files from tty input. Since this map is unique for each file
+ * we must store it in case there is a reference to the file later in archive
+ * (a link). Otherwise we will be unable to find the file we know was
+ * extracted. The remapping of these files is stored in a memory based hash
+ * table (it is assumed since input must come from /dev/tty, it is unlikely to
+ * be a very large table).
+ */
+
+/*
+ * name_start()
+ *	create the interactive rename table
+ * Return:
+ *	0 if successful, -1 otherwise
+ */
+
+#ifdef __STDC__
+int
+name_start(void)
+#else
+int
+name_start()
+#endif
+{
+	if (ntab != NULL)
+		return(0);
+ 	if ((ntab = (NAMT **)calloc(N_TAB_SZ, sizeof(NAMT *))) == NULL) {
+		paxwarn(1, "Cannot allocate memory for interactive rename table");
+		return(-1);
+	}
+	return(0);
+}
+
+/*
+ * add_name()
+ *	add the new name to old name mapping just created by the user.
+ *	If an old name mapping is found (there may be duplicate names on an
+ *	archive) only the most recent is kept.
+ * Return:
+ *	0 if added, -1 otherwise
+ */
+
+#ifdef __STDC__
+int
+add_name(register char *oname, int onamelen, char *nname)
+#else
+int
+add_name(oname, onamelen, nname)
+	register char *oname;
+	int onamelen;
+	char *nname;
+#endif
+{
+	register NAMT *pt;
+	register u_int indx;
+
+	if (ntab == NULL) {
+		/*
+		 * should never happen
+		 */
+		paxwarn(0, "No interactive rename table, links may fail\n");
+		return(0);
+	}
+
+	/*
+	 * look to see if we have already mapped this file, if so we
+	 * will update it
+	 */
+	indx = st_hash(oname, onamelen, N_TAB_SZ);
+	if ((pt = ntab[indx]) != NULL) {
+		/*
+		 * look down the has chain for the file
+		 */
+		while ((pt != NULL) && (strcmp(oname, pt->oname) != 0))
+			pt = pt->fow;
+
+		if (pt != NULL) {
+			/*
+			 * found an old mapping, replace it with the new one
+			 * the user just input (if it is different)
+			 */
+			if (strcmp(nname, pt->nname) == 0)
+				return(0);
+
+			(void)free((char *)pt->nname);
+			if ((pt->nname = strdup(nname)) == NULL) {
+				paxwarn(1, "Cannot update rename table");
+				return(-1);
+			}
+			return(0);
+		}
+	}
+
+	/*
+	 * this is a new mapping, add it to the table
+	 */
+	if ((pt = (NAMT *)malloc(sizeof(NAMT))) != NULL) {
+		if ((pt->oname = strdup(oname)) != NULL) {
+			if ((pt->nname = strdup(nname)) != NULL) {
+				pt->fow = ntab[indx];
+				ntab[indx] = pt;
+				return(0);
+			}
+			(void)free((char *)pt->oname);
+		}
+		(void)free((char *)pt);
+	}
+	paxwarn(1, "Interactive rename table out of memory");
+	return(-1);
+}
+
+/*
+ * sub_name()
+ *	look up a link name to see if it points at a file that has been
+ *	remapped by the user. If found, the link is adjusted to contain the
+ *	new name (oname is the link to name)
+ */
+
+#ifdef __STDC__
+void
+sub_name(register char *oname, int *onamelen, size_t onamesize)
+#else
+void
+sub_name(oname, onamelen, onamesize)
+	register char *oname;
+	int *onamelen;
+	size_t onamesize;
+#endif
+{
+	register NAMT *pt;
+	register u_int indx;
+
+	if (ntab == NULL)
+		return;
+	/*
+	 * look the name up in the hash table
+	 */
+	indx = st_hash(oname, *onamelen, N_TAB_SZ);
+	if ((pt = ntab[indx]) == NULL)
+		return;
+
+	while (pt != NULL) {
+		/*
+		 * walk down the hash chain looking for a match
+		 */
+		if (strcmp(oname, pt->oname) == 0) {
+			/*
+			 * found it, replace it with the new name
+			 * and return (we know that oname has enough space)
+			 */
+			*onamelen = l_strncpy(oname, pt->nname, onamesize - 1);
+			oname[*onamelen] = '\0';
+			return;
+		}
+		pt = pt->fow;
+	}
+
+	/*
+	 * no match, just return
+	 */
+	return;
+}
+
+/*
+ * device/inode mapping table routines
+ * (used with formats that store device and inodes fields)
+ *
+ * device/inode mapping tables remap the device field in a archive header. The
+ * device/inode fields are used to determine when files are hard links to each
+ * other. However these values have very little meaning outside of that. This
+ * database is used to solve one of two different problems.
+ *
+ * 1) when files are appended to an archive, while the new files may have hard
+ * links to each other, you cannot determine if they have hard links to any
+ * file already stored on the archive from a prior run of pax. We must assume
+ * that these inode/device pairs are unique only within a SINGLE run of pax
+ * (which adds a set of files to an archive). So we have to make sure the
+ * inode/dev pairs we add each time are always unique. We do this by observing
+ * while the inode field is very dense, the use of the dev field is fairly
+ * sparse. Within each run of pax, we remap any device number of a new archive
+ * member that has a device number used in a prior run and already stored in a
+ * file on the archive. During the read phase of the append, we store the
+ * device numbers used and mark them to not be used by any file during the
+ * write phase. If during write we go to use one of those old device numbers,
+ * we remap it to a new value.
+ *
+ * 2) Often the fields in the archive header used to store these values are
+ * too small to store the entire value. The result is an inode or device value
+ * which can be truncated. This really can foul up an archive. With truncation
+ * we end up creating links between files that are really not links (after
+ * truncation the inodes are the same value). We address that by detecting
+ * truncation and forcing a remap of the device field to split truncated
+ * inodes away from each other. Each truncation creates a pattern of bits that
+ * are removed. We use this pattern of truncated bits to partition the inodes
+ * on a single device to many different devices (each one represented by the
+ * truncated bit pattern). All inodes on the same device that have the same
+ * truncation pattern are mapped to the same new device. Two inodes that
+ * truncate to the same value clearly will always have different truncation
+ * bit patterns, so they will be split from away each other. When we spot
+ * device truncation we remap the device number to a non truncated value.
+ * (for more info see table.h for the data structures involved).
+ */
+
+/*
+ * dev_start()
+ *	create the device mapping table
+ * Return:
+ *	0 if successful, -1 otherwise
+ */
+
+#ifdef __STDC__
+int
+dev_start(void)
+#else
+int
+dev_start()
+#endif
+{
+	if (dtab != NULL)
+		return(0);
+ 	if ((dtab = (DEVT **)calloc(D_TAB_SZ, sizeof(DEVT *))) == NULL) {
+		paxwarn(1, "Cannot allocate memory for device mapping table");
+		return(-1);
+	}
+	return(0);
+}
+
+/*
+ * add_dev()
+ *	add a device number to the table. this will force the device to be
+ *	remapped to a new value if it be used during a write phase. This
+ *	function is called during the read phase of an append to prohibit the
+ *	use of any device number already in the archive.
+ * Return:
+ *	0 if added ok, -1 otherwise
+ */
+
+#ifdef __STDC__
+int
+add_dev(register ARCHD *arcn)
+#else
+int
+add_dev(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	if (chk_dev(arcn->sb.st_dev, 1) == NULL)
+		return(-1);
+	return(0);
+}
+
+/*
+ * chk_dev()
+ *	check for a device value in the device table. If not found and the add
+ *	flag is set, it is added. This does NOT assign any mapping values, just
+ *	adds the device number as one that need to be remapped. If this device
+ *	is alread mapped, just return with a pointer to that entry.
+ * Return:
+ *	pointer to the entry for this device in the device map table. Null
+ *	if the add flag is not set and the device is not in the table (it is
+ *	not been seen yet). If add is set and the device cannot be added, null
+ *	is returned (indicates an error).
+ */
+
+#ifdef __STDC__
+static DEVT *
+chk_dev(dev_t dev, int add)
+#else
+static DEVT *
+chk_dev(dev, add)
+	dev_t dev;
+	int add;
+#endif
+{
+	register DEVT *pt;
+	register u_int indx;
+
+	if (dtab == NULL)
+		return(NULL);
+	/*
+	 * look to see if this device is already in the table
+	 */
+	indx = ((unsigned)dev) % D_TAB_SZ;
+	if ((pt = dtab[indx]) != NULL) {
+		while ((pt != NULL) && (pt->dev != dev))
+			pt = pt->fow;
+
+		/*
+		 * found it, return a pointer to it
+		 */
+		if (pt != NULL)
+			return(pt);
+	}
+
+	/*
+	 * not in table, we add it only if told to as this may just be a check
+	 * to see if a device number is being used.
+	 */
+	if (add == 0)
+		return(NULL);
+
+	/*
+	 * allocate a node for this device and add it to the front of the hash
+	 * chain. Note we do not assign remaps values here, so the pt->list
+	 * list must be NULL.
+	 */
+	if ((pt = (DEVT *)malloc(sizeof(DEVT))) == NULL) {
+		paxwarn(1, "Device map table out of memory");
+		return(NULL);
+	}
+	pt->dev = dev;
+	pt->list = NULL;
+	pt->fow = dtab[indx];
+	dtab[indx] = pt;
+	return(pt);
+}
+/*
+ * map_dev()
+ *	given an inode and device storage mask (the mask has a 1 for each bit
+ *	the archive format is able to store in a header), we check for inode
+ *	and device truncation and remap the device as required. Device mapping
+ *	can also occur when during the read phase of append a device number was
+ *	seen (and was marked as do not use during the write phase). WE ASSUME
+ *	that unsigned longs are the same size or bigger than the fields used
+ *	for ino_t and dev_t. If not the types will have to be changed.
+ * Return:
+ *	0 if all ok, -1 otherwise.
+ */
+
+#ifdef __STDC__
+int
+map_dev(register ARCHD *arcn, u_long dev_mask, u_long ino_mask)
+#else
+int
+map_dev(arcn, dev_mask, ino_mask)
+	register ARCHD *arcn;
+	u_long dev_mask;
+	u_long ino_mask;
+#endif
+{
+	register DEVT *pt;
+	register DLIST *dpt;
+	static dev_t lastdev = 0;	/* next device number to try */
+	int trc_ino = 0;
+	int trc_dev = 0;
+	ino_t trunc_bits = 0;
+	ino_t nino;
+
+	if (dtab == NULL)
+		return(0);
+	/*
+	 * check for device and inode truncation, and extract the truncated
+	 * bit pattern.
+	 */
+	if ((arcn->sb.st_dev & (dev_t)dev_mask) != arcn->sb.st_dev)
+		++trc_dev;
+	if ((nino = arcn->sb.st_ino & (ino_t)ino_mask) != arcn->sb.st_ino) {
+		++trc_ino;
+		trunc_bits = arcn->sb.st_ino & (ino_t)(~ino_mask);
+	}
+
+	/*
+	 * see if this device is already being mapped, look up the device
+	 * then find the truncation bit pattern which applies
+	 */
+	if ((pt = chk_dev(arcn->sb.st_dev, 0)) != NULL) {
+		/*
+		 * this device is already marked to be remapped
+		 */
+		for (dpt = pt->list; dpt != NULL; dpt = dpt->fow)
+			if (dpt->trunc_bits == trunc_bits)
+				break;
+
+		if (dpt != NULL) {
+			/*
+			 * we are being remapped for this device and pattern
+			 * change the device number to be stored and return
+			 */
+			arcn->sb.st_dev = dpt->dev;
+			arcn->sb.st_ino = nino;
+			return(0);
+		}
+	} else {
+		/*
+		 * this device is not being remapped YET. if we do not have any
+		 * form of truncation, we do not need a remap
+		 */
+		if (!trc_ino && !trc_dev)
+			return(0);
+
+		/*
+		 * we have truncation, have to add this as a device to remap
+		 */
+		if ((pt = chk_dev(arcn->sb.st_dev, 1)) == NULL)
+			goto bad;
+
+		/*
+		 * if we just have a truncated inode, we have to make sure that
+		 * all future inodes that do not truncate (they have the
+		 * truncation pattern of all 0's) continue to map to the same
+		 * device number. We probably have already written inodes with
+		 * this device number to the archive with the truncation
+		 * pattern of all 0's. So we add the mapping for all 0's to the
+		 * same device number.
+		 */
+		if (!trc_dev && (trunc_bits != 0)) {
+			if ((dpt = (DLIST *)malloc(sizeof(DLIST))) == NULL)
+				goto bad;
+			dpt->trunc_bits = 0;
+			dpt->dev = arcn->sb.st_dev;
+			dpt->fow = pt->list;
+			pt->list = dpt;
+		}
+	}
+
+	/*
+	 * look for a device number not being used. We must watch for wrap
+	 * around on lastdev (so we do not get stuck looking forever!)
+	 */
+	while (++lastdev > 0) {
+		if (chk_dev(lastdev, 0) != NULL)
+			continue;
+		/*
+		 * found an unused value. If we have reached truncation point
+		 * for this format we are hosed, so we give up. Otherwise we
+		 * mark it as being used.
+		 */
+		if (((lastdev & ((dev_t)dev_mask)) != lastdev) ||
+		    (chk_dev(lastdev, 1) == NULL))
+			goto bad;
+		break;
+	}
+
+	if ((lastdev <= 0) || ((dpt = (DLIST *)malloc(sizeof(DLIST))) == NULL))
+		goto bad;
+
+	/*
+	 * got a new device number, store it under this truncation pattern.
+	 * change the device number this file is being stored with.
+	 */
+	dpt->trunc_bits = trunc_bits;
+	dpt->dev = lastdev;
+	dpt->fow = pt->list;
+	pt->list = dpt;
+	arcn->sb.st_dev = lastdev;
+	arcn->sb.st_ino = nino;
+	return(0);
+
+    bad:
+	paxwarn(1, "Unable to fix truncated inode/device field when storing %s",
+	    arcn->name);
+	paxwarn(0, "Archive may create improper hard links when extracted");
+	return(0);
+}
+
+/*
+ * directory access/mod time reset table routines (for directories READ by pax)
+ *
+ * The pax -t flag requires that access times of archive files to be the same
+ * before being read by pax. For regular files, access time is restored after
+ * the file has been copied. This database provides the same functionality for
+ * directories read during file tree traversal. Restoring directory access time
+ * is more complex than files since directories may be read several times until
+ * all the descendants in their subtree are visited by fts. Directory access
+ * and modification times are stored during the fts pre-order visit (done
+ * before any descendants in the subtree is visited) and restored after the
+ * fts post-order visit (after all the descendants have been visited). In the
+ * case of premature exit from a subtree (like from the effects of -n), any
+ * directory entries left in this database are reset during final cleanup
+ * operations of pax. Entries are hashed by inode number for fast lookup.
+ */
+
+/*
+ * atdir_start()
+ *	create the directory access time database for directories READ by pax.
+ * Return:
+ *	0 is created ok, -1 otherwise.
+ */
+
+#ifdef __STDC__
+int
+atdir_start(void)
+#else
+int
+atdir_start()
+#endif
+{
+	if (atab != NULL)
+		return(0);
+ 	if ((atab = (ATDIR **)calloc(A_TAB_SZ, sizeof(ATDIR *))) == NULL) {
+		paxwarn(1,"Cannot allocate space for directory access time table");
+		return(-1);
+	}
+	return(0);
+}
+
+
+/*
+ * atdir_end()
+ *	walk through the directory access time table and reset the access time
+ *	of any directory who still has an entry left in the database. These
+ *	entries are for directories READ by pax
+ */
+
+#ifdef __STDC__
+void
+atdir_end(void)
+#else
+void
+atdir_end()
+#endif
+{
+	register ATDIR *pt;
+	register int i;
+
+	if (atab == NULL)
+		return;
+	/*
+	 * for each non-empty hash table entry reset all the directories
+	 * chained there.
+	 */
+	for (i = 0; i < A_TAB_SZ; ++i) {
+		if ((pt = atab[i]) == NULL)
+			continue;
+		/*
+		 * remember to force the times, set_ftime() looks at pmtime
+		 * and patime, which only applies to things CREATED by pax,
+		 * not read by pax. Read time reset is controlled by -t.
+		 */
+		for (; pt != NULL; pt = pt->fow)
+			set_ftime(pt->name, pt->mtime, pt->atime, 1);
+	}
+}
+
+/*
+ * add_atdir()
+ *	add a directory to the directory access time table. Table is hashed
+ *	and chained by inode number. This is for directories READ by pax
+ */
+
+#ifdef __STDC__
+void
+add_atdir(char *fname, dev_t dev, ino_t ino, time_t mtime, time_t atime)
+#else
+void
+add_atdir(fname, dev, ino, mtime, atime)
+	char *fname;
+	dev_t dev;
+	ino_t ino;
+	time_t mtime;
+	time_t atime;
+#endif
+{
+	register ATDIR *pt;
+	register u_int indx;
+
+	if (atab == NULL)
+		return;
+
+	/*
+	 * make sure this directory is not already in the table, if so just
+	 * return (the older entry always has the correct time). The only
+	 * way this will happen is when the same subtree can be traversed by
+	 * different args to pax and the -n option is aborting fts out of a
+	 * subtree before all the post-order visits have been made).
+	 */
+	indx = ((unsigned)ino) % A_TAB_SZ;
+	if ((pt = atab[indx]) != NULL) {
+		while (pt != NULL) {
+			if ((pt->ino == ino) && (pt->dev == dev))
+				break;
+			pt = pt->fow;
+		}
+
+		/*
+		 * oops, already there. Leave it alone.
+		 */
+		if (pt != NULL)
+			return;
+	}
+
+	/*
+	 * add it to the front of the hash chain
+	 */
+	if ((pt = (ATDIR *)malloc(sizeof(ATDIR))) != NULL) {
+		if ((pt->name = strdup(fname)) != NULL) {
+			pt->dev = dev;
+			pt->ino = ino;
+			pt->mtime = mtime;
+			pt->atime = atime;
+			pt->fow = atab[indx];
+			atab[indx] = pt;
+			return;
+		}
+		(void)free((char *)pt);
+	}
+
+	paxwarn(1, "Directory access time reset table ran out of memory");
+	return;
+}
+
+/*
+ * get_atdir()
+ *	look up a directory by inode and device number to obtain the access
+ *	and modification time you want to set to. If found, the modification
+ *	and access time parameters are set and the entry is removed from the
+ *	table (as it is no longer needed). These are for directories READ by
+ *	pax
+ * Return:
+ *	0 if found, -1 if not found.
+ */
+
+#ifdef __STDC__
+int
+get_atdir(dev_t dev, ino_t ino, time_t *mtime, time_t *atime)
+#else
+int
+get_atdir(dev, ino, mtime, atime)
+	dev_t dev;
+	ino_t ino;
+	time_t *mtime;
+	time_t *atime;
+#endif
+{
+	register ATDIR *pt;
+	register ATDIR **ppt;
+	register u_int indx;
+
+	if (atab == NULL)
+		return(-1);
+	/*
+	 * hash by inode and search the chain for an inode and device match
+	 */
+	indx = ((unsigned)ino) % A_TAB_SZ;
+	if ((pt = atab[indx]) == NULL)
+		return(-1);
+
+	ppt = &(atab[indx]);
+	while (pt != NULL) {
+		if ((pt->ino == ino) && (pt->dev == dev))
+			break;
+		/*
+		 * no match, go to next one
+		 */
+		ppt = &(pt->fow);
+		pt = pt->fow;
+	}
+
+	/*
+	 * return if we did not find it.
+	 */
+	if (pt == NULL)
+		return(-1);
+
+	/*
+	 * found it. return the times and remove the entry from the table.
+	 */
+	*ppt = pt->fow;
+	*mtime = pt->mtime;
+	*atime = pt->atime;
+	(void)free((char *)pt->name);
+	(void)free((char *)pt);
+	return(0);
+}
+
+/*
+ * directory access mode and time storage routines (for directories CREATED
+ * by pax).
+ *
+ * Pax requires that extracted directories, by default, have their access/mod
+ * times and permissions set to the values specified in the archive. During the
+ * actions of extracting (and creating the destination subtree during -rw copy)
+ * directories extracted may be modified after being created. Even worse is
+ * that these directories may have been created with file permissions which
+ * prohibits any descendants of these directories from being extracted. When
+ * directories are created by pax, access rights may be added to permit the
+ * creation of files in their subtree. Every time pax creates a directory, the
+ * times and file permissions specified by the archive are stored. After all
+ * files have been extracted (or copied), these directories have their times
+ * and file modes reset to the stored values. The directory info is restored in
+ * reverse order as entries were added to the data file from root to leaf. To
+ * restore atime properly, we must go backwards. The data file consists of
+ * records with two parts, the file name followed by a DIRDATA trailer. The
+ * fixed sized trailer contains the size of the name plus the off_t location in
+ * the file. To restore we work backwards through the file reading the trailer
+ * then the file name.
+ */
+
+/*
+ * dir_start()
+ *	set up the directory time and file mode storage for directories CREATED
+ *	by pax.
+ * Return:
+ *	0 if ok, -1 otherwise
+ */
+
+#ifdef __STDC__
+int
+dir_start(void)
+#else
+int
+dir_start()
+#endif
+{
+	char *pt;
+
+	if (dirfd != -1)
+		return(0);
+
+	/*
+	 * unlink the file so it goes away at termination by itself
+	 */
+	pt = strdup("/tmp/paxXXXXXX");
+	if ((dirfd = mkstemp(pt)) >= 0) {
+		(void)unlink(pt);
+		free(pt);
+		return(0);
+	}
+	paxwarn(1, "Unable to create temporary file for directory times: %s", pt);
+	free(pt);
+	return(-1);
+}
+
+/*
+ * add_dir()
+ *	add the mode and times for a newly CREATED directory
+ *	name is name of the directory, psb the stat buffer with the data in it,
+ *	frc_mode is a flag that says whether to force the setting of the mode
+ *	(ignoring the user set values for preserving file mode). Frc_mode is
+ *	for the case where we created a file and found that the resulting
+ *	directory was not writeable and the user asked for file modes to NOT
+ *	be preserved. (we have to preserve what was created by default, so we
+ *	have to force the setting at the end. this is stated explicitly in the
+ *	pax spec)
+ */
+
+#ifdef __STDC__
+void
+add_dir(char *name, int nlen, struct stat *psb, int frc_mode)
+#else
+void
+add_dir(name, nlen, psb, frc_mode)
+	char *name;
+	int nlen;
+	struct stat *psb;
+	int frc_mode;
+#endif
+{
+	DIRDATA dblk;
+
+	if (dirfd < 0)
+		return;
+
+	/*
+	 * get current position (where file name will start) so we can store it
+	 * in the trailer
+	 */
+	if ((dblk.npos = lseek(dirfd, 0L, SEEK_CUR)) < 0) {
+		paxwarn(1,"Unable to store mode and times for directory: %s",name);
+		return;
+	}
+
+	/*
+	 * write the file name followed by the trailer
+	 */
+	dblk.nlen = nlen + 1;
+	dblk.mode = psb->st_mode & 0xffff;
+	dblk.mtime = psb->st_mtime;
+	dblk.atime = psb->st_atime;
+	dblk.frc_mode = frc_mode;
+	if ((write(dirfd, name, dblk.nlen) == dblk.nlen) &&
+	    (write(dirfd, (char *)&dblk, sizeof(dblk)) == sizeof(dblk))) {
+		++dircnt;
+		return;
+	}
+
+	paxwarn(1,"Unable to store mode and times for created directory: %s",name);
+	return;
+}
+
+/*
+ * proc_dir()
+ *	process all file modes and times stored for directories CREATED
+ *	by pax
+ */
+
+#ifdef __STDC__
+void
+proc_dir(void)
+#else
+void
+proc_dir()
+#endif
+{
+	char name[PAXPATHLEN+1];
+	DIRDATA dblk;
+	u_long cnt;
+
+	if (dirfd < 0)
+		return;
+	/*
+	 * read backwards through the file and process each directory
+	 */
+	for (cnt = 0; cnt < dircnt; ++cnt) {
+		/*
+		 * read the trailer, then the file name, if this fails
+		 * just give up.
+		 */
+		if (lseek(dirfd, -((off_t)sizeof(dblk)), SEEK_CUR) < 0)
+			break;
+		if (read(dirfd,(char *)&dblk, sizeof(dblk)) != sizeof(dblk))
+			break;
+		if (lseek(dirfd, dblk.npos, SEEK_SET) < 0)
+			break;
+		if (read(dirfd, name, dblk.nlen) != dblk.nlen)
+			break;
+		if (lseek(dirfd, dblk.npos, SEEK_SET) < 0)
+			break;
+
+		/*
+		 * frc_mode set, make sure we set the file modes even if
+		 * the user didn't ask for it (see file_subs.c for more info)
+		 */
+		if (pmode || dblk.frc_mode)
+			set_pmode(name, dblk.mode);
+		if (patime || pmtime)
+			set_ftime(name, dblk.mtime, dblk.atime, 0);
+	}
+
+	(void)close(dirfd);
+	dirfd = -1;
+	if (cnt != dircnt)
+		paxwarn(1,"Unable to set mode and times for created directories");
+	return;
+}
+
+/*
+ * database independent routines
+ */
+
+/*
+ * st_hash()
+ *	hashes filenames to a u_int for hashing into a table. Looks at the tail
+ *	end of file, as this provides far better distribution than any other
+ *	part of the name. For performance reasons we only care about the last
+ *	MAXKEYLEN chars (should be at LEAST large enough to pick off the file
+ *	name). Was tested on 500,000 name file tree traversal from the root
+ *	and gave almost a perfectly uniform distribution of keys when used with
+ *	prime sized tables (MAXKEYLEN was 128 in test). Hashes (sizeof int)
+ *	chars at a time and pads with 0 for last addition.
+ * Return:
+ *	the hash value of the string MOD (%) the table size.
+ */
+
+#ifdef __STDC__
+u_int
+st_hash(char *name, int len, int tabsz)
+#else
+u_int
+st_hash(name, len, tabsz)
+	char *name;
+	int len;
+	int tabsz;
+#endif
+{
+	register char *pt;
+	register char *dest;
+	register char *end;
+	register int i;
+	register u_int key = 0;
+	register int steps;
+	register int res;
+	u_int val;
+
+	/*
+	 * only look at the tail up to MAXKEYLEN, we do not need to waste
+	 * time here (remember these are pathnames, the tail is what will
+	 * spread out the keys)
+	 */
+	if (len > MAXKEYLEN) {
+		pt = &(name[len - MAXKEYLEN]);
+		len = MAXKEYLEN;
+	} else
+		pt = name;
+
+	/*
+	 * calculate the number of u_int size steps in the string and if
+	 * there is a runt to deal with
+	 */
+	steps = len/sizeof(u_int);
+	res = len % sizeof(u_int);
+
+	/*
+	 * add up the value of the string in unsigned integer sized pieces
+	 * too bad we cannot have unsigned int aligned strings, then we
+	 * could avoid the expensive copy.
+	 */
+	for (i = 0; i < steps; ++i) {
+		end = pt + sizeof(u_int);
+		dest = (char *)&val;
+		while (pt < end)
+			*dest++ = *pt++;
+		key += val;
+	}
+
+	/*
+	 * add in the runt padded with zero to the right
+	 */
+	if (res) {
+		val = 0;
+		end = pt + res;
+		dest = (char *)&val;
+		while (pt < end)
+			*dest++ = *pt++;
+		key += val;
+	}
+
+	/*
+	 * return the result mod the table size
+	 */
+	return(key % tabsz);
+}
diff --git a/pax/tables.h b/pax/tables.h
new file mode 100644
index 0000000..1d9c813
--- /dev/null
+++ b/pax/tables.h
@@ -0,0 +1,175 @@
+/*	$OpenBSD: tables.h,v 1.2 1996/06/23 14:20:43 deraadt Exp $	*/
+/*	$NetBSD: tables.h,v 1.3 1995/03/21 09:07:47 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)tables.h	8.1 (Berkeley) 5/31/93
+ */
+
+/*
+ * data structures and constants used by the different databases kept by pax
+ */
+
+/*
+ * Hash Table Sizes MUST BE PRIME, if set too small performance suffers.
+ * Probably safe to expect 500000 inodes per tape. Assuming good key
+ * distribution (inodes) chains of under 50 long (worse case) is ok.
+ */
+#define L_TAB_SZ	2503		/* hard link hash table size */
+#define F_TAB_SZ	50503		/* file time hash table size */
+#define N_TAB_SZ	541		/* interactive rename hash table */
+#define D_TAB_SZ	317		/* unique device mapping table */
+#define A_TAB_SZ	317		/* ftree dir access time reset table */
+#define MAXKEYLEN	64		/* max number of chars for hash */
+
+/*
+ * file hard link structure (hashed by dev/ino and chained) used to find the
+ * hard links in a file system or with some archive formats (cpio)
+ */
+typedef struct hrdlnk {
+	char		*name;	/* name of first file seen with this ino/dev */
+	dev_t		dev;	/* files device number */
+	ino_t		ino;	/* files inode number */
+	u_long		nlink;	/* expected link count */
+	struct hrdlnk	*fow;
+} HRDLNK;
+
+/*
+ * Archive write update file time table (the -u, -C flag), hashed by filename.
+ * Filenames are stored in a scratch file at seek offset into the file. The
+ * file time (mod time) and the file name length (for a quick check) are
+ * stored in a hash table node. We were forced to use a scratch file because
+ * with -u, the mtime for every node in the archive must always be available
+ * to compare against (and this data can get REALLY large with big archives).
+ * By being careful to read only when we have a good chance of a match, the
+ * performance loss is not measurable (and the size of the archive we can
+ * handle is greatly increased).
+ */
+typedef struct ftm {
+	int		namelen;	/* file name length */
+	time_t		mtime;		/* files last modification time */
+	off_t		seek;		/* loacation in scratch file */
+	struct ftm	*fow;
+} FTM;
+
+/*
+ * Interactive rename table (-i flag), hashed by orig filename.
+ * We assume this will not be a large table as this mapping data can only be
+ * obtained through interactive input by the user. Nobody is going to type in
+ * changes for 500000 files? We use chaining to resolve collisions.
+ */
+
+typedef struct namt {
+	char		*oname;		/* old name */
+	char		*nname;		/* new name typed in by the user */
+	struct namt	*fow;
+} NAMT;
+
+/*
+ * Unique device mapping tables. Some protocols (e.g. cpio) require that the
+ * <c_dev,c_ino> pair will uniquely identify a file in an archive unless they
+ * are links to the same file. Appending to archives can break this. For those
+ * protocols that have this requirement we map c_dev to a unique value not seen
+ * in the archive when we append. We also try to handle inode truncation with
+ * this table. (When the inode field in the archive header are too small, we
+ * remap the dev on writes to remove accidental collisions).
+ *
+ * The list is hashed by device number using chain collision resolution. Off of 
+ * each DEVT are linked the various remaps for this device based on those bits
+ * in the inode which were truncated. For example if we are just remapping to
+ * avoid a device number during an update append, off the DEVT we would have
+ * only a single DLIST that has a truncation id of 0 (no inode bits were
+ * stripped for this device so far). When we spot inode truncation we create
+ * a new mapping based on the set of bits in the inode which were stripped off.
+ * so if the top four bits of the inode are stripped and they have a pattern of
+ * 0110...... (where . are those bits not truncated) we would have a mapping
+ * assigned for all inodes that has the same 0110.... pattern (with this dev
+ * number of course). This keeps the mapping sparse and should be able to store
+ * close to the limit of files which can be represented by the optimal
+ * combination of dev and inode bits, and without creating a fouled up archive.
+ * Note we also remap truncated devs in the same way (an exercise for the
+ * dedicated reader; always wanted to say that...:)
+ */
+
+typedef struct devt {
+	dev_t		dev;	/* the orig device number we now have to map */
+	struct devt	*fow;	/* new device map list */
+	struct dlist	*list;	/* map list based on inode truncation bits */
+} DEVT;
+
+typedef struct dlist {
+	ino_t trunc_bits;	/* truncation pattern for a specific map */
+	dev_t dev;		/* the new device id we use */
+	struct dlist *fow;
+} DLIST;
+
+/*
+ * ftree directory access time reset table. When we are done with with a
+ * subtree we reset the access and mod time of the directory when the tflag is
+ * set. Not really explicitly specified in the pax spec, but easy and fast to
+ * do (and this may have even been intended in the spec, it is not clear).
+ * table is hashed by inode with chaining.
+ */
+
+typedef struct atdir {
+	char *name;	/* name of directory to reset */
+	dev_t dev;	/* dev and inode for fast lookup */
+	ino_t ino;
+	time_t mtime;	/* access and mod time to reset to */
+	time_t atime;
+	struct atdir *fow;
+} ATDIR;
+
+/*
+ * created directory time and mode storage entry. After pax is finished during
+ * extraction or copy, we must reset directory access modes and times that
+ * may have been modified after creation (they no longer have the specified
+ * times and/or modes). We must reset time in the reverse order of creation,
+ * because entries are added  from the top of the file tree to the bottom.
+ * We MUST reset times from leaf to root (it will not work the other
+ * direction).  Entries are recorded into a spool file to make reverse
+ * reading faster.
+ */
+
+typedef struct dirdata {
+	int nlen;	/* length of the directory name (includes \0) */
+	off_t npos;	/* position in file where this dir name starts */
+	mode_t mode;	/* file mode to restore */
+	time_t mtime;	/* mtime to set */
+	time_t atime;	/* atime to set */
+	int frc_mode;	/* do we force mode settings? */
+} DIRDATA;
diff --git a/pax/tar.1 b/pax/tar.1
new file mode 100644
index 0000000..9e31fb2
--- /dev/null
+++ b/pax/tar.1
@@ -0,0 +1,239 @@
+.\"
+.\" Copyright (c) 1996 SigmaSoft, Th. Lockert
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"      This product includes software developed by SigmaSoft, Th. Lockert.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\"    derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\"	$OpenBSD: tar.1,v 1.13 1997/05/29 15:47:19 millert Exp $
+.\"
+.Dd June 11, 1996
+.Dt TAR 1
+.Os
+.Sh NAME
+.Nm tar
+.Nd tape archiver
+.Sh SYNOPSIS
+.Nm
+.No [-]{crtux}[befhmopvwzHLPXZ014578]
+.Op Ar archive
+.Op Ar blocksize
+.\" XXX how to do this right?
+.No [-C
+.Ar directory
+.No ]
+.No [-s
+.Ar replstr
+.No ]
+.Ar file1
+.Op Ar file2...
+.Sh DESCRIPTION
+The
+.Nm
+command creates, adds files to, or extracts files from an
+archive file in \*Qtar\*U format.  A tar archive is often
+stored on a magnetic tape, but can be a floppy or a regular
+disk file.
+.Pp
+One of the following flags must be present:
+.Bl -tag -width Ar
+.It Fl c
+Create new archive, or overwrite an existing archive,
+adding the specified files to it.
+.It Fl r
+Append the named new files to existing archive.  Note that
+this will only work on media on which an end-of-file mark
+can be overwritten.
+.It Fl t
+List contents of archive.  If any files are named on the
+command line, only those files will be listed.
+.It Fl u
+Alias for
+.Fl r
+.It Fl x
+Extract files from archive.  If any files are named on the
+command line, only those files will be extracted from the
+archive.  If more than one copy of a file exists in the
+archive, later copies will overwrite earlier copies during
+extration.
+.El
+.Pp
+In addition to the flags mentioned above, any of the following
+flags may be used:
+.Bl -tag -width Ar
+.It Fl b Ar "blocking factor"
+Set blocking factor to use for the archive,
+.Nm
+uses 512 byte blocks.  The default is 20, the maximum is 126.
+Archives with a blocking factor larger 63 violate the
+.Tn POSIX
+standard and will not be portable to all systems.
+.It Fl e
+Stop after first error.
+.It Fl f Ar archive
+Filename where the archive is stored.  Defaults to
+.Pa /dev/rst0
+.It Fl h
+Follow symbolic links as if they were normal files
+or directories.
+.It Fl m
+Do not preserve modification time.
+.It Fl O
+Write old-style (non-POSIX) archives.
+.It Fl o
+Don't write directory information that the older (V7) style
+.Nm
+is unable to decode.
+This implies the
+.Fl O
+flag.
+.It Fl p
+Preserve user id, group id, file mode, access and modification
+times if possible.  The user id and group id will only be set
+if the user is the superuser (unless these values correspond
+to the user's user and group ids).
+.It Fl s Ar replstr
+Modify the file or archive member names specified by the
+.Ar pattern
+or
+.Ar file
+operands according to the substitution expression
+.Ar replstr ,
+using the syntax of the
+.Xr ed 1
+utility regular expressions.
+The format of these regular expressions are:
+.Dl /old/new/[gp]
+As in
+.Xr ed 1 ,
+.Cm old
+is a basic regular expression and
+.Cm new
+can contain an ampersand (&), \\n (where n is a digit) back-references,
+or subexpression matching.
+The
+.Cm old
+string may also contain
+.Dv <newline>
+characters.
+Any non-null character can be used as a delimiter (/ is shown here).
+Multiple
+.Fl s
+expressions can be specified.
+The expressions are applied in the order they are specified on the
+command line, terminating with the first successful substitution.
+The optional trailing
+.Cm g
+continues to apply the substitution expression to the pathname substring
+which starts with the first character following the end of the last successful
+substitution. The first unsuccessful substitution stops the operation of the
+.Cm g
+option.
+The optional trailing
+.Cm p
+will cause the final result of a successful substitution to be written to
+.Dv standard error
+in the following format:
+.Dl <original pathname> >> <new pathname>
+File or archive member names that substitute to the empty string
+are not selected and will be skipped.
+.It Fl v
+Verbose operation mode.
+.It Fl w
+Interactively rename files.  This option causes
+.Nm
+to prompt the user for the filename to use when storing or
+extracting files in an archive.
+.It Fl z
+Compress archive using gzip.
+.It Fl C Ar directory
+This is a positional argument which sets the working directory for the
+following files.  When extracting, files will be extracted into
+the specified directory; when creating, the specified files will be matched
+from the directory.
+.It Fl H
+Follow symlinks given on command line only.
+.It Fl L
+Follow all symlinks.
+.It Fl P
+Do not strip leading slashes (``/'') from pathnames.
+The default is to strip leading slashes.
+.It Fl X
+Do not cross mount points in the file system.
+.It Fl Z
+Compress archive using compress.
+.El
+.Pp
+The options
+.Op Fl 014578
+can be used to select one of the compiled-in backup devices,
+.Pa /dev/rstN .
+.Sh FILES
+.Bl -tag -width "/dev/rst0"
+.It Pa /dev/rst0
+The default archive name
+.El
+.Sh SEE ALSO
+.Xr pax 1 ,
+.Xr cpio 1
+.Sh AUTHOR
+Keith Muller at the University of California, San Diego
+.Sh ERRORS
+.Nm
+will exit with one of the following values:
+.Bl -tag -width 2n
+.It 0
+All files were processed successfully.
+.It 1
+An error occured.
+.El
+.Pp
+Whenever
+.Nm
+cannot create a file or a link when extracting an archive or cannot
+find a file while writing an archive, or cannot preserve the user
+ID, group ID, file mode or access and modification times when the
+.Fl p
+options is specified, a diagnostic message is written to standard
+error and a non-zero exit value will be returned, but processing
+will continue.  In the case where
+.Nm
+cannot create a link to a file,
+.Nm
+will not create a second copy of the file.
+.Pp
+If the extraction of a file from an archive is prematurely terminated
+by a signal or error,
+.Nm
+may have only partially extracted the file the user wanted.
+Additionally, the file modes of extracted files and directories may
+have incorrect file bits, and the modification and access times may
+be wrong.
+.Pp
+If the creation of an archive is prematurely terminated by a signal
+or error,
+.Nm
+may have only partially created the archive which may violate the
+specific archive format specification.
diff --git a/pax/tar.c b/pax/tar.c
new file mode 100644
index 0000000..9044fe5
--- /dev/null
+++ b/pax/tar.c
@@ -0,0 +1,1213 @@
+/*	$OpenBSD: tar.c,v 1.12 1997/09/01 18:30:03 deraadt Exp $	*/
+/*	$NetBSD: tar.c,v 1.5 1995/03/21 09:07:49 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)tar.c	8.2 (Berkeley) 4/18/94";
+#else
+static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: tar.c,v 1.12 1997/09/01 18:30:03 deraadt Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "pax.h"
+#include "extern.h"
+#include "tar.h"
+
+/*
+ * Routines for reading, writing and header identify of various versions of tar
+ */
+
+static u_long tar_chksm __P((register char *, register int));
+static char *name_split __P((register char *, register int));
+static int ul_oct __P((u_long, register char *, register int, int));
+#ifndef NET2_STAT
+static int uqd_oct __P((u_quad_t, register char *, register int, int));
+#endif
+
+/*
+ * Routines common to all versions of tar
+ */
+
+static int tar_nodir;			/* do not write dirs under old tar */
+
+/*
+ * tar_endwr()
+ *	add the tar trailer of two null blocks
+ * Return:
+ *	0 if ok, -1 otherwise (what wr_skip returns)
+ */
+
+#ifdef __STDC__
+int
+tar_endwr(void)
+#else
+int
+tar_endwr()
+#endif
+{
+	return(wr_skip((off_t)(NULLCNT*BLKMULT)));
+}
+
+/*
+ * tar_endrd()
+ *	no cleanup needed here, just return size of trailer (for append)
+ * Return:
+ *	size of trailer (2 * BLKMULT)
+ */
+
+#ifdef __STDC__
+off_t
+tar_endrd(void)
+#else
+off_t
+tar_endrd()
+#endif
+{
+	return((off_t)(NULLCNT*BLKMULT));
+}
+
+/*
+ * tar_trail()
+ *	Called to determine if a header block is a valid trailer. We are passed
+ *	the block, the in_sync flag (which tells us we are in resync mode;
+ *	looking for a valid header), and cnt (which starts at zero) which is
+ *	used to count the number of empty blocks we have seen so far.
+ * Return:
+ *	0 if a valid trailer, -1 if not a valid trailer, or 1 if the block
+ *	could never contain a header.
+ */
+
+#ifdef __STDC__
+int
+tar_trail(register char *buf, register int in_resync, register int *cnt)
+#else
+int
+tar_trail(buf, in_resync, cnt)
+	register char *buf;
+	register int in_resync;
+	register int *cnt;
+#endif
+{
+	register int i;
+
+	/*
+	 * look for all zero, trailer is two consecutive blocks of zero
+	 */
+	for (i = 0; i < BLKMULT; ++i) {
+		if (buf[i] != '\0')
+			break;
+	}
+
+	/*
+	 * if not all zero it is not a trailer, but MIGHT be a header.
+	 */
+	if (i != BLKMULT)
+		return(-1);
+
+	/*
+	 * When given a zero block, we must be careful!
+	 * If we are not in resync mode, check for the trailer. Have to watch
+	 * out that we do not mis-identify file data as the trailer, so we do
+	 * NOT try to id a trailer during resync mode. During resync mode we
+	 * might as well throw this block out since a valid header can NEVER be
+	 * a block of all 0 (we must have a valid file name).
+	 */
+	if (!in_resync && (++*cnt >= NULLCNT))
+		return(0);
+	return(1);
+}
+
+/*
+ * ul_oct()
+ *	convert an unsigned long to an octal string. many oddball field
+ *	termination characters are used by the various versions of tar in the
+ *	different fields. term selects which kind to use. str is '0' padded
+ *	at the front to len. we are unable to use only one format as many old
+ *	tar readers are very cranky about this.
+ * Return:
+ *	0 if the number fit into the string, -1 otherwise
+ */
+
+#ifdef __STDC__
+static int
+ul_oct(u_long val, register char *str, register int len, int term)
+#else
+static int
+ul_oct(val, str, len, term)
+	u_long val;
+	register char *str;
+	register int len;
+	int term;
+#endif
+{
+	register char *pt;
+
+	/*
+	 * term selects the appropriate character(s) for the end of the string
+	 */
+	pt = str + len - 1;
+	switch(term) {
+	case 3:
+		*pt-- = '\0';
+		break;
+	case 2:
+		*pt-- = ' ';
+		*pt-- = '\0';
+		break;
+	case 1:
+		*pt-- = ' ';
+		break;
+	case 0:
+	default:
+		*pt-- = '\0';
+		*pt-- = ' ';
+		break;
+	}
+
+	/*
+	 * convert and blank pad if there is space
+	 */
+	while (pt >= str) {
+		*pt-- = '0' + (char)(val & 0x7);
+		if ((val = val >> 3) == (u_long)0)
+			break;
+	}
+
+	while (pt >= str)
+		*pt-- = '0';
+	if (val != (u_long)0)
+		return(-1);
+	return(0);
+}
+
+#ifndef NET2_STAT
+/*
+ * uqd_oct()
+ *	convert an u_quad_t to an octal string. one of many oddball field
+ *	termination characters are used by the various versions of tar in the
+ *	different fields. term selects which kind to use. str is '0' padded
+ *	at the front to len. we are unable to use only one format as many old
+ *	tar readers are very cranky about this.
+ * Return:
+ *	0 if the number fit into the string, -1 otherwise
+ */
+
+#ifdef __STDC__
+static int
+uqd_oct(u_quad_t val, register char *str, register int len, int term)
+#else
+static int
+uqd_oct(val, str, len, term)
+	u_quad_t val;
+	register char *str;
+	register int len;
+	int term;
+#endif
+{
+	register char *pt;
+
+	/*
+	 * term selects the appropriate character(s) for the end of the string
+	 */
+	pt = str + len - 1;
+	switch(term) {
+	case 3:
+		*pt-- = '\0';
+		break;
+	case 2:
+		*pt-- = ' ';
+		*pt-- = '\0';
+		break;
+	case 1:
+		*pt-- = ' ';
+		break;
+	case 0:
+	default:
+		*pt-- = '\0';
+		*pt-- = ' ';
+		break;
+	}
+
+	/*
+	 * convert and blank pad if there is space
+	 */
+	while (pt >= str) {
+		*pt-- = '0' + (char)(val & 0x7);
+		if ((val = val >> 3) == 0)
+			break;
+	}
+
+	while (pt >= str)
+		*pt-- = '0';
+	if (val != (u_quad_t)0)
+		return(-1);
+	return(0);
+}
+#endif
+
+/*
+ * tar_chksm()
+ *	calculate the checksum for a tar block counting the checksum field as
+ *	all blanks (BLNKSUM is that value pre-calculated, the sume of 8 blanks).
+ *	NOTE: we use len to short circuit summing 0's on write since we ALWAYS
+ *	pad headers with 0.
+ * Return:
+ *	unsigned long checksum
+ */
+
+#ifdef __STDC__
+static u_long
+tar_chksm(register char *blk, register int len)
+#else
+static u_long
+tar_chksm(blk, len)
+	register char *blk;
+	register int len;
+#endif
+{
+	register char *stop;
+	register char *pt;
+	u_long chksm = BLNKSUM;	/* inital value is checksum field sum */
+
+	/*
+	 * add the part of the block before the checksum field
+	 */
+	pt = blk;
+	stop = blk + CHK_OFFSET;
+	while (pt < stop)
+		chksm += (u_long)(*pt++ & 0xff);
+	/*
+	 * move past the checksum field and keep going, spec counts the
+	 * checksum field as the sum of 8 blanks (which is pre-computed as
+	 * BLNKSUM).
+	 * ASSUMED: len is greater than CHK_OFFSET. (len is where our 0 padding
+	 * starts, no point in summing zero's)
+	 */
+	pt += CHK_LEN;
+	stop = blk + len;
+	while (pt < stop)
+		chksm += (u_long)(*pt++ & 0xff);
+	return(chksm);
+}
+
+/*
+ * Routines for old BSD style tar (also made portable to sysV tar)
+ */
+
+/*
+ * tar_id()
+ *	determine if a block given to us is a valid tar header (and not a USTAR
+ *	header). We have to be on the lookout for those pesky blocks of	all
+ *	zero's.
+ * Return:
+ *	0 if a tar header, -1 otherwise
+ */
+
+#ifdef __STDC__
+int
+tar_id(register char *blk, int size)
+#else
+int
+tar_id(blk, size)
+	register char *blk;
+	int size;
+#endif
+{
+	register HD_TAR *hd;
+	register HD_USTAR *uhd;
+
+	if (size < BLKMULT)
+		return(-1);
+	hd = (HD_TAR *)blk;
+	uhd = (HD_USTAR *)blk;
+
+	/*
+	 * check for block of zero's first, a simple and fast test, then make
+	 * sure this is not a ustar header by looking for the ustar magic
+	 * cookie. We should use TMAGLEN, but some USTAR archive programs are
+	 * wrong and create archives missing the \0. Last we check the
+	 * checksum. If this is ok we have to assume it is a valid header.
+	 */
+	if (hd->name[0] == '\0')
+		return(-1);
+	if (strncmp(uhd->magic, TMAGIC, TMAGLEN - 1) == 0)
+		return(-1);
+	if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT))
+		return(-1);
+	return(0);
+}
+
+/*
+ * tar_opt()
+ *	handle tar format specific -o options
+ * Return:
+ *	0 if ok -1 otherwise
+ */
+
+#ifdef __STDC__
+int
+tar_opt(void)
+#else
+int
+tar_opt()
+#endif
+{
+	OPLIST *opt;
+
+	while ((opt = opt_next()) != NULL) {
+		if (strcmp(opt->name, TAR_OPTION) ||
+		    strcmp(opt->value, TAR_NODIR)) {
+			paxwarn(1, "Unknown tar format -o option/value pair %s=%s",
+			    opt->name, opt->value);
+			paxwarn(1,"%s=%s is the only supported tar format option",
+			    TAR_OPTION, TAR_NODIR);
+			return(-1);
+		}
+
+		/*
+		 * we only support one option, and only when writing
+		 */
+		if ((act != APPND) && (act != ARCHIVE)) {
+			paxwarn(1, "%s=%s is only supported when writing.",
+			    opt->name, opt->value);
+			return(-1);
+		}
+		tar_nodir = 1;
+	}
+	return(0);
+}
+
+
+/*
+ * tar_rd()
+ *	extract the values out of block already determined to be a tar header.
+ *	store the values in the ARCHD parameter.
+ * Return:
+ *	0
+ */
+
+#ifdef __STDC__
+int
+tar_rd(register ARCHD *arcn, register char *buf)
+#else
+int
+tar_rd(arcn, buf)
+	register ARCHD *arcn;
+	register char *buf;
+#endif
+{
+	register HD_TAR *hd;
+	register char *pt;
+
+	/*
+	 * we only get proper sized buffers passed to us
+	 */
+	if (tar_id(buf, BLKMULT) < 0)
+		return(-1);
+	arcn->org_name = arcn->name;
+	arcn->sb.st_nlink = 1;
+	arcn->pat = NULL;
+
+	/*
+	 * copy out the name and values in the stat buffer
+	 */
+	hd = (HD_TAR *)buf;
+	arcn->nlen = l_strncpy(arcn->name, hd->name, sizeof(arcn->name) - 1);
+	arcn->name[arcn->nlen] = '\0';
+	arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode,sizeof(hd->mode),OCT) &
+	    0xfff);
+	arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT);
+	arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT);
+	arcn->sb.st_size = (size_t)asc_ul(hd->size, sizeof(hd->size), OCT);
+	arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT);
+	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
+
+	/*
+	 * have to look at the last character, it may be a '/' and that is used
+	 * to encode this as a directory
+	 */
+	pt = &(arcn->name[arcn->nlen - 1]);
+	arcn->pad = 0;
+	arcn->skip = 0;
+	switch(hd->linkflag) {
+	case SYMTYPE:
+		/*
+		 * symbolic link, need to get the link name and set the type in
+		 * the st_mode so -v printing will look correct.
+		 */
+		arcn->type = PAX_SLK;
+		arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname,
+			sizeof(arcn->ln_name) - 1);
+		arcn->ln_name[arcn->ln_nlen] = '\0';
+		arcn->sb.st_mode |= S_IFLNK;
+		break;
+	case LNKTYPE:
+		/*
+		 * hard link, need to get the link name, set the type in the
+		 * st_mode and st_nlink so -v printing will look better.
+		 */
+		arcn->type = PAX_HLK;
+		arcn->sb.st_nlink = 2;
+		arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname,
+			sizeof(arcn->ln_name) - 1);
+		arcn->ln_name[arcn->ln_nlen] = '\0';
+
+		/*
+		 * no idea of what type this thing really points at, but
+		 * we set something for printing only.
+		 */
+		arcn->sb.st_mode |= S_IFREG;
+		break;
+	case DIRTYPE:
+		/*
+		 * It is a directory, set the mode for -v printing
+		 */
+		arcn->type = PAX_DIR;
+		arcn->sb.st_mode |= S_IFDIR;
+		arcn->sb.st_nlink = 2;
+		arcn->ln_name[0] = '\0';
+		arcn->ln_nlen = 0;
+		break;
+	case AREGTYPE:
+	case REGTYPE:
+	default:
+		/*
+		 * If we have a trailing / this is a directory and NOT a file.
+		 */
+		arcn->ln_name[0] = '\0';
+		arcn->ln_nlen = 0;
+		if (*pt == '/') {
+			/*
+			 * it is a directory, set the mode for -v printing
+			 */
+			arcn->type = PAX_DIR;
+			arcn->sb.st_mode |= S_IFDIR;
+			arcn->sb.st_nlink = 2;
+		} else {
+			/*
+			 * have a file that will be followed by data. Set the
+			 * skip value to the size field and caluculate the size
+			 * of the padding.
+			 */
+			arcn->type = PAX_REG;
+			arcn->sb.st_mode |= S_IFREG;
+			arcn->pad = TAR_PAD(arcn->sb.st_size);
+			arcn->skip = arcn->sb.st_size;
+		}
+		break;
+	}
+
+	/*
+	 * strip off any trailing slash.
+	 */
+	if (*pt == '/') {
+		*pt = '\0'; 
+		--arcn->nlen;
+	}
+	return(0);
+}
+
+/*
+ * tar_wr()
+ *	write a tar header for the file specified in the ARCHD to the archive.
+ *	Have to check for file types that cannot be stored and file names that
+ *	are too long. Be careful of the term (last arg) to ul_oct, each field
+ *	of tar has it own spec for the termination character(s).
+ *	ASSUMED: space after header in header block is zero filled
+ * Return:
+ *	0 if file has data to be written after the header, 1 if file has NO
+ *	data to write after the header, -1 if archive write failed
+ */
+
+#ifdef __STDC__
+int
+tar_wr(register ARCHD *arcn)
+#else
+int
+tar_wr(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	register HD_TAR *hd;
+	int len;
+	char hdblk[sizeof(HD_TAR)];
+
+	/*
+	 * check for those file system types which tar cannot store
+	 */
+	switch(arcn->type) {
+	case PAX_DIR:
+		/*
+		 * user asked that dirs not be written to the archive
+		 */
+		if (tar_nodir)
+			return(1);
+		break;
+	case PAX_CHR:
+		paxwarn(1, "Tar cannot archive a character device %s",
+		    arcn->org_name);
+		return(1);
+	case PAX_BLK:
+		paxwarn(1, "Tar cannot archive a block device %s", arcn->org_name);
+		return(1);
+	case PAX_SCK:
+		paxwarn(1, "Tar cannot archive a socket %s", arcn->org_name);
+		return(1);
+	case PAX_FIF:
+		paxwarn(1, "Tar cannot archive a fifo %s", arcn->org_name);
+		return(1);
+	case PAX_SLK:
+	case PAX_HLK:
+	case PAX_HRG:
+		if (arcn->ln_nlen > sizeof(hd->linkname)) {
+			paxwarn(1,"Link name too long for tar %s", arcn->ln_name);
+			return(1);
+		}
+		break;
+	case PAX_REG:
+	case PAX_CTG:
+	default:
+		break;
+	}
+
+	/*
+	 * check file name len, remember extra char for dirs (the / at the end)
+	 */
+	len = arcn->nlen;
+	if (arcn->type == PAX_DIR)
+		++len;
+	if (len >= sizeof(hd->name)) {
+		paxwarn(1, "File name too long for tar %s", arcn->name);
+		return(1);
+	}
+
+	/*
+	 * copy the data out of the ARCHD into the tar header based on the type
+	 * of the file. Remember many tar readers want the unused fields to be
+	 * padded with zero. We set the linkflag field (type), the linkname
+	 * (or zero if not used),the size, and set the padding (if any) to be
+	 * added after the file data (0 for all other types, as they only have
+	 * a header)
+	 */
+	hd = (HD_TAR *)hdblk;
+	l_strncpy(hd->name, arcn->name, sizeof(hd->name) - 1);
+	hd->name[sizeof(hd->name) - 1] = '\0';
+	arcn->pad = 0;
+
+	if (arcn->type == PAX_DIR) {
+		/*
+		 * directories are the same as files, except have a filename
+		 * that ends with a /, we add the slash here. No data follows,
+		 * dirs, so no pad.
+		 */
+		hd->linkflag = AREGTYPE;
+		memset(hd->linkname, 0, sizeof(hd->linkname));
+		hd->name[len-1] = '/';
+		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1))
+			goto out;
+	} else if (arcn->type == PAX_SLK) {
+		/*
+		 * no data follows this file, so no pad
+		 */
+		hd->linkflag = SYMTYPE;
+		l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1);
+		hd->linkname[sizeof(hd->linkname) - 1] = '\0';
+		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1))
+			goto out;
+	} else if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) {
+		/*
+		 * no data follows this file, so no pad
+		 */
+		hd->linkflag = LNKTYPE;
+		l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1);
+		hd->linkname[sizeof(hd->linkname) - 1] = '\0';
+		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1))
+			goto out;
+	} else {
+		/*
+		 * data follows this file, so set the pad
+		 */
+		hd->linkflag = AREGTYPE;
+		memset(hd->linkname, 0, sizeof(hd->linkname));
+#		ifdef NET2_STAT
+		if (ul_oct((u_long)arcn->sb.st_size, hd->size,
+		    sizeof(hd->size), 1)) {
+#		else
+		if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size,
+		    sizeof(hd->size), 1)) {
+#		endif
+			paxwarn(1,"File is too large for tar %s", arcn->org_name);
+			return(1);
+		}
+		arcn->pad = TAR_PAD(arcn->sb.st_size);
+	}
+
+	/*
+	 * copy those fields that are independent of the type
+	 */
+	if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 0) ||
+	    ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 0) ||
+	    ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 0) ||
+	    ul_oct((u_long)arcn->sb.st_mtime, hd->mtime, sizeof(hd->mtime), 1))
+		goto out;
+
+	/*
+	 * calculate and add the checksum, then write the header. A return of
+	 * 0 tells the caller to now write the file data, 1 says no data needs
+	 * to be written
+	 */
+	if (ul_oct(tar_chksm(hdblk, sizeof(HD_TAR)), hd->chksum,
+	    sizeof(hd->chksum), 3))
+		goto out;
+	if (wr_rdbuf(hdblk, sizeof(HD_TAR)) < 0)
+		return(-1);
+	if (wr_skip((off_t)(BLKMULT - sizeof(HD_TAR))) < 0)
+		return(-1);
+	if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG))
+		return(0);
+	return(1);
+
+    out:
+	/*
+	 * header field is out of range
+	 */
+	paxwarn(1, "Tar header field is too small for %s", arcn->org_name);
+	return(1);
+}
+
+/*
+ * Routines for POSIX ustar
+ */
+
+/*
+ * ustar_strd()
+ *	initialization for ustar read
+ * Return:
+ *	0 if ok, -1 otherwise
+ */
+
+#ifdef __STDC__
+int
+ustar_strd(void)
+#else
+int
+ustar_strd()
+#endif
+{
+	if ((usrtb_start() < 0) || (grptb_start() < 0))
+		return(-1);
+	return(0);
+}
+
+/*
+ * ustar_stwr()
+ *	initialization for ustar write
+ * Return:
+ *	0 if ok, -1 otherwise
+ */
+
+#ifdef __STDC__
+int
+ustar_stwr(void)
+#else
+int
+ustar_stwr()
+#endif
+{
+	if ((uidtb_start() < 0) || (gidtb_start() < 0))
+		return(-1);
+	return(0);
+}
+
+/*
+ * ustar_id()
+ *	determine if a block given to us is a valid ustar header. We have to
+ *	be on the lookout for those pesky blocks of all zero's
+ * Return:
+ *	0 if a ustar header, -1 otherwise
+ */
+
+#ifdef __STDC__
+int
+ustar_id(char *blk, int size)
+#else
+int
+ustar_id(blk, size)
+	char *blk;
+	int size;
+#endif
+{
+	register HD_USTAR *hd;
+
+	if (size < BLKMULT)
+		return(-1);
+	hd = (HD_USTAR *)blk;
+
+	/*
+	 * check for block of zero's first, a simple and fast test then check
+	 * ustar magic cookie. We should use TMAGLEN, but some USTAR archive
+	 * programs are fouled up and create archives missing the \0. Last we
+	 * check the checksum. If ok we have to assume it is a valid header.
+	 */
+	if (hd->name[0] == '\0')
+		return(-1);
+	if (strncmp(hd->magic, TMAGIC, TMAGLEN - 1) != 0)
+		return(-1);
+	if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT))
+		return(-1);
+	return(0);
+}
+
+/*
+ * ustar_rd()
+ *	extract the values out of block already determined to be a ustar header.
+ *	store the values in the ARCHD parameter.
+ * Return:
+ *	0
+ */
+
+#ifdef __STDC__
+int
+ustar_rd(register ARCHD *arcn, register char *buf)
+#else
+int
+ustar_rd(arcn, buf)
+	register ARCHD *arcn;
+	register char *buf;
+#endif
+{
+	register HD_USTAR *hd;
+	register char *dest;
+	register int cnt = 0;
+	dev_t devmajor;
+	dev_t devminor;
+
+	/*
+	 * we only get proper sized buffers
+	 */
+	if (ustar_id(buf, BLKMULT) < 0)
+		return(-1);
+	arcn->org_name = arcn->name;
+	arcn->sb.st_nlink = 1;
+	arcn->pat = NULL;
+	arcn->nlen = 0;
+	hd = (HD_USTAR *)buf;
+
+	/*
+	 * see if the filename is split into two parts. if, so joint the parts.
+	 * we copy the prefix first and add a / between the prefix and name.
+	 */
+	dest = arcn->name;
+	if (*(hd->prefix) != '\0') {
+		cnt = l_strncpy(dest, hd->prefix, sizeof(arcn->name) - 2);
+		dest += cnt;
+		*dest++ = '/';
+		cnt++;
+	}
+	arcn->nlen = cnt + l_strncpy(dest, hd->name, sizeof(arcn->name) - cnt);
+	arcn->name[arcn->nlen] = '\0';
+
+	/*
+	 * follow the spec to the letter. we should only have mode bits, strip
+	 * off all other crud we may be passed.
+	 */
+	arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode, sizeof(hd->mode), OCT) &
+	    0xfff);
+	arcn->sb.st_size = (size_t)asc_ul(hd->size, sizeof(hd->size), OCT);
+	arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT);
+	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
+
+	/*
+	 * If we can find the ascii names for gname and uname in the password
+	 * and group files we will use the uid's and gid they bind. Otherwise
+	 * we use the uid and gid values stored in the header. (This is what
+	 * the posix spec wants).
+	 */
+	hd->gname[sizeof(hd->gname) - 1] = '\0';
+	if (gid_name(hd->gname, &(arcn->sb.st_gid)) < 0)
+		arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT);
+	hd->uname[sizeof(hd->uname) - 1] = '\0';
+	if (uid_name(hd->uname, &(arcn->sb.st_uid)) < 0)
+		arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT);
+
+	/*
+	 * set the defaults, these may be changed depending on the file type
+	 */
+	arcn->ln_name[0] = '\0';
+	arcn->ln_nlen = 0;
+	arcn->pad = 0;
+	arcn->skip = 0;
+	arcn->sb.st_rdev = (dev_t)0;
+
+	/*
+	 * set the mode and PAX type according to the typeflag in the header
+	 */
+	switch(hd->typeflag) {
+	case FIFOTYPE:
+		arcn->type = PAX_FIF;
+		arcn->sb.st_mode |= S_IFIFO;
+		break;
+	case DIRTYPE:
+		arcn->type = PAX_DIR;
+		arcn->sb.st_mode |= S_IFDIR;
+		arcn->sb.st_nlink = 2;
+
+		/*
+		 * Some programs that create ustar archives append a '/'
+		 * to the pathname for directories. This clearly violates
+		 * ustar specs, but we will silently strip it off anyway.
+		 */
+		if (arcn->name[arcn->nlen - 1] == '/')
+			arcn->name[--arcn->nlen] = '\0';
+		break;
+	case BLKTYPE:
+	case CHRTYPE:
+		/*
+		 * this type requires the rdev field to be set.
+		 */
+		if (hd->typeflag == BLKTYPE) {
+			arcn->type = PAX_BLK;
+			arcn->sb.st_mode |= S_IFBLK;
+		} else {
+			arcn->type = PAX_CHR;
+			arcn->sb.st_mode |= S_IFCHR;
+		}
+		devmajor = (dev_t)asc_ul(hd->devmajor,sizeof(hd->devmajor),OCT);
+		devminor = (dev_t)asc_ul(hd->devminor,sizeof(hd->devminor),OCT);
+		arcn->sb.st_rdev = TODEV(devmajor, devminor);
+		break;
+	case SYMTYPE:
+	case LNKTYPE:
+		if (hd->typeflag == SYMTYPE) {
+			arcn->type = PAX_SLK;
+			arcn->sb.st_mode |= S_IFLNK;
+		} else {
+			arcn->type = PAX_HLK;
+			/*
+			 * so printing looks better
+			 */
+			arcn->sb.st_mode |= S_IFREG;
+			arcn->sb.st_nlink = 2;
+		}
+		/*
+		 * copy the link name
+		 */
+		arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname,
+			sizeof(arcn->ln_name) - 1);
+		arcn->ln_name[arcn->ln_nlen] = '\0';
+		break;
+	case CONTTYPE:
+	case AREGTYPE:
+	case REGTYPE:
+	default:
+		/*
+		 * these types have file data that follows. Set the skip and
+		 * pad fields.
+		 */
+		arcn->type = PAX_REG;
+		arcn->pad = TAR_PAD(arcn->sb.st_size);
+		arcn->skip = arcn->sb.st_size;
+		arcn->sb.st_mode |= S_IFREG;
+		break;
+	}
+	return(0);
+}
+
+/*
+ * ustar_wr()
+ *	write a ustar header for the file specified in the ARCHD to the archive
+ *	Have to check for file types that cannot be stored and file names that
+ *	are too long. Be careful of the term (last arg) to ul_oct, we only use
+ *	'\0' for the termination character (this is different than picky tar)
+ *	ASSUMED: space after header in header block is zero filled
+ * Return:
+ *	0 if file has data to be written after the header, 1 if file has NO
+ *	data to write after the header, -1 if archive write failed
+ */
+
+#ifdef __STDC__
+int
+ustar_wr(register ARCHD *arcn)
+#else
+int
+ustar_wr(arcn)
+	register ARCHD *arcn;
+#endif
+{
+	register HD_USTAR *hd;
+	register char *pt;
+	char hdblk[sizeof(HD_USTAR)];
+
+	/*
+	 * check for those file system types ustar cannot store
+	 */
+	if (arcn->type == PAX_SCK) {
+		paxwarn(1, "Ustar cannot archive a socket %s", arcn->org_name);
+		return(1);
+	}
+
+	/*
+	 * check the length of the linkname
+	 */
+	if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) ||
+	    (arcn->type == PAX_HRG)) && (arcn->ln_nlen >= sizeof(hd->linkname))){
+		paxwarn(1, "Link name too long for ustar %s", arcn->ln_name);
+		return(1);
+	}
+
+	/*
+	 * split the path name into prefix and name fields (if needed). if
+	 * pt != arcn->name, the name has to be split
+	 */
+	if ((pt = name_split(arcn->name, arcn->nlen)) == NULL) {
+		paxwarn(1, "File name too long for ustar %s", arcn->name);
+		return(1);
+	}
+	hd = (HD_USTAR *)hdblk;
+	arcn->pad = 0L;
+
+	/*
+	 * split the name, or zero out the prefix
+	 */
+	if (pt != arcn->name) {
+		/*
+		 * name was split, pt points at the / where the split is to
+		 * occur, we remove the / and copy the first part to the prefix
+		 */
+		*pt = '\0';
+		l_strncpy(hd->prefix, arcn->name, sizeof(hd->prefix) - 1);
+		*pt++ = '/';
+	} else
+		memset(hd->prefix, 0, sizeof(hd->prefix));
+
+	/*
+	 * copy the name part. this may be the whole path or the part after
+	 * the prefix
+	 */
+	l_strncpy(hd->name, pt, sizeof(hd->name) - 1);
+	hd->name[sizeof(hd->name) - 1] = '\0';
+
+	/*
+	 * set the fields in the header that are type dependent
+	 */
+	switch(arcn->type) {
+	case PAX_DIR:
+		hd->typeflag = DIRTYPE;
+		memset(hd->linkname, 0, sizeof(hd->linkname));
+		memset(hd->devmajor, 0, sizeof(hd->devmajor));
+		memset(hd->devminor, 0, sizeof(hd->devminor));
+		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))
+			goto out;
+		break;
+	case PAX_CHR:
+	case PAX_BLK:
+		if (arcn->type == PAX_CHR)
+			hd->typeflag = CHRTYPE;
+		else
+			hd->typeflag = BLKTYPE;
+		memset(hd->linkname, 0, sizeof(hd->linkname));
+		if (ul_oct((u_long)MAJOR(arcn->sb.st_rdev), hd->devmajor,
+		   sizeof(hd->devmajor), 3) ||
+		   ul_oct((u_long)MINOR(arcn->sb.st_rdev), hd->devminor,
+		   sizeof(hd->devminor), 3) ||
+		   ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))
+			goto out;
+		break;
+	case PAX_FIF:
+		hd->typeflag = FIFOTYPE;
+		memset(hd->linkname, 0, sizeof(hd->linkname));
+		memset(hd->devmajor, 0, sizeof(hd->devmajor));
+		memset(hd->devminor, 0, sizeof(hd->devminor));
+		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))
+			goto out;
+		break;
+	case PAX_SLK:
+	case PAX_HLK:
+	case PAX_HRG:
+		if (arcn->type == PAX_SLK)
+			hd->typeflag = SYMTYPE;
+		else
+			hd->typeflag = LNKTYPE;
+		l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1);
+		hd->linkname[sizeof(hd->linkname) - 1] = '\0';
+		memset(hd->devmajor, 0, sizeof(hd->devmajor));
+		memset(hd->devminor, 0, sizeof(hd->devminor));
+		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))
+			goto out;
+		break;
+	case PAX_REG:
+	case PAX_CTG:
+	default:
+		/*
+		 * file data with this type, set the padding
+		 */
+		if (arcn->type == PAX_CTG)
+			hd->typeflag = CONTTYPE;
+		else
+			hd->typeflag = REGTYPE;
+		memset(hd->linkname, 0, sizeof(hd->linkname));
+		memset(hd->devmajor, 0, sizeof(hd->devmajor));
+		memset(hd->devminor, 0, sizeof(hd->devminor));
+		arcn->pad = TAR_PAD(arcn->sb.st_size);
+#		ifdef NET2_STAT
+		if (ul_oct((u_long)arcn->sb.st_size, hd->size,
+		    sizeof(hd->size), 3)) {
+#		else
+		if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size,
+		    sizeof(hd->size), 3)) {
+#		endif
+			paxwarn(1,"File is too long for ustar %s",arcn->org_name);
+			return(1);
+		}
+		break;
+	}
+
+	l_strncpy(hd->magic, TMAGIC, TMAGLEN);
+	l_strncpy(hd->version, TVERSION, TVERSLEN);
+
+	/*
+	 * set the remaining fields. Some versions want all 16 bits of mode
+	 * we better humor them (they really do not meet spec though)....
+	 */
+	if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 3) ||
+	    ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 3)  ||
+	    ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 3) ||
+	    ul_oct((u_long)arcn->sb.st_mtime,hd->mtime,sizeof(hd->mtime),3))
+		goto out;
+	l_strncpy(hd->uname,name_uid(arcn->sb.st_uid, 0),sizeof(hd->uname));
+	l_strncpy(hd->gname,name_gid(arcn->sb.st_gid, 0),sizeof(hd->gname));
+
+	/*
+	 * calculate and store the checksum write the header to the archive
+	 * return 0 tells the caller to now write the file data, 1 says no data
+	 * needs to be written
+	 */
+	if (ul_oct(tar_chksm(hdblk, sizeof(HD_USTAR)), hd->chksum,
+	   sizeof(hd->chksum), 3))
+		goto out;
+	if (wr_rdbuf(hdblk, sizeof(HD_USTAR)) < 0)
+		return(-1);
+	if (wr_skip((off_t)(BLKMULT - sizeof(HD_USTAR))) < 0)
+		return(-1);
+	if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG))
+		return(0);
+	return(1);
+
+    out:
+    	/*
+	 * header field is out of range
+	 */
+	paxwarn(1, "Ustar header field is too small for %s", arcn->org_name);
+	return(1);
+}
+
+/*
+ * name_split()
+ *	see if the name has to be split for storage in a ustar header. We try
+ *	to fit the entire name in the name field without splitting if we can.
+ *	The split point is always at a /
+ * Return
+ *	character pointer to split point (always the / that is to be removed
+ *	if the split is not needed, the points is set to the start of the file
+ *	name (it would violate the spec to split there). A NULL is returned if
+ *	the file name is too long
+ */
+
+#ifdef __STDC__
+static char *
+name_split(register char *name, register int len)
+#else
+static char *
+name_split(name, len)
+	register char *name;
+	register int len;
+#endif
+{
+	register char *start;
+
+	/*
+	 * check to see if the file name is small enough to fit in the name
+	 * field. if so just return a pointer to the name.
+	 */
+	if (len < TNMSZ)
+		return(name);
+	if (len > (TPFSZ + TNMSZ))
+		return(NULL);
+
+	/*
+	 * we start looking at the biggest sized piece that fits in the name
+	 * field. We walk foward looking for a slash to split at. The idea is
+	 * to find the biggest piece to fit in the name field (or the smallest
+	 * prefix we can find)
+	 */
+	start = name + len - TNMSZ;
+	while ((*start != '\0') && (*start != '/'))
+		++start;
+
+	/*
+	 * if we hit the end of the string, this name cannot be split, so we
+	 * cannot store this file.
+	 */
+	if (*start == '\0')
+		return(NULL);
+	len = start - name;
+
+	/*
+	 * NOTE: /str where the length of str == TNMSZ can not be stored under
+	 * the p1003.1-1990 spec for ustar. We could force a prefix of / and
+	 * the file would then expand on extract to //str. The len == 0 below
+	 * makes this special case follow the spec to the letter.
+	 */
+	if ((len >= TPFSZ) || (len == 0))
+		return(NULL);
+
+	/*
+	 * ok have a split point, return it to the caller
+	 */
+	return(start);
+}
diff --git a/pax/tar.h b/pax/tar.h
new file mode 100644
index 0000000..79a8ce4
--- /dev/null
+++ b/pax/tar.h
@@ -0,0 +1,151 @@
+/*	$OpenBSD: tar.h,v 1.5 1997/04/16 03:50:25 millert Exp $	*/
+/*	$NetBSD: tar.h,v 1.3 1995/03/21 09:07:51 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)tar.h	8.2 (Berkeley) 4/18/94
+ */
+
+/*
+ * defines and data structures common to all tar formats
+ */
+#define CHK_LEN		8		/* length of checksum field */
+#define TNMSZ		100		/* size of name field */
+#ifdef _PAX_
+#define NULLCNT		2		/* number of null blocks in trailer */
+#define CHK_OFFSET	148		/* start of chksum field */
+#define BLNKSUM		256L		/* sum of checksum field using ' ' */
+#endif /* _PAX_ */
+
+/*
+ * Values used in typeflag field in all tar formats
+ * (only REGTYPE, LNKTYPE and SYMTYPE are used in old bsd tar headers)
+ */
+#define	REGTYPE		'0'		/* Regular File */
+#define	AREGTYPE	'\0'		/* Regular File */
+#define	LNKTYPE		'1'		/* Link */
+#define	SYMTYPE		'2'		/* Symlink */
+#define	CHRTYPE		'3'		/* Character Special File */
+#define	BLKTYPE		'4'		/* Block Special File */
+#define	DIRTYPE		'5'		/* Directory */
+#define	FIFOTYPE	'6'		/* FIFO */
+#define	CONTTYPE	'7'		/* high perf file */
+
+/*
+ * Mode field encoding of the different file types - values in octal
+ */
+#define TSUID		04000		/* Set UID on execution */
+#define TSGID		02000		/* Set GID on execution */
+#define TSVTX		01000		/* Reserved */
+#define TUREAD		00400		/* Read by owner */
+#define TUWRITE		00200		/* Write by owner */
+#define TUEXEC		00100		/* Execute/Search by owner */
+#define TGREAD		00040		/* Read by group */
+#define TGWRITE		00020		/* Write by group */
+#define TGEXEC		00010		/* Execute/Search by group */
+#define TOREAD		00004		/* Read by other */
+#define TOWRITE		00002		/* Write by other */
+#define TOEXEC		00001		/* Execute/Search by other */
+
+#ifdef _PAX_
+/*
+ * Pad with a bit mask, much faster than doing a mod but only works on powers
+ * of 2. Macro below is for block of 512 bytes.
+ */
+#define TAR_PAD(x)	((512 - ((x) & 511)) & 511)
+#endif /* _PAX_ */
+
+/*
+ * structure of an old tar header as it appeared in BSD releases
+ */
+typedef struct {
+	char name[TNMSZ];		/* name of entry */
+	char mode[8]; 			/* mode */
+	char uid[8]; 			/* uid */
+	char gid[8];			/* gid */
+	char size[12];			/* size */
+	char mtime[12];			/* modification time */
+	char chksum[CHK_LEN];		/* checksum */
+	char linkflag;			/* norm, hard, or sym. */
+	char linkname[TNMSZ];		/* linked to name */
+} HD_TAR;
+
+#ifdef _PAX_
+/*
+ * -o options for BSD tar to not write directories to the archive
+ */
+#define TAR_NODIR	"nodir"
+#define TAR_OPTION	"write_opt"
+
+/*
+ * default device names
+ */
+#define	DEV_0		"/dev/rst0"
+#define	DEV_1		"/dev/rst1"
+#define	DEV_4		"/dev/rst4"
+#define	DEV_5		"/dev/rst5"
+#define	DEV_7		"/dev/rst7"
+#define	DEV_8		"/dev/rst8"
+#endif /* _PAX_ */
+
+/*
+ * Data Interchange Format - Extended tar header format - POSIX 1003.1-1990
+ */
+#define TPFSZ		155
+#define	TMAGIC		"ustar"		/* ustar and a null */
+#define	TMAGLEN		6
+#define	TVERSION	"00"		/* 00 and no null */
+#define	TVERSLEN	2
+
+typedef struct {
+	char name[TNMSZ];		/* name of entry */
+	char mode[8]; 			/* mode */
+	char uid[8]; 			/* uid */
+	char gid[8];			/* gid */
+	char size[12];			/* size */
+	char mtime[12];			/* modification time */
+	char chksum[CHK_LEN];		/* checksum */
+	char typeflag;			/* type of file. */
+	char linkname[TNMSZ];		/* linked to name */
+	char magic[TMAGLEN];		/* magic cookie */
+	char version[TVERSLEN];		/* version */
+	char uname[32];			/* ascii owner name */
+	char gname[32];			/* ascii group name */
+	char devmajor[8];		/* major device number */
+	char devminor[8];		/* minor device number */
+	char prefix[TPFSZ];		/* linked to name */
+} HD_USTAR;
diff --git a/pax/tty_subs.c b/pax/tty_subs.c
new file mode 100644
index 0000000..61f4e78
--- /dev/null
+++ b/pax/tty_subs.c
@@ -0,0 +1,251 @@
+/*	$OpenBSD: tty_subs.c,v 1.5 1997/07/25 18:58:39 mickey Exp $	*/
+/*	$NetBSD: tty_subs.c,v 1.5 1995/03/21 09:07:52 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)tty_subs.c	8.2 (Berkeley) 4/18/94";
+#else
+static char rcsid[] __attribute__((__unused__))  = "$OpenBSD: tty_subs.c,v 1.5 1997/07/25 18:58:39 mickey Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include "pax.h"
+#include "extern.h"
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+/*
+ * routines that deal with I/O to and from the user
+ */
+
+#define DEVTTY		"/dev/tty"	/* device for interactive i/o */
+static FILE *ttyoutf = NULL;		/* output pointing at control tty */
+static FILE *ttyinf = NULL;		/* input pointing at control tty */
+
+/*
+ * tty_init()
+ *	try to open the controlling termina (if any) for this process. if the
+ *	open fails, future ops that require user input will get an EOF
+ */
+
+#ifdef __STDC__
+int
+tty_init(void)
+#else
+int
+tty_init()
+#endif
+{
+	int ttyfd;
+
+	if ((ttyfd = open(DEVTTY, O_RDWR)) >= 0) {
+		if ((ttyoutf = fdopen(ttyfd, "w")) != NULL) {
+			if ((ttyinf = fdopen(ttyfd, "r")) != NULL)
+				return(0);
+			(void)fclose(ttyoutf);
+		}
+		(void)close(ttyfd);
+	}
+
+	if (iflag) {
+		paxwarn(1, "Fatal error, cannot open %s", DEVTTY);
+		return(-1);
+	}
+	return(0);
+}
+
+/*
+ * tty_prnt()
+ *	print a message using the specified format to the controlling tty
+ *	if there is no controlling terminal, just return.
+ */
+
+#ifdef __STDC__
+void
+tty_prnt(char *fmt, ...)
+#else
+void
+tty_prnt(fmt, va_alist)
+	char *fmt;
+	va_dcl
+#endif
+{
+	va_list ap;
+#	ifdef __STDC__
+	va_start(ap, fmt);
+#	else
+	va_start(ap);
+#	endif
+	if (ttyoutf == NULL)
+		return;
+	(void)vfprintf(ttyoutf, fmt, ap);
+	va_end(ap);
+	(void)fflush(ttyoutf);
+}
+
+/*
+ * tty_read()
+ *	read a string from the controlling terminal if it is open into the
+ *	supplied buffer
+ * Return:
+ *	0 if data was read, -1 otherwise.
+ */
+
+#ifdef __STDC__
+int
+tty_read(char *str, int len)
+#else
+int
+tty_read(str, len)
+	char *str;
+	int len;
+#endif
+{
+	register char *pt;
+
+	if ((--len <= 0) || (ttyinf == NULL) || (fgets(str,len,ttyinf) == NULL))
+		return(-1);
+	*(str + len) = '\0';
+
+	/*
+	 * strip off that trailing newline
+	 */
+	if ((pt = strchr(str, '\n')) != NULL)
+		*pt = '\0';
+	return(0);
+}
+
+/*
+ * paxwarn()
+ *	write a warning message to stderr. if "set" the exit value of pax
+ *	will be non-zero.
+ */
+
+#ifdef __STDC__
+void
+paxwarn(int set, char *fmt, ...)
+#else
+void
+paxwarn(set, fmt, va_alist)
+	int set;
+	char *fmt;
+	va_dcl
+#endif
+{
+	va_list ap;
+#	ifdef __STDC__
+	va_start(ap, fmt);
+#	else
+	va_start(ap);
+#	endif
+	if (set)
+		exit_val = 1;
+	/*
+	 * when vflag we better ship out an extra \n to get this message on a
+	 * line by itself
+	 */
+	if (vflag && vfpart) {
+		(void)fputc('\n', stderr);
+		vfpart = 0;
+	}
+	(void)fprintf(stderr, "%s: ", argv0);
+	(void)vfprintf(stderr, fmt, ap);
+	va_end(ap);
+	(void)fputc('\n', stderr);
+}
+
+/*
+ * syswarn()
+ *	write a warning message to stderr. if "set" the exit value of pax
+ *	will be non-zero.
+ */
+
+#ifdef __STDC__
+void
+syswarn(int set, int errnum, char *fmt, ...)
+#else
+void
+syswarn(set, errnum, fmt, va_alist)
+	int set;
+	int errnum;
+	char *fmt;
+	va_dcl
+#endif
+{
+	va_list ap;
+#	ifdef __STDC__
+	va_start(ap, fmt);
+#	else
+	va_start(ap);
+#	endif
+	if (set)
+		exit_val = 1;
+	/*
+	 * when vflag we better ship out an extra \n to get this message on a
+	 * line by itself
+	 */
+	if (vflag && vfpart) {
+		(void)fputc('\n', stderr);
+		vfpart = 0;
+	}
+	(void)fprintf(stderr, "%s: ", argv0);
+	(void)vfprintf(stderr, fmt, ap);
+	va_end(ap);
+
+	/*
+	 * format and print the errno
+	 */
+	if (errnum > 0)
+		(void)fprintf(stderr, " <%s>", strerror(errnum));
+	(void)fputc('\n', stderr);
+}
diff --git a/rm/Makefile b/rm/Makefile
new file mode 100644
index 0000000..f557347
--- /dev/null
+++ b/rm/Makefile
@@ -0,0 +1,48 @@
+#
+# Generated by the NeXT Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = rm
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+CFILES = rm.c
+
+OTHERSRCS = Makefile Makefile.preamble Makefile.postamble rm.1
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /bin
+LIBS = 
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+
+
+NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/$(NAME)/Build
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
diff --git a/rm/Makefile.postamble b/rm/Makefile.postamble
new file mode 100644
index 0000000..013b558
--- /dev/null
+++ b/rm/Makefile.postamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
diff --git a/rm/Makefile.preamble b/rm/Makefile.preamble
new file mode 100644
index 0000000..9e10e90
--- /dev/null
+++ b/rm/Makefile.preamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
diff --git a/rm/PB.project b/rm/PB.project
new file mode 100644
index 0000000..9eb1a48
--- /dev/null
+++ b/rm/PB.project
@@ -0,0 +1,25 @@
+{
+    DYNAMIC_CODE_GEN = YES; 
+    FILESTABLE = {
+        FRAMEWORKS = (); 
+        OTHER_LINKED = (rm.c); 
+        OTHER_SOURCES = (Makefile, Makefile.preamble, Makefile.postamble, rm.1); 
+    }; 
+    LANGUAGE = English; 
+    LOCALIZABLE_FILES = {}; 
+    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
+    NEXTSTEP_BUILDDIR = "/tmp/$(NAME)/Build"; 
+    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
+    NEXTSTEP_INSTALLDIR = /bin; 
+    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
+    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
+    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
+    PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; 
+    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
+    PROJECTNAME = rm; 
+    PROJECTTYPE = Tool; 
+    PROJECTVERSION = 2.8; 
+    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
+    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
+    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
+}
diff --git a/rm/rm.1 b/rm/rm.1
new file mode 100644
index 0000000..98bf94f
--- /dev/null
+++ b/rm/rm.1
@@ -0,0 +1,157 @@
+.\"	$NetBSD: rm.1,v 1.9 1997/10/20 08:53:14 enami Exp $
+.\"
+.\" Copyright (c) 1990, 1993, 1994
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)rm.1	8.5 (Berkeley) 12/5/94
+.\"
+.Dd December 5, 1994
+.Dt RM 1
+.Os
+.Sh NAME
+.Nm rm
+.Nd remove directory entries
+.Sh SYNOPSIS
+.Nm
+.Op Fl f | Fl i
+.Op Fl dPRrW
+.Ar file ...
+.Sh DESCRIPTION
+The
+.Nm
+utility attempts to remove the non-directory type files specified on the
+command line.
+If the permissions of the file do not permit writing, and the standard
+input device is a terminal, the user is prompted (on the standard error
+output) for confirmation.
+.Pp
+The options are as follows:
+.Bl -tag -width flag
+.It Fl d
+Attempt to remove directories as well as other types of files.
+.It Fl f
+Attempt to remove the files without prompting for confirmation,
+regardless of the file's permissions.
+If the file does not exist, do not display a diagnostic message or modify
+the exit status to reflect an error.
+The
+.Fl f
+option overrides any previous
+.Fl i 
+options.
+.It Fl i
+Request confirmation before attempting to remove each file, regardless of
+the file's permissions, or whether or not the standard input device is a
+terminal.
+The
+.Fl i
+option overrides any previous
+.Fl f 
+options.
+.It Fl P
+Overwrite regular files before deleting them.
+Files are overwritten three times, first with the byte pattern 0xff,
+then 0x00, and then 0xff again, before they are deleted.
+.It Fl R
+Attempt to remove the file hierarchy rooted in each file argument.
+The 
+.Fl R
+option implies the
+.Fl d
+option.
+If the
+.Fl i
+option is specified, the user is prompted for confirmation before 
+each directory's contents are processed (as well as before the attempt
+is made to remove the directory).
+If the user does not respond affirmatively, the file hierarchy rooted in
+that directory is skipped.
+.Pp
+.It Fl r
+Equivalent to
+.Fl R .
+.It Fl W
+Attempts to undelete the named files.
+Currently, this option can only be used to recover
+files covered by whiteouts.
+.El
+.Pp
+The
+.Nm
+utility removes symbolic links, not the files referenced by the links.
+.Pp
+It is an error to attempt to remove the files ``.'' and ``..''.
+.Pp
+The
+.Nm
+utility exits 0 if all of the named files or file hierarchies were removed,
+or if the
+.Fl f
+option was specified and all of the existing files or file hierarchies were
+removed.
+If an error occurs,
+.Nm
+exits with a value >0.
+.Sh SEE ALSO
+.Xr rmdir 1 ,
+.Xr undelete 2 ,
+.Xr unlink 2 ,
+.Xr fts 3 ,
+.Xr symlink 7
+.Sh BUGS
+The
+.Fl P
+option assumes that the underlying file system is a fixed-block file
+system.
+UFS is a fixed-block file system, LFS is not.
+In addition, only regular files are overwritten, other types of files
+are not.
+.Sh COMPATIBILITY
+The
+.Nm
+utility differs from historical implementations in that the
+.Fl f
+option only masks attempts to remove non-existent files instead of
+masking a large variety of errors.
+.Pp
+Also, historical
+.Bx
+implementations prompted on the standard output,
+not the standard error output.
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be
+.St -p1003.2
+compatible.
diff --git a/rm/rm.c b/rm/rm.c
new file mode 100644
index 0000000..38e01b8
--- /dev/null
+++ b/rm/rm.c
@@ -0,0 +1,448 @@
+/*	$NetBSD: rm.c,v 1.24 1998/07/28 11:41:51 mycroft Exp $	*/
+
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1990, 1993, 1994\n\
+	The Regents of the University of California.  All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)rm.c	8.8 (Berkeley) 4/27/95";
+#else
+__RCSID("$NetBSD: rm.c,v 1.24 1998/07/28 11:41:51 mycroft Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <locale.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+
+int dflag, eval, fflag, iflag, Pflag, Wflag, stdin_ok;
+
+int	check __P((char *, char *, struct stat *));
+void	checkdot __P((char **));
+void	rm_file __P((char **));
+void	rm_overwrite __P((char *, struct stat *));
+void	rm_tree __P((char **));
+void	usage __P((void));
+int	main __P((int, char *[]));
+
+#ifdef __APPLE__ /* We're missing this prototype */
+int undelete __P((char *));
+#endif
+
+/*
+ * For the sake of the `-f' flag, check whether an error number indicates the
+ * failure of an operation due to an non-existent file, either per se (ENOENT)
+ * or because its filename argument was illegal (ENAMETOOLONG, ENOTDIR).
+ */
+#define NONEXISTENT(x) \
+    ((x) == ENOENT || (x) == ENAMETOOLONG || (x) == ENOTDIR)
+
+/*
+ * rm --
+ *	This rm is different from historic rm's, but is expected to match
+ *	POSIX 1003.2 behavior.  The most visible difference is that -f
+ *	has two specific effects now, ignore non-existent files and force
+ * 	file removal.
+ */
+int
+main(argc, argv)
+	int argc;
+	char *argv[];
+{
+	int ch, rflag;
+
+	(void)setlocale(LC_ALL, "");
+
+	Pflag = rflag = 0;
+	while ((ch = getopt(argc, argv, "dfiPRrW")) != -1)
+		switch(ch) {
+		case 'd':
+			dflag = 1;
+			break;
+		case 'f':
+			fflag = 1;
+			iflag = 0;
+			break;
+		case 'i':
+			fflag = 0;
+			iflag = 1;
+			break;
+		case 'P':
+			Pflag = 1;
+			break;
+		case 'R':
+		case 'r':			/* Compatibility. */
+			rflag = 1;
+			break;
+		case 'W':
+			Wflag = 1;
+			break;
+		case '?':
+		default:
+			usage();
+		}
+	argc -= optind;
+	argv += optind;
+
+	if (argc < 1)
+		usage();
+
+	checkdot(argv);
+
+	if (*argv) {
+		stdin_ok = isatty(STDIN_FILENO);
+
+		if (rflag)
+			rm_tree(argv);
+		else
+			rm_file(argv);
+	}
+
+	exit(eval);
+	/* NOTREACHED */
+}
+
+void
+rm_tree(argv)
+	char **argv;
+{
+	FTS *fts;
+	FTSENT *p;
+	int needstat;
+	int flags;
+
+	/*
+	 * Remove a file hierarchy.  If forcing removal (-f), or interactive
+	 * (-i) or can't ask anyway (stdin_ok), don't stat the file.
+	 */
+	needstat = !fflag && !iflag && stdin_ok;
+
+	/*
+	 * If the -i option is specified, the user can skip on the pre-order
+	 * visit.  The fts_number field flags skipped directories.
+	 */
+#define	SKIPPED	1
+
+	flags = FTS_PHYSICAL;
+	if (!needstat)
+		flags |= FTS_NOSTAT;
+	if (Wflag)
+		flags |= FTS_WHITEOUT;
+	if (!(fts = fts_open(argv, flags,
+		(int (*) __P((const FTSENT **, const FTSENT **)))NULL)))
+		err(1, "%s", "");
+	while ((p = fts_read(fts)) != NULL) {
+		switch (p->fts_info) {
+		case FTS_DNR:
+			if (!fflag || p->fts_errno != ENOENT) {
+				warnx("%s: %s",
+				    p->fts_path, strerror(p->fts_errno));
+				eval = 1;
+			}
+			continue;
+		case FTS_ERR:
+			errx(1, "%s: %s", p->fts_path, strerror(p->fts_errno));
+			/* NOTREACHED */
+		case FTS_NS:
+			/*
+			 * FTS_NS: assume that if can't stat the file, it
+			 * can't be unlinked.
+			 */
+			if (!needstat)
+				break;
+			if (!fflag || !NONEXISTENT(p->fts_errno)) {
+				warnx("%s: %s",
+				    p->fts_path, strerror(p->fts_errno));
+				eval = 1;
+			}
+			continue;
+		case FTS_D:
+			/* Pre-order: give user chance to skip. */
+			if (!fflag && !check(p->fts_path, p->fts_accpath,
+			    p->fts_statp)) {
+				(void)fts_set(fts, p, FTS_SKIP);
+				p->fts_number = SKIPPED;
+			}
+			continue;
+		case FTS_DP:
+			/* Post-order: see if user skipped. */
+			if (p->fts_number == SKIPPED)
+				continue;
+			break;
+		default:
+			if (!fflag &&
+			    !check(p->fts_path, p->fts_accpath, p->fts_statp))
+				continue;
+		}
+
+		/*
+		 * If we can't read or search the directory, may still be
+		 * able to remove it.  Don't print out the un{read,search}able
+		 * message unless the remove fails.
+		 */
+		switch (p->fts_info) {
+		case FTS_DP:
+		case FTS_DNR:
+			if (!rmdir(p->fts_accpath) ||
+			    (fflag && errno == ENOENT))
+				continue;
+			break;
+
+		case FTS_W:
+			if (!undelete(p->fts_accpath) ||
+			    (fflag && errno == ENOENT))
+				continue;
+			break;
+
+		default:
+			if (Pflag)
+				rm_overwrite(p->fts_accpath, NULL);
+			if (!unlink(p->fts_accpath) ||
+			    (fflag && NONEXISTENT(errno)))
+				continue;
+		}
+		warn("%s", p->fts_path);
+		eval = 1;
+	}
+	if (errno)
+		err(1, "fts_read");
+}
+
+void
+rm_file(argv)
+	char **argv;
+{
+	struct stat sb;
+	int rval;
+	char *f;
+
+	/*
+	 * Remove a file.  POSIX 1003.2 states that, by default, attempting
+	 * to remove a directory is an error, so must always stat the file.
+	 */
+	while ((f = *argv++) != NULL) {
+		/* Assume if can't stat the file, can't unlink it. */
+		if (lstat(f, &sb)) {
+			if (Wflag) {
+				sb.st_mode = S_IFWHT|S_IWUSR|S_IRUSR;
+			} else {
+				if (!fflag || !NONEXISTENT(errno)) {
+					warn("%s", f);
+					eval = 1;
+				}
+				continue;
+			}
+		} else if (Wflag) {
+			warnx("%s: %s", f, strerror(EEXIST));
+			eval = 1;
+			continue;
+		}
+
+		if (S_ISDIR(sb.st_mode) && !dflag) {
+			warnx("%s: is a directory", f);
+			eval = 1;
+			continue;
+		}
+		if (!fflag && !S_ISWHT(sb.st_mode) && !check(f, f, &sb))
+			continue;
+		if (S_ISWHT(sb.st_mode))
+			rval = undelete(f);
+		else if (S_ISDIR(sb.st_mode))
+			rval = rmdir(f);
+		else {
+			if (Pflag)
+				rm_overwrite(f, &sb);
+			rval = unlink(f);
+		}
+		if (rval && (!fflag || !NONEXISTENT(errno))) {
+			warn("%s", f);
+			eval = 1;
+		}
+	}
+}
+
+/*
+ * rm_overwrite --
+ *	Overwrite the file 3 times with varying bit patterns.
+ *
+ * XXX
+ * This is a cheap way to *really* delete files.  Note that only regular
+ * files are deleted, directories (and therefore names) will remain.
+ * Also, this assumes a fixed-block file system (like FFS, or a V7 or a
+ * System V file system).  In a logging file system, you'll have to have
+ * kernel support.
+ */
+void
+rm_overwrite(file, sbp)
+	char *file;
+	struct stat *sbp;
+{
+	struct stat sb;
+	off_t len;
+	int fd, wlen;
+	char buf[8 * 1024];
+
+	fd = -1;
+	if (sbp == NULL) {
+		if (lstat(file, &sb))
+			goto err;
+		sbp = &sb;
+	}
+	if (!S_ISREG(sbp->st_mode))
+		return;
+	if ((fd = open(file, O_WRONLY, 0)) == -1)
+		goto err;
+
+#define	PASS(byte) {							\
+	memset(buf, byte, sizeof(buf));					\
+	for (len = sbp->st_size; len > 0; len -= wlen) {		\
+		wlen = len < sizeof(buf) ? len : sizeof(buf);		\
+		if (write(fd, buf, wlen) != wlen)			\
+			goto err;					\
+	}								\
+}
+	PASS(0xff);
+	if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET))
+		goto err;
+	PASS(0x00);
+	if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET))
+		goto err;
+	PASS(0xff);
+	if (!fsync(fd) && !close(fd))
+		return;
+
+err:	eval = 1;
+	warn("%s", file);
+}
+
+
+int
+check(path, name, sp)
+	char *path, *name;
+	struct stat *sp;
+{
+	int ch, first;
+	char modep[15];
+
+	/* Check -i first. */
+	if (iflag)
+		(void)fprintf(stderr, "remove %s? ", path);
+	else {
+		/*
+		 * If it's not a symbolic link and it's unwritable and we're
+		 * talking to a terminal, ask.  Symbolic links are excluded
+		 * because their permissions are meaningless.  Check stdin_ok
+		 * first because we may not have stat'ed the file.
+		 */
+		if (!stdin_ok || S_ISLNK(sp->st_mode) || !access(name, W_OK))
+			return (1);
+		strmode(sp->st_mode, modep);
+		(void)fprintf(stderr, "override %s%s%s/%s for %s? ",
+		    modep + 1, modep[9] == ' ' ? "" : " ",
+		    user_from_uid(sp->st_uid, 0),
+		    group_from_gid(sp->st_gid, 0), path);
+	}
+	(void)fflush(stderr);
+
+	first = ch = getchar();
+	while (ch != '\n' && ch != EOF)
+		ch = getchar();
+	return (first == 'y' || first == 'Y');
+}
+
+/*
+ * POSIX.2 requires that if "." or ".." are specified as the basename
+ * portion of an operand, a diagnostic message be written to standard
+ * error and nothing more be done with such operands.
+ *
+ * Since POSIX.2 defines basename as the final portion of a path after
+ * trailing slashes have been removed, we'll remove them here.
+ */
+#define ISDOT(a) ((a)[0] == '.' && (!(a)[1] || ((a)[1] == '.' && !(a)[2])))
+void
+checkdot(argv)
+	char **argv;
+{
+	char *p, **save, **t;
+	int complained;
+
+	complained = 0;
+	for (t = argv; *t;) {
+		/* strip trailing slashes */
+		p = strrchr (*t, '\0');
+		while (--p > *t && *p == '/')
+			*p = '\0';
+
+		/* extract basename */
+		if ((p = strrchr(*t, '/')) != NULL)
+			++p;
+		else
+			p = *t;
+
+		if (ISDOT(p)) {
+			if (!complained++)
+				warnx("\".\" and \"..\" may not be removed");
+			eval = 1;
+			for (save = t; (t[0] = t[1]) != NULL; ++t)
+				continue;
+			t = save;
+		} else
+			++t;
+	}
+}
+
+void
+usage()
+{
+
+	(void)fprintf(stderr, "usage: rm [-dfiPRrW] file ...\n");
+	exit(1);
+	/* NOTREACHED */
+}
diff --git a/rmdir/Makefile b/rmdir/Makefile
new file mode 100644
index 0000000..9eb48aa
--- /dev/null
+++ b/rmdir/Makefile
@@ -0,0 +1,48 @@
+#
+# Generated by the NeXT Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = rmdir
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+CFILES = rmdir.c
+
+OTHERSRCS = Makefile Makefile.preamble Makefile.postamble rmdir.1
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /bin
+LIBS = 
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+
+
+NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/$(NAME)/Build
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
diff --git a/rmdir/Makefile.postamble b/rmdir/Makefile.postamble
new file mode 100644
index 0000000..013b558
--- /dev/null
+++ b/rmdir/Makefile.postamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
diff --git a/rmdir/Makefile.preamble b/rmdir/Makefile.preamble
new file mode 100644
index 0000000..9e10e90
--- /dev/null
+++ b/rmdir/Makefile.preamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
diff --git a/rmdir/PB.project b/rmdir/PB.project
new file mode 100644
index 0000000..8475318
--- /dev/null
+++ b/rmdir/PB.project
@@ -0,0 +1,25 @@
+{
+    DYNAMIC_CODE_GEN = YES; 
+    FILESTABLE = {
+        FRAMEWORKS = (); 
+        OTHER_LINKED = (rmdir.c); 
+        OTHER_SOURCES = (Makefile, Makefile.preamble, Makefile.postamble, rmdir.1); 
+    }; 
+    LANGUAGE = English; 
+    LOCALIZABLE_FILES = {}; 
+    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
+    NEXTSTEP_BUILDDIR = "/tmp/$(NAME)/Build"; 
+    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
+    NEXTSTEP_INSTALLDIR = /bin; 
+    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
+    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
+    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
+    PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; 
+    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
+    PROJECTNAME = rmdir; 
+    PROJECTTYPE = Tool; 
+    PROJECTVERSION = 2.8; 
+    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
+    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
+    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
+}
diff --git a/rmdir/rmdir.1 b/rmdir/rmdir.1
new file mode 100644
index 0000000..2d67c7a
--- /dev/null
+++ b/rmdir/rmdir.1
@@ -0,0 +1,94 @@
+.\"	$NetBSD: rmdir.1,v 1.11 1997/10/20 08:53:22 enami Exp $
+.\"
+.\" Copyright (c) 1990, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)rmdir.1	8.1 (Berkeley) 5/31/93
+.\"
+.Dd May 31, 1993
+.Dt RMDIR 1
+.Os
+.Sh NAME
+.Nm rmdir
+.Nd remove directories
+.Sh SYNOPSIS
+.Nm
+.Op Fl p
+.Ar directory ...
+.Sh DESCRIPTION
+The rmdir utility removes the directory entry specified by
+each
+.Ar directory
+argument, provided it is empty.
+.Pp
+Arguments are processed in the order given.
+In order to remove both a parent directory and a subdirectory
+of that parent, the subdirectory
+must be specified first so the parent directory
+is empty when
+.Nm
+tries to remove it.
+.Pp
+The following option is available:
+.Bl -tag -width Ds
+.It Fl p
+Each
+.Ar directory
+argument is treated as a pathname of which all
+components will be removed, if they are empty,
+starting with the last most component.
+(See
+.Xr rm 1
+for fully non-discriminant recursive removal.)
+.El
+.Pp
+The
+.Nm
+utility exits with one of the following values:
+.Bl -tag -width Ds
+.It Li \&0
+Each directory entry specified by a dir operand
+referred to an empty directory and was removed
+successfully.
+.It Li \&>\&0
+An error occurred.
+.El
+.Sh SEE ALSO
+.Xr rm 1
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be
+.St -p1003.2
+compatible.
diff --git a/rmdir/rmdir.c b/rmdir/rmdir.c
new file mode 100644
index 0000000..8f61e93
--- /dev/null
+++ b/rmdir/rmdir.c
@@ -0,0 +1,136 @@
+/*	$NetBSD: rmdir.c,v 1.16 1998/07/28 05:31:27 mycroft Exp $	*/
+
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1992, 1993, 1994\n\
+	The Regents of the University of California.  All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)rmdir.c	8.3 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: rmdir.c,v 1.16 1998/07/28 05:31:27 mycroft Exp $");
+#endif
+#endif /* not lint */
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <unistd.h>
+
+int rm_path __P((char *));
+void usage __P((void));
+int main __P((int, char *[]));
+
+int
+main(argc, argv)
+	int argc;
+	char *argv[];
+{
+	int ch, errors;
+	int pflag;
+
+	(void)setlocale(LC_ALL, "");
+
+	pflag = 0;
+	while ((ch = getopt(argc, argv, "p")) != -1)
+		switch(ch) {
+		case 'p':
+			pflag = 1;
+			break;
+		case '?':
+		default:
+			usage();
+		}
+	argc -= optind;
+	argv += optind;
+
+	if (argc == 0)
+		usage();
+
+	for (errors = 0; *argv; argv++) {
+		char *p;
+
+		/* Delete trailing slashes, per POSIX. */
+		p = *argv + strlen(*argv);
+		while (--p > *argv && *p == '/')
+			;
+		*++p = '\0';
+
+		if (rmdir(*argv) < 0) {
+			warn("%s", *argv);
+			errors = 1;
+		} else if (pflag)
+			errors |= rm_path(*argv);
+	}
+
+	exit(errors);
+	/* NOTREACHED */
+}
+
+int
+rm_path(path)
+	char *path;
+{
+	char *p;
+
+	while ((p = strrchr(path, '/')) != NULL) {
+		/* Delete trailing slashes. */
+		while (--p > path && *p == '/')
+			;
+		*++p = '\0';
+
+		if (rmdir(path) < 0) {
+			warn("%s", path);
+			return (1);
+		}
+	}
+
+	return (0);
+}
+
+void
+usage()
+{
+
+	(void)fprintf(stderr, "usage: rmdir [-p] directory ...\n");
+	exit(1);
+	/* NOTREACHED */
+}
diff --git a/rmt/Makefile b/rmt/Makefile
new file mode 100644
index 0000000..805eda7
--- /dev/null
+++ b/rmt/Makefile
@@ -0,0 +1,48 @@
+#
+# Generated by the NeXT Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = rmt
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+CFILES = rmt.c
+
+OTHERSRCS = Makefile Makefile.preamble Makefile.postamble rmt.8
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /usr/sbin
+LIBS = 
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+
+
+NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/$(NAME)/Build
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
diff --git a/rmt/Makefile.postamble b/rmt/Makefile.postamble
new file mode 100644
index 0000000..013b558
--- /dev/null
+++ b/rmt/Makefile.postamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
diff --git a/rmt/Makefile.preamble b/rmt/Makefile.preamble
new file mode 100644
index 0000000..9e10e90
--- /dev/null
+++ b/rmt/Makefile.preamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
diff --git a/rmt/PB.project b/rmt/PB.project
new file mode 100644
index 0000000..08efaea
--- /dev/null
+++ b/rmt/PB.project
@@ -0,0 +1,25 @@
+{
+    DYNAMIC_CODE_GEN = YES; 
+    FILESTABLE = {
+        FRAMEWORKS = (); 
+        OTHER_LINKED = (rmt.c); 
+        OTHER_SOURCES = (Makefile, Makefile.preamble, Makefile.postamble, rmt.8); 
+    }; 
+    LANGUAGE = English; 
+    LOCALIZABLE_FILES = {}; 
+    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
+    NEXTSTEP_BUILDDIR = "/tmp/$(NAME)/Build"; 
+    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
+    NEXTSTEP_INSTALLDIR = /usr/sbin; 
+    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
+    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
+    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
+    PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; 
+    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
+    PROJECTNAME = rmt; 
+    PROJECTTYPE = Tool; 
+    PROJECTVERSION = 2.8; 
+    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
+    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
+    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
+}
diff --git a/rmt/rmt.8 b/rmt/rmt.8
new file mode 100644
index 0000000..77a9074
--- /dev/null
+++ b/rmt/rmt.8
@@ -0,0 +1,220 @@
+.\"	$NetBSD: rmt.8,v 1.6 1997/10/17 13:03:15 lukem Exp $
+.\"
+.\" Copyright (c) 1983, 1991, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     @(#)rmt.8	8.3 (Berkeley) 6/1/94
+.\"
+.Dd June 1, 1994
+.Dt RMT 8
+.Os BSD 4.2
+.Sh NAME
+.Nm rmt
+.Nd remote magtape protocol module
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+.Nm
+is a program used by the remote dump and restore programs
+in manipulating a magnetic tape drive through an interprocess
+communication connection.
+.Nm
+is normally started up with an
+.Xr rexec 3
+or
+.Xr rcmd 3
+call.
+.Pp
+The 
+.Nm
+program accepts requests specific to the manipulation of
+magnetic tapes, performs the commands, then responds with
+a status indication.  All responses are in
+.Tn ASCII
+and in
+one of two forms. 
+Successful commands have responses of:
+.Bd -filled -offset indent
+.Sm off
+.Sy A Ar number No \en
+.Sm on
+.Ed
+.Pp
+.Ar Number
+is an
+.Tn ASCII
+representation of a decimal number.
+Unsuccessful commands are responded to with:
+.Bd -filled -offset indent
+.Sm off
+.Xo Sy E Ar error-number
+.No \en Ar error-message
+.No \en
+.Xc
+.Sm on
+.Ed
+.Pp
+.Ar Error-number
+is one of the possible error
+numbers described in
+.Xr intro 2
+and
+.Ar error-message
+is the corresponding error string as printed
+from a call to
+.Xr perror 3 .
+The protocol is comprised of the
+following commands, which are sent as indicated - no spaces are supplied
+between the command and its arguments, or between its arguments, and
+.Ql \en
+indicates that a newline should be supplied:
+.Bl -tag -width Ds
+.Sm off
+.It Xo Sy \&O Ar device
+.No \en Ar mode No \en
+.Xc
+Open the specified 
+.Ar device
+using the indicated
+.Ar mode .
+.Ar Device
+is a full pathname and
+.Ar mode
+is an
+.Tn ASCII
+representation of a decimal
+number suitable for passing to
+.Xr open 2 .
+If a device had already been opened, it is
+closed before a new open is performed.
+.It Xo Sy C Ar device No \en
+.Xc
+Close the currently open device.  The
+.Ar device
+specified is ignored.
+.It Xo Sy L
+.Ar offset No \en
+.Ar whence No \en
+.Xc
+.Sm on
+Perform an
+.Xr lseek 2
+operation using the specified parameters.
+The response value is that returned from the
+.Xr lseek
+call.
+.Sm off
+.It Sy W Ar count No \en
+.Sm on
+Write data onto the open device.
+.Nm
+reads
+.Ar count
+bytes from the connection, aborting if
+a premature end-of-file is encountered.
+The response value is that returned from
+the
+.Xr write 2
+call.
+.Sm off
+.It Sy R Ar count No \en
+.Sm on
+Read
+.Ar count
+bytes of data from the open device.
+If
+.Ar count
+exceeds the size of the data buffer (10 kilobytes), it is
+truncated to the data buffer size.
+.Nm
+then performs the requested 
+.Xr read 2
+and responds with 
+.Sm off
+.Sy A Ar count-read No \en
+.Sm on
+if the read was
+successful; otherwise an error in the
+standard format is returned.  If the read
+was successful, the data read is then sent.
+.Sm off
+.It Xo Sy I Ar operation
+.No \en Ar count No \en
+.Xc
+.Sm on
+Perform a
+.Dv MTIOCOP
+.Xr ioctl 2
+command using the specified parameters.
+The parameters are interpreted as the
+.Tn ASCII
+representations of the decimal values
+to place in the 
+.Ar mt_op
+and
+.Ar mt_count
+fields of the structure used in the
+.Xr ioctl
+call.  The return value is the
+.Ar count
+parameter when the operation is successful.
+.ne 1i
+.It Sy S
+Return the status of the open device, as
+obtained with a
+.Dv MTIOCGET
+.Xr ioctl
+call.  If the operation was successful,
+an ``ack'' is sent with the size of the
+status buffer, then the status buffer is
+sent (in binary).
+.El
+.Sm on
+.Pp
+Any other command causes 
+.Nm
+to exit.
+.Sh DIAGNOSTICS
+All responses are of the form described above.
+.Sh SEE ALSO
+.Xr rcmd 3 ,
+.Xr rexec 3 ,
+.Xr mtio 4 ,
+.Xr rdump 8 ,
+.Xr rrestore 8
+.Sh BUGS
+People should be discouraged from using this for a remote
+file access protocol.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/rmt/rmt.c b/rmt/rmt.c
new file mode 100644
index 0000000..bfb4d37
--- /dev/null
+++ b/rmt/rmt.c
@@ -0,0 +1,259 @@
+/*	$NetBSD: rmt.c,v 1.9 1997/10/17 13:03:25 lukem Exp $	*/
+
+/*
+ * Copyright (c) 1983, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\
+	The Regents of the University of California.  All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)rmt.c	8.1 (Berkeley) 6/6/93";
+#else
+__RCSID("$NetBSD: rmt.c,v 1.9 1997/10/17 13:03:25 lukem Exp $");
+#endif
+#endif /* not lint */
+
+/*
+ * rmt
+ */
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/mtio.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int	tape = -1;
+
+char	*record;
+int	maxrecsize = -1;
+
+#define	SSIZE	64
+char	device[SSIZE];
+char	count[SSIZE], mode[SSIZE], pos[SSIZE], op[SSIZE];
+
+char	resp[BUFSIZ];
+
+FILE	*debug;
+#define	DEBUG(f)	if (debug) fprintf(debug, f)
+#define	DEBUG1(f,a)	if (debug) fprintf(debug, f, a)
+#define	DEBUG2(f,a1,a2)	if (debug) fprintf(debug, f, a1, a2)
+
+char	*checkbuf __P((char *, int));
+void	 error __P((int));
+int	 main __P((int, char **));
+void	 getstring __P((char *));
+
+int
+main(argc, argv)
+	int argc;
+	char **argv;
+{
+	int rval;
+	char c;
+	int n, i, cc;
+
+	argc--, argv++;
+	if (argc > 0) {
+		debug = fopen(*argv, "w");
+		if (debug == 0)
+			exit(1);
+		(void)setbuf(debug, (char *)0);
+	}
+top:
+	errno = 0;
+	rval = 0;
+	if (read(STDIN_FILENO, &c, 1) != 1)
+		exit(0);
+	switch (c) {
+
+	case 'O':
+		if (tape >= 0)
+			(void) close(tape);
+		getstring(device);
+		getstring(mode);
+		DEBUG2("rmtd: O %s %s\n", device, mode);
+		tape = open(device, atoi(mode),
+		    S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+		if (tape < 0)
+			goto ioerror;
+		goto respond;
+
+	case 'C':
+		DEBUG("rmtd: C\n");
+		getstring(device);		/* discard */
+		if (close(tape) < 0)
+			goto ioerror;
+		tape = -1;
+		goto respond;
+
+	case 'L':
+		getstring(count);
+		getstring(pos);
+		DEBUG2("rmtd: L %s %s\n", count, pos);
+		rval = lseek(tape, (off_t)strtoq(count, NULL, 10), atoi(pos));
+		if (rval < 0)
+			goto ioerror;
+		goto respond;
+
+	case 'W':
+		getstring(count);
+		n = atoi(count);
+		DEBUG1("rmtd: W %s\n", count);
+		record = checkbuf(record, n);
+		for (i = 0; i < n; i += cc) {
+			cc = read(STDIN_FILENO, &record[i], n - i);
+			if (cc <= 0) {
+				DEBUG("rmtd: premature eof\n");
+				exit(2);
+			}
+		}
+		rval = write(tape, record, n);
+		if (rval < 0)
+			goto ioerror;
+		goto respond;
+
+	case 'R':
+		getstring(count);
+		DEBUG1("rmtd: R %s\n", count);
+		n = atoi(count);
+		record = checkbuf(record, n);
+		rval = read(tape, record, n);
+		if (rval < 0)
+			goto ioerror;
+		(void)sprintf(resp, "A%d\n", rval);
+		(void)write(STDOUT_FILENO, resp, strlen(resp));
+		(void)write(STDOUT_FILENO, record, rval);
+		goto top;
+
+	case 'I':
+		getstring(op);
+		getstring(count);
+		DEBUG2("rmtd: I %s %s\n", op, count);
+		{
+			struct mtop mtop;
+
+			mtop.mt_op = atoi(op);
+			mtop.mt_count = atoi(count);
+			if (ioctl(tape, MTIOCTOP, (char *)&mtop) < 0)
+				goto ioerror;
+			rval = mtop.mt_count;
+		}
+		goto respond;
+
+	case 'S':		/* status */
+		DEBUG("rmtd: S\n");
+		{
+			struct mtget mtget;
+
+			if (ioctl(tape, MTIOCGET, (char *)&mtget) < 0)
+				goto ioerror;
+			rval = sizeof (mtget);
+			(void)sprintf(resp, "A%d\n", rval);
+			(void)write(STDOUT_FILENO, resp, strlen(resp));
+			(void)write(STDOUT_FILENO, (char *)&mtget,
+			    sizeof (mtget));
+			goto top;
+		}
+
+	default:
+		DEBUG1("rmtd: garbage command %c\n", c);
+		exit(3);
+	}
+respond:
+	DEBUG1("rmtd: A %d\n", rval);
+	(void)sprintf(resp, "A%d\n", rval);
+	(void)write(STDOUT_FILENO, resp, strlen(resp));
+	goto top;
+ioerror:
+	error(errno);
+	goto top;
+}
+
+void
+getstring(bp)
+	char *bp;
+{
+	int i;
+	char *cp = bp;
+
+	for (i = 0; i < SSIZE - 1; i++) {
+		if (read(STDIN_FILENO, cp+i, 1) != 1)
+			exit(0);
+		if (cp[i] == '\n')
+			break;
+	}
+	cp[i] = '\0';
+}
+
+char *
+checkbuf(record, size)
+	char *record;
+	int size;
+{
+
+	if (size <= maxrecsize)
+		return (record);
+	if (record != 0)
+		free(record);
+	record = malloc(size);
+	if (record == 0) {
+		DEBUG("rmtd: cannot allocate buffer space\n");
+		exit(4);
+	}
+	maxrecsize = size;
+	while (size > 1024 &&
+	    setsockopt(0, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size)) < 0)
+		size -= 1024;
+	return (record);
+}
+
+void
+error(num)
+	int num;
+{
+
+	DEBUG2("rmtd: E %d (%s)\n", num, strerror(num));
+	(void)sprintf(resp, "E%d\n%s\n", num, strerror(num));
+	(void)write(STDOUT_FILENO, resp, strlen(resp));
+}
diff --git a/shar/Makefile b/shar/Makefile
new file mode 100644
index 0000000..b7a027d
--- /dev/null
+++ b/shar/Makefile
@@ -0,0 +1,49 @@
+#
+# Generated by the NeXT Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = shar
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+OTHERLINKED = shar.sh
+
+OTHERSRCS = Makefile Makefile.preamble Makefile.postamble shar.1
+
+OTHERLINKEDOFILES = shar.o
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /usr/bin
+LIBS = 
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+
+
+NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/developer_cmds/Build
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
diff --git a/shar/Makefile.postamble b/shar/Makefile.postamble
new file mode 100644
index 0000000..013b558
--- /dev/null
+++ b/shar/Makefile.postamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
diff --git a/shar/Makefile.preamble b/shar/Makefile.preamble
new file mode 100644
index 0000000..eaa3b46
--- /dev/null
+++ b/shar/Makefile.preamble
@@ -0,0 +1,3 @@
+SHELLTOOL = shar.sh
+
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
diff --git a/shar/PB.project b/shar/PB.project
new file mode 100644
index 0000000..ed6df54
--- /dev/null
+++ b/shar/PB.project
@@ -0,0 +1,25 @@
+{
+    DYNAMIC_CODE_GEN = YES; 
+    FILESTABLE = {
+        FRAMEWORKS = (); 
+        OTHER_LINKED = (shar.sh); 
+        OTHER_SOURCES = (Makefile, Makefile.preamble, Makefile.postamble, shar.1); 
+    }; 
+    LANGUAGE = English; 
+    LOCALIZABLE_FILES = {}; 
+    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
+    NEXTSTEP_BUILDDIR = /tmp/developer_cmds/Build; 
+    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
+    NEXTSTEP_INSTALLDIR = /usr/bin; 
+    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
+    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
+    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
+    PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; 
+    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
+    PROJECTNAME = shar; 
+    PROJECTTYPE = Tool; 
+    PROJECTVERSION = 2.8; 
+    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
+    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
+    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
+}
diff --git a/shar/shar.1 b/shar/shar.1
new file mode 100644
index 0000000..e6b0f15
--- /dev/null
+++ b/shar/shar.1
@@ -0,0 +1,105 @@
+.\"	$NetBSD: shar.1,v 1.6 1998/06/08 12:41:44 lukem Exp $
+.\"
+.\" Copyright (c) 1990, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     @(#)shar.1	8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt SHAR 1
+.Os BSD 4.4
+.Sh NAME
+.Nm shar
+.Nd create a shell archive of files
+.Sh SYNOPSIS
+.Nm
+.Ar
+.Sh DESCRIPTION
+.Nm
+writes an
+.Xr sh 1
+shell script to the standard output which will recreate the file
+hierarchy specified by the command line operands.
+Directories will be recreated and must be specified before the
+files they contain (the
+.Xr find 1
+utility does this correctly).
+.Pp
+.Nm
+is normally used for distributing files by
+.Xr ftp  1
+or
+.Xr mail  1  .
+.Sh SEE ALSO
+.Xr compress 1 ,
+.Xr mail 1 ,
+.Xr uuencode 1 ,
+.Xr tar 1
+.Sh BUGS
+.Nm
+makes no provisions for special types of files or files containing
+magic characters.
+.Sh EXAMPLES
+To create a shell archive of the program
+.Xr ls  1
+and mail it to Rick:
+.Bd -literal -offset indent
+cd ls
+shar `find . -print` \&|  mail -s "ls source" rick
+.Ed
+.Pp
+To recreate the program directory:
+.Bd -literal -offset indent
+mkdir ls
+cd ls
+\&...
+<delete header lines and examine mailed archive>
+\&...
+sh archive
+.Ed
+.Sh HISTORY
+The
+.Nm
+command appears in
+.Bx 4.4 .
+.Sh SECURITY CONSIDERATIONS
+It is easy to insert trojan horses into
+.Nm
+files.
+It is strongly recommended that all shell archive files be examined
+before running them through
+.Xr sh  1  .
+Archives produced using this implementation of
+.Nm
+may be easily examined with the command:
+.Bd -literal -offset indent
+egrep -v '^[X#]' shar.file
+.Ed
diff --git a/shar/shar.sh b/shar/shar.sh
new file mode 100644
index 0000000..7048b44
--- /dev/null
+++ b/shar/shar.sh
@@ -0,0 +1,76 @@
+#!/bin/sh -
+#
+#	$NetBSD: shar.sh,v 1.2 1994/12/21 08:42:04 jtc Exp $
+#
+# Copyright (c) 1990, 1993
+#	The Regents of the University of California.  All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+#    must display the following acknowledgement:
+#	This product includes software developed by the University of
+#	California, Berkeley and its contributors.
+# 4. Neither the name of the University nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+#	@(#)shar.sh	8.1 (Berkeley) 6/6/93
+#
+
+if [ $# -eq 0 ]; then
+	echo 'usage: shar file ...'
+	exit 1
+fi
+
+cat << EOF
+# This is a shell archive.  Save it in a file, remove anything before
+# this line, and then unpack it by entering "sh file".  Note, it may
+# create directories; files and directories will be owned by you and
+# have default permissions.
+#
+# This archive contains:
+#
+EOF
+
+for i
+do
+	echo "#	$i"
+done
+
+echo "#"
+
+for i
+do
+	if [ -d $i ]; then
+		echo "echo c - $i"
+		echo "mkdir -p $i > /dev/null 2>&1"
+	else
+		echo "echo x - $i"
+		echo "sed 's/^X//' >$i << 'END-of-$i'"
+		sed 's/^/X/' $i
+		echo "END-of-$i"
+	fi
+done
+echo exit
+echo ""
+
+exit 0
diff --git a/tcopy/Makefile b/tcopy/Makefile
new file mode 100644
index 0000000..0d2d6b1
--- /dev/null
+++ b/tcopy/Makefile
@@ -0,0 +1,48 @@
+#
+# Generated by the NeXT Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = tcopy
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+CFILES = tcopy.c
+
+OTHERSRCS = Makefile Makefile.preamble Makefile.postamble tcopy.1
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /usr/bin
+LIBS = 
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+
+
+NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/developer_cmds/Build
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
diff --git a/tcopy/Makefile.postamble b/tcopy/Makefile.postamble
new file mode 100644
index 0000000..013b558
--- /dev/null
+++ b/tcopy/Makefile.postamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
diff --git a/tcopy/Makefile.preamble b/tcopy/Makefile.preamble
new file mode 100644
index 0000000..9e10e90
--- /dev/null
+++ b/tcopy/Makefile.preamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
diff --git a/tcopy/PB.project b/tcopy/PB.project
new file mode 100644
index 0000000..d628535
--- /dev/null
+++ b/tcopy/PB.project
@@ -0,0 +1,25 @@
+{
+    DYNAMIC_CODE_GEN = YES; 
+    FILESTABLE = {
+        FRAMEWORKS = (); 
+        OTHER_LINKED = (tcopy.c); 
+        OTHER_SOURCES = (Makefile, Makefile.preamble, Makefile.postamble, tcopy.1); 
+    }; 
+    LANGUAGE = English; 
+    LOCALIZABLE_FILES = {}; 
+    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
+    NEXTSTEP_BUILDDIR = /tmp/developer_cmds/Build; 
+    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
+    NEXTSTEP_INSTALLDIR = /usr/bin; 
+    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
+    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
+    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
+    PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; 
+    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
+    PROJECTNAME = tcopy; 
+    PROJECTTYPE = Tool; 
+    PROJECTVERSION = 2.8; 
+    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
+    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
+    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
+}
diff --git a/tcopy/tcopy.1 b/tcopy/tcopy.1
new file mode 100644
index 0000000..ed27627
--- /dev/null
+++ b/tcopy/tcopy.1
@@ -0,0 +1,91 @@
+.\"	$NetBSD: tcopy.1,v 1.5 1997/10/20 00:35:14 lukem Exp $
+.\"
+.\" Copyright (c) 1985, 1990, 1991, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     @(#)tcopy.1	8.2 (Berkeley) 4/17/94
+.\"
+.Dd April 17, 1994
+.Dt TCOPY 1
+.Os BSD 4.3
+.Sh NAME
+.Nm tcopy
+.Nd copy and/or verify mag tapes
+.Sh SYNOPSIS
+.Nm
+.Op Fl cvx
+.Op Fl s Ar maxblk
+.Oo Ar src Op Ar dest
+.Oc
+.Sh DESCRIPTION
+.Nm
+is designed to copy magnetic tapes.  The only assumption made
+about the tape is that there are two tape marks at the end.
+.Nm
+with only a source tape
+.Pf ( Ar /dev/rst0
+by default) specified will print
+information about the sizes of records and tape files.  If a destination
+is specified a copy will be made of the source tape.  The blocking on the
+destination tape will be identical to that used on the source tape.  Copying
+a tape will yield the same output as if just printing the sizes.
+.Pp
+Options:
+.Bl -tag -width s_maxblk
+.It Fl c
+Copy
+.Ar src
+to
+.Ar dest
+and then verify that the two tapes are identical.
+.It Fl s Ar maxblk
+Specify a maximum block size,
+.Ar maxblk .
+.It Fl v
+Given the two tapes,
+.ar src
+and
+.Ar dest
+verify that they are identical.
+.It Fl x
+Output all informational messages to the standard error.
+This option is useful when
+.Ar dest
+is
+.Pa /dev/stdout .
+.El
+.Sh SEE ALSO
+.Xr mtio 4
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.3 .
diff --git a/tcopy/tcopy.c b/tcopy/tcopy.c
new file mode 100644
index 0000000..297ad01
--- /dev/null
+++ b/tcopy/tcopy.c
@@ -0,0 +1,339 @@
+/*	$NetBSD: tcopy.c,v 1.8 1998/08/25 20:59:41 ross Exp $	*/
+
+/*
+ * Copyright (c) 1985, 1987, 1993, 1995
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1985, 1987, 1993\n\
+	The Regents of the University of California.  All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)tcopy.c	8.3 (Berkeley) 1/23/95";
+#endif
+__RCSID("$NetBSD: tcopy.c,v 1.8 1998/08/25 20:59:41 ross Exp $");
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mtio.h>
+
+#include <err.h>
+#include <errno.h>
+#include <paths.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define	MAXREC	(64 * 1024)
+#define	NOCOUNT	(-2)
+
+int	filen, guesslen, maxblk = MAXREC;
+long	lastrec, record;
+off_t	size, tsize;
+FILE	*msg = stdout;
+
+void	*getspace __P((int));
+void	 intr __P((int));
+int	 main __P((int, char **));
+void	 usage __P((void));
+void	 verify __P((int, int, char *));
+void	 writeop __P((int, int));
+
+int
+main(argc, argv)
+	int argc;
+	char *argv[];
+{
+	int ch, needeof, nw, inp, outp;
+	ssize_t lastnread, nread;
+	enum {READ, VERIFY, COPY, COPYVERIFY} op = READ;
+	sig_t oldsig;
+	char *buff, *inf;
+
+	outp = 0;
+	inf = NULL;
+	guesslen = 1;
+	while ((ch = getopt(argc, argv, "cs:vx")) != -1)
+		switch((char)ch) {
+		case 'c':
+			op = COPYVERIFY;
+			break;
+		case 's':
+			maxblk = atoi(optarg);
+			if (maxblk <= 0) {
+				warnx("illegal block size");
+				usage();
+			}
+			guesslen = 0;
+			break;
+		case 'v':
+			op = VERIFY;
+			break;
+		case 'x':
+			msg = stderr;
+			break;
+		case '?':
+		default:
+			usage();
+		}
+	argc -= optind;
+	argv += optind;
+
+	switch(argc) {
+	case 0:
+		if (op != READ)
+			usage();
+		inf = _PATH_DEFTAPE;
+		break;
+	case 1:
+		if (op != READ)
+			usage();
+		inf = argv[0];
+		break;
+	case 2:
+		if (op == READ)
+			op = COPY;
+		inf = argv[0];
+		if ((outp = open(argv[1], op == VERIFY ? O_RDONLY :
+		    op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE)) < 0) {
+			err(3, argv[1]);
+		}
+		break;
+	default:
+		usage();
+	}
+
+	if ((inp = open(inf, O_RDONLY, 0)) < 0)
+		err(1, inf);
+
+	buff = getspace(maxblk);
+
+	if (op == VERIFY) {
+		verify(inp, outp, buff);
+		exit(0);
+	}
+
+	if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN)
+		(void) signal(SIGINT, intr);
+
+	needeof = 0;
+	for (lastnread = NOCOUNT;;) {
+		if ((nread = read(inp, buff, maxblk)) == -1) {
+			while (errno == EINVAL && (maxblk -= 1024)) {
+				nread = read(inp, buff, maxblk);
+				if (nread >= 0)
+					goto r1;
+			}
+			err(1, "read error, file %d, record %ld",
+			    filen, record);
+		} else if (nread != lastnread) {
+			if (lastnread != 0 && lastnread != NOCOUNT) {
+				if (lastrec == 0 && nread == 0)
+					fprintf(msg, "%ld records\n", record);
+				else if (record - lastrec > 1)
+					fprintf(msg, "records %ld to %ld\n",
+					    lastrec, record);
+				else
+					fprintf(msg, "record %ld\n", lastrec);
+			}
+			if (nread != 0)
+				fprintf(msg, "file %d: block size %ld: ",
+				    filen, (long)nread);
+			(void) fflush(stdout);
+			lastrec = record;
+		}
+r1:		guesslen = 0;
+		if (nread > 0) {
+			if (op == COPY || op == COPYVERIFY) {
+				if (needeof) {
+					writeop(outp, MTWEOF);
+					needeof = 0;
+				}
+				nw = write(outp, buff, nread);
+				if (nw != nread) {
+				    int error = errno;
+				    fprintf(stderr,
+					"write error, file %d, record %ld: ",
+					filen, record);
+				    if (nw == -1)
+					fprintf(stderr,
+						": %s", strerror(error));
+				    else
+					fprintf(stderr,
+					    "write (%d) != read (%ld)\n",
+					    nw, (long)nread);
+				    fprintf(stderr, "copy aborted\n");
+				    exit(5);
+				}
+			}
+			size += nread;
+			record++;
+		} else {
+			if (lastnread <= 0 && lastnread != NOCOUNT) {
+				fprintf(msg, "eot\n");
+				break;
+			}
+			fprintf(msg,
+			    "file %d: eof after %ld records: %qd bytes\n",
+			    filen, record, (long long)size);
+			needeof = 1;
+			filen++;
+			tsize += size;
+			size = record = lastrec = 0;
+			lastnread = 0;
+		}
+		lastnread = nread;
+	}
+	fprintf(msg, "total length: %qd bytes\n", (long long)tsize);
+	(void)signal(SIGINT, oldsig);
+	if (op == COPY || op == COPYVERIFY) {
+		writeop(outp, MTWEOF);
+		writeop(outp, MTWEOF);
+		if (op == COPYVERIFY) {
+			writeop(outp, MTREW);
+			writeop(inp, MTREW);
+			verify(inp, outp, buff);
+		}
+	}
+	exit(0);
+}
+
+void
+verify(inp, outp, outb)
+	int inp, outp;
+	char *outb;
+{
+	int eot, inmaxblk, inn, outmaxblk, outn;
+	char *inb;
+
+	inb = getspace(maxblk);
+	inmaxblk = outmaxblk = maxblk;
+	for (eot = 0;; guesslen = 0) {
+		if ((inn = read(inp, inb, inmaxblk)) == -1) {
+			if (guesslen)
+				while (errno == EINVAL && (inmaxblk -= 1024)) {
+					inn = read(inp, inb, inmaxblk);
+					if (inn >= 0)
+						goto r1;
+				}
+			warn("read error");
+			break;
+		}
+r1:		if ((outn = read(outp, outb, outmaxblk)) == -1) {
+			if (guesslen)
+				while (errno == EINVAL && (outmaxblk -= 1024)) {
+					outn = read(outp, outb, outmaxblk);
+					if (outn >= 0)
+						goto r2;
+				}
+			warn("read error");
+			break;
+		}
+r2:		if (inn != outn) {
+			fprintf(msg,
+			    "%s: tapes have different block sizes; %d != %d.\n",
+			    "tcopy", inn, outn);
+			break;
+		}
+		if (!inn) {
+			if (eot++) {
+				fprintf(msg, "%s: tapes are identical.\n",
+					"tcopy");
+				return;
+			}
+		} else {
+			if (memcmp(inb, outb, inn)) {
+				fprintf(msg,
+				    "%s: tapes have different data.\n",
+					"tcopy");
+				break;
+			}
+			eot = 0;
+		}
+	}
+	exit(1);
+}
+
+void
+intr(signo)
+	int signo;
+{
+	if (record) {
+		if (record - lastrec > 1)
+			fprintf(msg, "records %ld to %ld\n", lastrec, record);
+		else
+			fprintf(msg, "record %ld\n", lastrec);
+	}
+	fprintf(msg, "interrupt at file %d: record %ld\n", filen, record);
+	fprintf(msg, "total length: %qd bytes\n", (long long)(tsize + size));
+	exit(1);
+}
+
+void *
+getspace(blk)
+	int blk;
+{
+	void *bp;
+
+	if ((bp = malloc((size_t)blk)) == NULL)
+		errx(11, "no memory");
+
+	return (bp);
+}
+
+void
+writeop(fd, type)
+	int fd, type;
+{
+	struct mtop op;
+
+	op.mt_op = type;
+	op.mt_count = (daddr_t)1;
+	if (ioctl(fd, MTIOCTOP, (char *)&op) < 0)
+		err(6, "tape op");
+}
+
+void
+usage()
+{
+
+	fprintf(stderr, "usage: tcopy [-cvx] [-s maxblk] src [dest]\n");
+	exit(1);
+}
diff --git a/touch/Makefile b/touch/Makefile
new file mode 100644
index 0000000..774770c
--- /dev/null
+++ b/touch/Makefile
@@ -0,0 +1,48 @@
+#
+# Generated by the NeXT Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = touch
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+CFILES = touch.c
+
+OTHERSRCS = Makefile Makefile.preamble Makefile.postamble touch.1
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /usr/bin
+LIBS = 
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+
+
+NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/developer_cmds/Build
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
diff --git a/touch/Makefile.postamble b/touch/Makefile.postamble
new file mode 100644
index 0000000..013b558
--- /dev/null
+++ b/touch/Makefile.postamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
diff --git a/touch/Makefile.preamble b/touch/Makefile.preamble
new file mode 100644
index 0000000..9e10e90
--- /dev/null
+++ b/touch/Makefile.preamble
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
diff --git a/touch/PB.project b/touch/PB.project
new file mode 100644
index 0000000..0f39cfd
--- /dev/null
+++ b/touch/PB.project
@@ -0,0 +1,25 @@
+{
+    DYNAMIC_CODE_GEN = YES; 
+    FILESTABLE = {
+        FRAMEWORKS = (); 
+        OTHER_LINKED = (touch.c); 
+        OTHER_SOURCES = (Makefile, Makefile.preamble, Makefile.postamble, touch.1); 
+    }; 
+    LANGUAGE = English; 
+    LOCALIZABLE_FILES = {}; 
+    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
+    NEXTSTEP_BUILDDIR = /tmp/developer_cmds/Build; 
+    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
+    NEXTSTEP_INSTALLDIR = /usr/bin; 
+    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
+    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
+    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
+    PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; 
+    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
+    PROJECTNAME = touch; 
+    PROJECTTYPE = Tool; 
+    PROJECTVERSION = 2.8; 
+    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
+    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
+    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
+}
diff --git a/touch/touch.1 b/touch/touch.1
new file mode 100644
index 0000000..d2bb977
--- /dev/null
+++ b/touch/touch.1
@@ -0,0 +1,177 @@
+.\"	$NetBSD: touch.1,v 1.13 1998/01/20 21:18:25 mycroft Exp $
+.\"
+.\" Copyright (c) 1991, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     @(#)touch.1	8.3 (Berkeley) 4/28/95
+.\"
+.Dd April 28, 1995
+.Dt TOUCH 1
+.Os
+.Sh NAME
+.Nm touch
+.Nd change file access and modification times
+.Sh SYNOPSIS
+.Nm
+.Op Fl acfhm
+.Op Fl r Ar file
+.Op Fl t Ar [[CC]YY]MMDDhhmm[.SS]
+.Ar file ...
+.Sh DESCRIPTION
+The
+.Nm
+utility sets the modification and access times of files to the
+current time of day.
+If the file doesn't exist, it is created with default permissions.
+.Pp
+The following options are available:
+.Bl -tag -width Ds
+.It Fl a
+Change the access time of the file.
+The modification time of the file is not changed unless the
+.Fl m
+flag is also specified.
+.It Fl c
+Do not create the file if it does not exist.
+The
+.Nm
+utility does not treat this as an error.
+No error messages are displayed and the exit value is not affected.
+.It Fl f
+Attempt to force the update, even if the file permissions do not
+currently permit it.
+.It Fl h
+If
+.Ar file
+is a symbolic link, access and/or modification time of the link is changed.
+This option implies
+.Fl c .
+.It Fl m
+Change the modification time of the file.
+The access time of the file is not changed unless the
+.Fl a
+flag is also specified.
+.It Fl r
+Use the access and modifications times from the specified file
+instead of the current time of day.
+.It Fl t
+Change the access and modification times to the specified time.
+The argument should be in the form
+.Dq [[CC]YY]MMDDhhmm[.SS]
+where each pair of letters represents the following:
+.Pp
+.Bl -tag -width Ds -compact -offset indent
+.It Ar CC
+The first two digits of the year (the century).
+.It Ar YY
+The second two digits of the year.
+If
+.Dq YY
+is specified, but
+.Dq CC
+is not, a value for
+.Dq YY
+between 69 and 99 results in a
+.Dq CC
+value of 19.
+Otherwise, a
+.Dq CC
+value of 20 is used.
+.It Ar MM
+The month of the year, from 1 to 12.
+.It Ar DD
+The day of the month, from 1 to 31.
+.It Ar hh
+The hour of the day, from 0 to 23.
+.It Ar mm
+The minute of the hour, from 0 to 59.
+.It Ar SS
+The second of the minute, from 0 to 61.
+.El
+.Pp
+If the
+.Dq CC
+and
+.Dq YY
+letter pairs are not specified, the values default to the current
+year.
+If the
+.Dq SS
+letter pair is not specified, the value defaults to 0.
+.El
+.Pp
+The
+.Nm
+utility exits 0 on success, and >0 if an error occurs.
+.Sh SEE ALSO
+.Xr utimes 2
+.Sh COMPATIBILITY
+The obsolescent form of
+.Nm "" ,
+where a time format is specified as the first argument, is supported.
+When no
+.Fl r
+or
+.Fl t
+option is specified, there are at least two arguments, and the first
+argument is a string of digits either eight or ten characters in length,
+the first argument is interpreted as a time specification of the form
+.Dq MMDDhhmm[YY] .
+.Pp
+The
+.Dq MM ,
+.Dq DD ,
+.Dq hh
+and
+.Dq mm
+letter pairs are treated as their counterparts specified to the
+.Fl t
+option.
+If the
+.Dq YY
+letter pair is in the range 69 to 99, the year is set to 1969 to 1999,
+otherwise, the year is set in the 21st century.
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be a superset of the
+.St -p1003.2
+specification.
+.Sh HISTORY
+A
+.Nm
+utility appeared in
+.At v7 .
+.Sh BUGS
+A symbolic link can't be a reference file of access and/or modification time.
diff --git a/touch/touch.c b/touch/touch.c
new file mode 100644
index 0000000..71499fa
--- /dev/null
+++ b/touch/touch.c
@@ -0,0 +1,389 @@
+/*	$NetBSD: touch.c,v 1.22 1998/08/25 20:59:42 ross Exp $	*/
+
+/*
+ * Copyright (c) 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1993\n\
+	The Regents of the University of California.  All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)touch.c	8.2 (Berkeley) 4/28/95";
+#endif
+__RCSID("$NetBSD: touch.c,v 1.22 1998/08/25 20:59:42 ross Exp $");
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <time.h>
+#include <tzfile.h>
+#include <unistd.h>
+
+int	main __P((int, char **));
+int	rw __P((char *, struct stat *, int));
+void	stime_arg1 __P((char *, struct timeval *));
+void	stime_arg2 __P((char *, int, struct timeval *));
+void	stime_file __P((char *, struct timeval *));
+void	usage __P((void));
+
+int
+main(argc, argv)
+	int argc;
+	char *argv[];
+{
+	struct stat sb;
+	struct timeval tv[2];
+	int aflag, cflag, fflag, hflag, mflag, ch, fd, len, rval, timeset;
+	char *p;
+	int (*change_file_times) __P((const char *, const struct timeval *));
+	int (*get_file_status) __P((const char *, struct stat *));
+
+	setlocale(LC_ALL, "");
+
+	aflag = cflag = fflag = hflag = mflag = timeset = 0;
+	if (gettimeofday(&tv[0], NULL))
+		err(1, "gettimeofday");
+
+	while ((ch = getopt(argc, argv, "acfhmr:t:")) != -1)
+		switch(ch) {
+		case 'a':
+			aflag = 1;
+			break;
+		case 'c':
+			cflag = 1;
+			break;
+		case 'f':
+			fflag = 1;
+			break;
+#ifndef __APPLE__
+		case 'h':
+			hflag = 1;
+			break;
+#endif
+		case 'm':
+			mflag = 1;
+			break;
+		case 'r':
+			timeset = 1;
+			stime_file(optarg, tv);
+			break;
+		case 't':
+			timeset = 1;
+			stime_arg1(optarg, tv);
+			break;
+		case '?':
+		default:
+			usage();
+		}
+	argc -= optind;
+	argv += optind;
+
+	/* Default is both -a and -m. */
+	if (aflag == 0 && mflag == 0)
+		aflag = mflag = 1;
+
+#ifndef __APPLE__
+	if (hflag) {
+		cflag = 1;		/* Don't create new file */
+		change_file_times = lutimes;
+		get_file_status = lstat;
+	} else {
+#endif
+		change_file_times = utimes;
+		get_file_status = stat;
+#ifndef __APPLE__
+	}
+#endif
+
+	/*
+	 * If no -r or -t flag, at least two operands, the first of which
+	 * is an 8 or 10 digit number, use the obsolete time specification.
+	 */
+	if (!timeset && argc > 1) {
+		(void)strtol(argv[0], &p, 10);
+		len = p - argv[0];
+		if (*p == '\0' && (len == 8 || len == 10)) {
+			timeset = 1;
+			stime_arg2(*argv++, len == 10, tv);
+		}
+	}
+
+	/* Otherwise use the current time of day. */
+	if (!timeset)
+		tv[1] = tv[0];
+
+	if (*argv == NULL)
+		usage();
+
+	for (rval = 0; *argv; ++argv) {
+		/* See if the file exists. */
+		if ((*get_file_status)(*argv, &sb)) {
+			if (!cflag) {
+				/* Create the file. */
+				fd = open(*argv,
+				    O_WRONLY | O_CREAT, DEFFILEMODE);
+				if (fd == -1 || fstat(fd, &sb) || close(fd)) {
+					rval = 1;
+					warn("%s", *argv);
+					continue;
+				}
+
+				/* If using the current time, we're done. */
+				if (!timeset)
+					continue;
+			} else
+				continue;
+		}
+		if (!aflag)
+			TIMESPEC_TO_TIMEVAL(&tv[0], &sb.st_atimespec);
+		if (!mflag)
+			TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtimespec);
+
+		/* Try utimes(2). */
+		if (!(*change_file_times)(*argv, tv))
+			continue;
+
+		/* If the user specified a time, nothing else we can do. */
+		if (timeset) {
+			rval = 1;
+			warn("%s", *argv);
+		}
+
+		/*
+		 * System V and POSIX 1003.1 require that a NULL argument
+		 * set the access/modification times to the current time.
+		 * The permission checks are different, too, in that the
+		 * ability to write the file is sufficient.  Take a shot.
+		 */
+		 if (!(*change_file_times)(*argv, NULL))
+			continue;
+
+		/* Try reading/writing. */
+		if (!S_ISLNK(sb.st_mode) && rw(*argv, &sb, fflag))
+			rval = 1;
+	}
+	exit(rval);
+}
+
+#define	ATOI2(s)	((s) += 2, ((s)[-2] - '0') * 10 + ((s)[-1] - '0'))
+
+void
+stime_arg1(arg, tvp)
+	char *arg;
+	struct timeval *tvp;
+{
+	struct tm *t;
+	time_t tmptime;
+	int yearset;
+	char *p;
+					/* Start with the current time. */
+	tmptime = tvp[0].tv_sec;
+	if ((t = localtime(&tmptime)) == NULL)
+		err(1, "localtime");
+					/* [[CC]YY]MMDDhhmm[.SS] */
+	if ((p = strchr(arg, '.')) == NULL)
+		t->tm_sec = 0;		/* Seconds defaults to 0. */
+	else {
+		if (strlen(p + 1) != 2)
+			goto terr;
+		*p++ = '\0';
+		t->tm_sec = ATOI2(p);
+	}
+		
+	yearset = 0;
+	switch (strlen(arg)) {
+	case 12:			/* CCYYMMDDhhmm */
+		t->tm_year = ATOI2(arg) * 100 - TM_YEAR_BASE;
+		yearset = 1;
+		/* FALLTHOUGH */
+	case 10:			/* YYMMDDhhmm */
+		if (yearset) {
+			t->tm_year += ATOI2(arg);
+		} else {
+			yearset = ATOI2(arg);
+			if (yearset < 69)
+				t->tm_year = yearset + 2000 - TM_YEAR_BASE;
+			else
+				t->tm_year = yearset + 1900 - TM_YEAR_BASE;
+		}
+		/* FALLTHROUGH */
+	case 8:				/* MMDDhhmm */
+		t->tm_mon = ATOI2(arg);
+		--t->tm_mon;		/* Convert from 01-12 to 00-11 */
+		/* FALLTHROUGH */
+	case 6:
+		t->tm_mday = ATOI2(arg);
+		/* FALLTHROUGH */
+	case 4:
+		t->tm_hour = ATOI2(arg);
+		/* FALLTHROUGH */
+	case 2:
+		t->tm_min = ATOI2(arg);
+		break;
+	default:
+		goto terr;
+	}
+
+	t->tm_isdst = -1;		/* Figure out DST. */
+	tvp[0].tv_sec = tvp[1].tv_sec = mktime(t);
+	if (tvp[0].tv_sec == -1)
+terr:		errx(1,
+	"out of range or illegal time specification: [[CC]YY]MMDDhhmm[.SS]");
+
+	tvp[0].tv_usec = tvp[1].tv_usec = 0;
+}
+
+void
+stime_arg2(arg, year, tvp)
+	char *arg;
+	int year;
+	struct timeval *tvp;
+{
+	struct tm *t;
+	time_t tmptime;
+					/* Start with the current time. */
+	tmptime = tvp[0].tv_sec;
+	if ((t = localtime(&tmptime)) == NULL)
+		err(1, "localtime");
+
+	t->tm_mon = ATOI2(arg);		/* MMDDhhmm[yy] */
+	--t->tm_mon;			/* Convert from 01-12 to 00-11 */
+	t->tm_mday = ATOI2(arg);
+	t->tm_hour = ATOI2(arg);
+	t->tm_min = ATOI2(arg);
+	if (year) {
+		year = ATOI2(arg);
+		if (year < 69)
+			t->tm_year = year + 2000 - TM_YEAR_BASE;
+		else
+			t->tm_year = year + 1900 - TM_YEAR_BASE;
+	}
+
+	t->tm_isdst = -1;		/* Figure out DST. */
+	tvp[0].tv_sec = tvp[1].tv_sec = mktime(t);
+	if (tvp[0].tv_sec == -1)
+		errx(1,
+	"out of range or illegal time specification: MMDDhhmm[yy]");
+
+	tvp[0].tv_usec = tvp[1].tv_usec = 0;
+}
+
+void
+stime_file(fname, tvp)
+	char *fname;
+	struct timeval *tvp;
+{
+	struct stat sb;
+
+	if (stat(fname, &sb))
+		err(1, "%s", fname);
+	TIMESPEC_TO_TIMEVAL(&tvp[0], &sb.st_atimespec);
+	TIMESPEC_TO_TIMEVAL(&tvp[1], &sb.st_mtimespec);
+}
+
+int
+rw(fname, sbp, force)
+	char *fname;
+	struct stat *sbp;
+	int force;
+{
+	int fd, needed_chmod, rval;
+	u_char byte;
+
+	/* Try regular files and directories. */
+	if (!S_ISREG(sbp->st_mode) && !S_ISDIR(sbp->st_mode)) {
+		warnx("%s: %s", fname, strerror(EFTYPE));
+		return (1);
+	}
+
+	needed_chmod = rval = 0;
+	if ((fd = open(fname, O_RDWR, 0)) == -1) {
+		if (!force || chmod(fname, DEFFILEMODE))
+			goto err;
+		if ((fd = open(fname, O_RDWR, 0)) == -1)
+			goto err;
+		needed_chmod = 1;
+	}
+
+	if (sbp->st_size != 0) {
+		if (read(fd, &byte, sizeof(byte)) != sizeof(byte))
+			goto err;
+		if (lseek(fd, (off_t)0, SEEK_SET) == -1)
+			goto err;
+		if (write(fd, &byte, sizeof(byte)) != sizeof(byte))
+			goto err;
+	} else {
+		if (write(fd, &byte, sizeof(byte)) != sizeof(byte)) {
+err:			rval = 1;
+			warn("%s", fname);
+		} else if (ftruncate(fd, (off_t)0)) {
+			rval = 1;
+			warn("%s: file modified", fname);
+		}
+	}
+
+	if (close(fd) && rval != 1) {
+		rval = 1;
+		warn("%s", fname);
+	}
+	if (needed_chmod && chmod(fname, sbp->st_mode) && rval != 1) {
+		rval = 1;
+		warn("%s: permissions modified", fname);
+	}
+	return (rval);
+}
+
+__dead void
+usage()
+{
+#ifndef __APPLE__
+	(void)fprintf(stderr,
+	    "usage: touch [-acfhm] [-r file] [-t time] file ...\n");
+#else
+	(void)fprintf(stderr,
+	    "usage: touch [-acfm] [-r file] [-t time] file ...\n");
+#endif
+	exit(1);
+}
-- 
2.47.2