summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cvsignore12
-rw-r--r--AUTHORS3
-rw-r--r--Makefile.am23
-rw-r--r--NEWS32
-rw-r--r--README-alpha86
-rw-r--r--THANKS10
-rw-r--r--build-aux/.cvsignore7
-rwxr-xr-xbuild-aux/bootstrap270
-rw-r--r--build-aux/gnulib.modules17
-rw-r--r--configure.ac268
-rw-r--r--lib/.cvsignore75
-rw-r--r--lib/Makefile.tmpl32
-rw-r--r--m4/.cvsignore70
-rw-r--r--paxlib/.cvsignore4
-rw-r--r--paxlib/Makefile.am43
-rw-r--r--paxlib/pax.h69
-rw-r--r--paxlib/paxbuf.c332
-rw-r--r--paxlib/paxbuf.h65
-rw-r--r--paxlib/rtape.c761
-rw-r--r--paxlib/tar.h279
-rw-r--r--paxlib/tarbuf.c218
-rw-r--r--paxlib/tardef.h54
-rw-r--r--paxtest/.cvsignore4
-rw-r--r--paxtest/Makefile.am28
-rw-r--r--paxtest/paxtest.c85
-rw-r--r--paxtest/paxtest.h25
26 files changed, 2872 insertions, 0 deletions
diff --git a/.cvsignore b/.cvsignore
new file mode 100644
index 0000000..51cfcd3
--- /dev/null
+++ b/.cvsignore
@@ -0,0 +1,12 @@
+ABOUT-NLS
+INSTALL
+Makefile
+Makefile.in
+aclocal.m4
+autom4te.cache
+config.h
+config.h.in
+config.log
+config.status
+configure
+stamp-h1
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..11acbcc
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,3 @@
+Authors of GNU paxutils
+
+Sergey Poznyakoff gray@gnu.org.ua
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..f8cae47
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,23 @@
+# This file is part of GNU paxutils
+#
+# Copyright (c) 2005 Free Software Foundation, Inc.
+#
+# Written by Sergey Poznyakoff
+#
+# GNU Paxutils is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2, or (at your option) any later
+# version.
+#
+# GNU Paxutils is distributed in the hope that it will be useful, but
+# without any warranty; without even the implied warranty of
+# merchantability or fitness for a particular purpose. see the gnu general
+# public license for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with GNU Paxutils; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ACLOCAL_AMFLAGS = -I m4
+
+SUBDIRS = lib paxlib paxtest po
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..25cf64c
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,32 @@
+GNU paxutils NEWS -- history of user-visible changes. 2005-05-14
+Copyright (C) 2005 Free Software Foundation, Inc.
+See the end of file for copying conditions.
+
+Please send paxutils bug reports to <bug-tar@gnu.org>.
+
+
+Version 0.0.1:
+
+* Implemented general-purpose buffer support.
+* Implemented the framework of paxtest utility
+
+
+----------------------------------------------------------------------
+* Copyright information:
+
+Copyright (C) 2005 Free Software Foundation, Inc.
+
+ Permission is granted to anyone to make or distribute verbatim copies
+ of this document as received, in any medium, provided that the
+ copyright notice and this permission notice are preserved,
+ thus giving the recipient permission to redistribute in turn.
+
+ Permission is granted to distribute modified versions
+ of this document, or of portions of it,
+ under the above conditions, provided also that they
+ carry prominent notices stating who last changed them.
+
+Local variables:
+mode: outline
+paragraph-separate: "[ ]*$"
+end:
diff --git a/README-alpha b/README-alpha
new file mode 100644
index 0000000..9c26f9b
--- /dev/null
+++ b/README-alpha
@@ -0,0 +1,86 @@
+This is GNU paxutils.
+This document describes the actions needed to build the pre-release
+or CVS version of the package. See end of file for copying conditions.
+
+* Introduction
+
+ This is a *pre-release* version, and not ready for production use
+yet. For information about GNU paxutils and its aims, please see file
+README.
+
+ If you are taking source from CVS, you will need to have automake,
+and autoconf installed to bootstrap the package. See the chapter
+`Building' for the detailed instructions. After bootstrapping, there
+should be a file 'INSTALL' with generic installation
+instructions. Package-specific installation instructions are set forth
+in the file README.
+
+ Please, note that the accompanying documentation may be inaccurate
+or incomplete (well, to say the truth it is absent. See TODO for more
+info). The ChangeLog file is currently the authoritative documentation
+of all recent changes.
+
+Report bugs to <bug-tar@gnu.org>
+
+* Checking Out the Sources
+
+ The following instructions apply if you wish to obtain sources from
+the CVS repository:
+
+To checkout the source tree from CVS issue the following command:
+
+CVS_RSH=ssh \
+ cvs -d :ext:anoncvs@savannah.gnu.org:/cvsroot/paxutils checkout paxutils
+
+Make sure SSHv2 is used.
+
+This will give you read-only access. If you think you need write access,
+contact the mailing list.
+
+The CVS repository is also available via HTTP from
+
+ http://savannah.gnu.org/cgi-bin/viewcvs/paxutils/paxutils
+
+* Building
+
+ In order to build this you will first need to have right versions
+of autotools. At the time of this writing these are:
+
+ Package Version (>=)
+ ======== ============
+ automake 1.8.5
+ autoconf 2.59
+ gettext 0.14.1
+
+ To prepare the package for building run build-aux/bootstrap. For
+example:
+
+ $ cd paxutils
+ $ build-aux/bootstrap
+
+ If you have already checked out gnulib sources, use --gnulib-srcdir
+to specify their location, this will spare you time and bandwidth:
+
+ $ cd paxutils
+ $ build-aux/bootstrap --gnulib-srcdir=$HOME/gnu/gnulib
+
+* Copyright information:
+
+Copyright (C) 2005 Free Software Foundation, Inc.
+
+ Permission is granted to anyone to make or distribute verbatim copies
+ of this document as received, in any medium, provided that the
+ copyright notice and this permission notice are preserved,
+ thus giving the recipient permission to redistribute in turn.
+
+ Permission is granted to distribute modified versions
+ of this document, or of portions of it,
+ under the above conditions, provided also that they
+ carry prominent notices stating who last changed them.
+
+
+Local Variables:
+mode: outline
+paragraph-separate: "[ ]*$"
+version-control: never
+End:
diff --git a/THANKS b/THANKS
new file mode 100644
index 0000000..df33cc7
--- /dev/null
+++ b/THANKS
@@ -0,0 +1,10 @@
+GNU paxutils THANKS file
+
+Paul Eggert eggert@twinsun.com
+François Pinard pinard@iro.umontreal.ca
+
+
+;;;; Local variables:
+;;;; mode: Fundamental
+;;;; buffer-file-coding-system: utf-8
+;;;; End:
diff --git a/build-aux/.cvsignore b/build-aux/.cvsignore
new file mode 100644
index 0000000..eb303c8
--- /dev/null
+++ b/build-aux/.cvsignore
@@ -0,0 +1,7 @@
+config.guess
+config.rpath
+config.sub
+depcomp
+install-sh
+missing
+mkinstalldirs
diff --git a/build-aux/bootstrap b/build-aux/bootstrap
new file mode 100755
index 0000000..25d5242
--- /dev/null
+++ b/build-aux/bootstrap
@@ -0,0 +1,270 @@
+#! /bin/sh
+
+# Bootstrap 'paxutils' from CVS.
+
+# Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# Written by Paul Eggert and Sergey Poznyakoff.
+
+# *Eventual* URL of our text domain page in Translation Project
+TP_URL="http://www.iro.umontreal.ca/translation/maint/paxutils/"
+
+# Ensure file names are sorted consistently across platforms;
+# e.g., m4/ulonglong_gl.m4 should follow m4/ulonglong.m4.
+LC_ALL=C
+export LC_ALL
+
+usage() {
+ cat <<EOF
+ usage: $0 [--gnulib-srcdir=DIR][--cvs-auth=AUTH-METHOD][--cvs-user=USERNAME][--no-po]
+ Options are:
+ --gnulib-srcdir=DIRNAME Specify the local directory where gnulib
+ sources reside. Use this if you already
+ have gnulib sources on your machine, and
+ do not want to waste your bandwidth dowloading
+ them again.
+ --cvs-auth=METHOD Set the CVS access method used for downloading
+ gnulib files. METHOD is one of the keywords
+ accepted by cvs -d option (see info cvs
+ repository).
+ --cvs-user=USERNAME Set the CVS username to be used when accessing
+ the gnulib repository.
+ --no-po Do not download po files.
+ --update-po[=LANG] Update po file(s) and exit.
+
+Running without arguments will suffice in most cases. It is equivalent
+to
+
+ ./bootstrap --cvs-auth=ext --cvs-user=anoncvs
+
+EOF
+}
+
+bailout() {
+ echo "$0: $*" >&2
+ exit 1
+}
+
+update_po() {
+ if [ $# = 1 ]; then
+ case $1 in
+ *.po) POFILE=$1;;
+ *) POFILE=${1}.po;;
+ esac
+ echo "$0: getting translation for $1..."
+ wget -r -C off $TP_URL/$POFILE
+ else
+ echo "$0: getting translations into po..."
+ (cd po &&
+ rm -f dummy `ls | sed -n '/\.gmo$/p; /\.po/p'` &&
+ wget -nv -nd -r -l 1 -A .po -C off $TP_URL &&
+ rm -f index.html index.html.[0-9]*
+ ls *.po | sed 's/\.po$//' >LINGUAS
+ ) || exit
+ fi
+}
+
+# Parse options.
+
+DOWNLOAD_PO=no
+for option
+do
+ case $option in
+ --help)
+ usage
+ exit;;
+ --gnulib-srcdir=*)
+ GNULIB_SRCDIR=`expr "$option" : '--gnulib-srcdir=\(.*\)'`;;
+ --cvs-auth=*)
+ CVS_AUTH=`expr "$option" : '--cvs-auth=\(.*\)'`;;
+ --cvs-user=*)
+ CVS_USER=`expr "$option" : '--cvs-user=\(.*\)'`;;
+ --no-po)
+ DOWNLOAD_PO=no;;
+ --update-po=*)
+ bailout "Option is not yet active"
+ DOWNLOAD_PO=`expr "$option" : '--update-po=\(.*\)'`;;
+ --update-po)
+ bailout "Option is not yet active"
+ DOWNLOAD_PO=only;;
+ *)
+ bailout "$option: unknown option"
+ exit 1;;
+ esac
+done
+
+case $DOWNLOAD_PO in
+only) update_po
+ exit 0
+ ;;
+no|yes) ;;
+*) update_po $DOWNLOAD_PO
+ exit 0
+esac
+
+echo "$0: Bootstrapping CVS paxutils..."
+
+build_cvs_prefix() {
+ CVS_PREFIX=:${1}:
+ if [ "${2}" != - ]; then
+ CVS_PREFIX=${CVS_PREFIX}${2}@
+ fi
+ if [ "$1" = "ext" ]; then
+ if [ -z "${CVS_RSH}" ]; then
+ CVS_RSH=ssh
+ export CVS_RSH
+ fi
+ fi
+}
+
+# checkout package
+checkout() {
+ if [ ! -d $1 ]; then
+ echo "$0: getting $1 files..."
+
+ trap exit 1 2 13 15
+ trap 'rm -fr $1; exit 1' 0
+
+ case "${CVS_AUTH--}" in
+ -) build_cvs_prefix ext anoncvs
+ ;;
+ pserver) build_cvs_prefix $CVS_AUTH ${CVS_USER:-anoncvs}
+ ;;
+ gserver|server)
+ build_cvs_prefix $CVS_AUTH ${CVS_USER--}
+ ;;
+ ext) build_cvs_prefix $CVS_AUTH ${CVS_USER--}
+ ;;
+ *) echo "$0: Unknown CVS access method" >&2
+ exit 1;;
+ esac
+ if [ "${CVS_AUTH--}" = "pserver" ]; then
+ cvs -d ${CVS_PREFIX}subversions.gnu.org:/cvsroot/$1 login || exit
+ fi
+ cvs -q -d ${CVS_PREFIX}subversions.gnu.org:/cvsroot/$1 co $1 || exit
+
+ trap 0
+ fi
+}
+
+# Prepare temporary module list
+cat /dev/null > modlist.tmp
+trap 'rm -f modlist.tmp' 0 1 2 13 15
+
+get_modules() {
+ sed '/^[ ]*#/d;/^[ ]*$/d' $* >> modlist.tmp
+}
+
+# copy_files srcdir dstdir
+copy_files() {
+ for file in `cat $1/DISTFILES`
+ do
+ case $file in
+ "#*") continue;;
+ esac
+ echo "$0: Copying file $1/$file"
+ cp -p $1/$file $2/`expr $file : '.*/\(.*\)'`
+ done
+}
+
+# Get gnulib files.
+
+case ${GNULIB_SRCDIR--} in
+-) checkout gnulib
+ GNULIB_SRCDIR=gnulib
+esac
+
+<$GNULIB_SRCDIR/gnulib-tool || exit
+
+get_modules build-aux/gnulib.modules
+
+gnulib_modules=`sort -u modlist.tmp`
+previous_gnulib_modules=
+while [ "$gnulib_modules" != "$previous_gnulib_modules" ]; do
+ previous_gnulib_modules=$gnulib_modules
+ gnulib_modules=`
+ (echo "$gnulib_modules"
+ for gnulib_module in $gnulib_modules; do
+ $GNULIB_SRCDIR/gnulib-tool --extract-dependencies $gnulib_module
+ done) | sort -u
+ `
+done
+
+gnulib_files=`
+ (for gnulib_module in $gnulib_modules; do
+ $GNULIB_SRCDIR/gnulib-tool --extract-filelist $gnulib_module
+ done) | sort -u
+`
+
+gnulib_dirs=`echo "$gnulib_files" | sed 's,/[^/]*$,,' | sort -u`
+mkdir -p $gnulib_dirs || exit
+
+for gnulib_file in $gnulib_files; do
+ dest=$gnulib_file
+
+ case $gnulib_file in
+ m4/codeset.m4) continue;;
+ m4/intdiv0.m4) continue;;
+ m4/inttypes-pri.m4) continue;;
+ m4/isc-posix.m4) continue;;
+ m4/lcmessage.m4) continue;;
+ m4/onceonly_2_57.m4) dest=m4/onceonly.m4;;
+ # These will be overwritten by autopoint, which still uses
+ # old jm_.* macro names, so we have to keep both copies.
+ m4/gettext.m4 | m4/glibc21.m4 | m4/inttypes_h.m4 | m4/lib-ld.m4 | \
+ m4/lib-prefix.m4 | m4/po.m4 | m4/stdint_h.m4 | m4/uintmax_t.m4 | \
+ m4/ulonglong.m4)
+ dest=`expr $gnulib_file : '\(.*\).m4'`_gl.m4;;
+ esac
+
+ rm -f $dest &&
+ echo "$0: Copying file $GNULIB_SRCDIR/$gnulib_file" &&
+ cp -p $GNULIB_SRCDIR/$gnulib_file $dest || exit
+done
+
+echo "$0: Creating m4/gnulib.m4"
+(echo "# This file is generated automatically. Please, do not edit."
+ echo "#"
+ echo "AC_DEFUN([paxutils_GNULIB],["
+ for gnulib_module in $gnulib_modules; do
+ echo "# $gnulib_module"
+ $GNULIB_SRCDIR/gnulib-tool --extract-autoconf-snippet $gnulib_module
+ done | sed '/AM_GNU_GETTEXT/d'
+ echo "])") > ./m4/gnulib.m4
+
+echo "$0: Creating lib/Makefile.am"
+(echo "# This file is generated automatically from lib/Makefile.am. Do not edit!"
+ cat lib/Makefile.tmpl
+
+ for gnulib_module in $gnulib_modules; do
+ echo "# $gnulib_module"
+ $GNULIB_SRCDIR/gnulib-tool --extract-automake-snippet $gnulib_module
+ done | sed 's/lib_SOURCES/libgnu_a_SOURCES/g' ) > lib/Makefile.am
+
+# Get translations.
+if test "$DOWNLOAD_PO" = "yes"; then
+ update_po
+fi
+
+# Reconfigure, getting other files.
+
+echo "$0: autoreconf --verbose --install --force ..."
+autoreconf --verbose --install --force || exit 1
+
+
+echo "$0: done. Now you can run './configure'."
diff --git a/build-aux/gnulib.modules b/build-aux/gnulib.modules
new file mode 100644
index 0000000..6b0b649
--- /dev/null
+++ b/build-aux/gnulib.modules
@@ -0,0 +1,17 @@
+# List of gnulib modules needed for GNU paxutils.
+# A module name per line. Empty lines and comments are ignored.
+
+argp
+savedir
+unlocked-io
+fileblocks
+error
+gettext
+inttostr
+dirname
+full-write
+getopt
+safe-read
+stdbool
+strtol
+xalloc
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..6923d0c
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,268 @@
+# This file is part of GNU paxutils
+#
+# Copyright (C) 2005 Free Software Foundation, Inc.
+#
+# GNU paxutils is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2, or (at your option) any later
+# version.
+#
+# GNU paxutils program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with GNU paxutils; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+AC_INIT([GNU paxutils], [0.0.1], [bug-paxutils@gnu.org])
+AC_CONFIG_SRCDIR([paxtest/paxtest.c])
+AC_CONFIG_AUX_DIR([build-aux])
+AC_CONFIG_HEADERS([config.h])
+AC_PREREQ([2.59])
+AM_INIT_AUTOMAKE([1.8 gnits dist-bzip2 dist-shar std-options])
+
+gl_USE_SYSTEM_EXTENSIONS
+AC_PROG_CC
+AC_EXEEXT
+AC_PROG_RANLIB
+AC_SYS_LARGEFILE
+AC_ISC_POSIX
+AC_C_INLINE
+
+AC_CHECK_HEADERS(fcntl.h linux/fd.h memory.h net/errno.h \
+ sgtty.h string.h \
+ sys/param.h sys/device.h sys/gentape.h \
+ sys/inet.h sys/io/trioctl.h \
+ sys/mtio.h sys/time.h sys/tprintf.h sys/tape.h \
+ unistd.h locale.h)
+
+AC_CHECK_HEADERS([sys/buf.h], [], [],
+[#if HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif])
+
+AC_HEADER_SYS_WAIT
+AM_STDBOOL_H
+
+AC_HEADER_DIRENT
+AC_HEADER_MAJOR
+AC_HEADER_STAT
+AC_HEADER_STDC
+AC_STRUCT_ST_BLKSIZE
+AC_STRUCT_ST_BLOCKS
+AC_MSG_CHECKING([for st_fstype string in struct stat])
+AC_CACHE_VAL(diff_cv_st_fstype_string,
+ [AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/stat.h>], [struct stat s; s.st_fstype[0] = 'x';],
+ diff_cv_st_fstype_string=yes,
+ diff_cv_st_fstype_string=no)])
+AC_MSG_RESULT($diff_cv_st_fstype_string)
+if test $diff_cv_st_fstype_string = yes; then
+ AC_DEFINE(HAVE_ST_FSTYPE_STRING, 1,
+ [Define if struct stat has a char st_fstype[] member.])
+fi
+
+AC_TYPE_SIGNAL
+AC_TYPE_MODE_T
+AC_TYPE_PID_T
+AC_TYPE_OFF_T
+AC_TYPE_SIZE_T
+AC_TYPE_UID_T
+AC_CHECK_TYPE(major_t, , AC_DEFINE(major_t, int,
+ [Type of major device numbers.]))
+AC_CHECK_TYPE(minor_t, , AC_DEFINE(minor_t, int,
+ [Type of minor device numbers.]))
+AC_CHECK_TYPE(dev_t, unsigned)
+AC_CHECK_TYPE(ino_t, unsigned)
+
+gt_TYPE_SSIZE_T
+gl_AC_TYPE_INTMAX_T
+jm_AC_TYPE_UINTMAX_T
+
+MU_DEBUG_MODE
+
+# gnulib modules
+paxutils_GNULIB
+
+PU_RMT
+PU_RTAPELIB
+PU_SYSTEM
+
+AC_CHECK_MEMBERS([struct stat.st_spare1, struct stat.st_atim.tv_nsec, struct stat.st_atimespec.tv_nsec, struct stat.st_atimensec], , ,
+ [
+#include <sys/types.h>
+#include <sys/stat.h>])
+
+# Save and restore LIBS so e.g., -lrt, isn't added to it. Otherwise, *all*
+# programs in the package would end up linked with that potentially-shared
+# library, inducing unnecessary run-time overhead.
+
+# Solaris 2.5.1 needs -lposix4 to get the clock_gettime function.
+# Solaris 7 prefers the library name -lrt to the obsolescent name -lposix4.
+tar_save_LIBS=$LIBS
+ LIB_CLOCK_GETTIME=
+ AC_SEARCH_LIBS(clock_gettime, [rt posix4])
+ case "$ac_cv_search_clock_gettime" in
+ -l*) LIB_CLOCK_GETTIME=$ac_cv_search_clock_gettime;;
+ esac
+ AC_SUBST(LIB_CLOCK_GETTIME)
+ AC_CHECK_FUNCS(clock_gettime)
+LIBS=$tar_save_LIBS
+
+AC_CHECK_FUNCS(fsync lstat mkfifo readlink strerror symlink setlocale utimes)
+AC_CHECK_DECLS([getgrgid],,, [#include <grp.h>])
+AC_CHECK_DECLS([getpwuid],,, [#include <pwd.h>])
+AC_CHECK_DECLS([time],,, [#include <time.h>])
+
+# Set LIB_SETSOCKOPT to -lnsl -lsocket if necessary.
+tar_save_LIBS=$LIBS
+ LIB_SETSOCKOPT=
+ AC_SEARCH_LIBS(setsockopt, [socket], ,
+ [AC_SEARCH_LIBS(setsockopt, [socket], , , [-lnsl])])
+ AC_SEARCH_LIBS(setsockopt, [nsl])
+
+ case "$ac_cv_search_setsockopt" in
+ -l*) LIB_SETSOCKOPT=$ac_cv_search_setsockopt
+ esac
+ AC_SUBST(LIB_SETSOCKOPT)
+LIBS=$tar_save_LIBS
+
+AC_REPLACE_FUNCS(waitpid)
+
+AC_CACHE_CHECK(for remote shell, tar_cv_path_RSH,
+ [if test -n "$RSH"; then
+ tar_cv_path_RSH=$RSH
+ else
+ tar_cv_path_RSH=no
+ for ac_file in /usr/ucb/rsh /usr/bin/remsh /usr/bin/rsh /usr/bsd/rsh \
+ /usr/bin/nsh /usr/bin/rcmd
+ do
+ # Prefer a non-symlink rsh to a symlink one, so that binaries built
+ # on AIX 4.1.4, where /usr/ucb/rsh is a symlink to /usr/bin/rsh
+ # will run on AIX 4.3.0, which has only /usr/bin/rsh.
+ if test -f $ac_file; then
+ if (test -h $ac_file) 2>/dev/null; then
+ test $tar_cv_path_RSH = no && tar_cv_path_RSH=$ac_file
+ else
+ tar_cv_path_RSH=$ac_file
+ break
+ fi
+ fi
+ done
+ fi])
+if test $tar_cv_path_RSH = no; then
+ AC_CHECK_HEADERS(netdb.h)
+else
+ AC_DEFINE_UNQUOTED(REMOTE_SHELL, "$tar_cv_path_RSH",
+ [Define to the full path of your rsh, if any.])
+fi
+
+AC_MSG_CHECKING(for default archive format)
+
+AC_ARG_VAR([DEFAULT_ARCHIVE_FORMAT],
+ [Set the default archive format. Allowed values are: V7, OLDGNU, USTAR, POSIX, GNU. Default is GNU])
+
+if test -z "$DEFAULT_ARCHIVE_FORMAT"; then
+ DEFAULT_ARCHIVE_FORMAT="GNU"
+fi
+case $DEFAULT_ARCHIVE_FORMAT in
+ V7|OLDGNU|USTAR|POSIX|GNU) ;;
+ *) AC_MSG_ERROR(Invalid format name);;
+esac
+AC_DEFINE_UNQUOTED(DEFAULT_ARCHIVE_FORMAT, ${DEFAULT_ARCHIVE_FORMAT}_FORMAT,
+ [By default produce archives of this format])
+AC_MSG_RESULT($DEFAULT_ARCHIVE_FORMAT)
+
+AC_MSG_CHECKING(for default archive)
+
+AC_ARG_VAR([DEFAULT_ARCHIVE],
+ [Set the name of the default archive (default: -)])
+if test -z "$DEFAULT_ARCHIVE"; then
+ DEFAULT_ARCHIVE=-
+else
+ if test -z "`ls $DEFAULT_ARCHIVE 2>/dev/null`"; then
+ AC_MSG_WARN(DEFAULT_ARCHIVE \`$DEFAULT_ARCHIVE' not found on this system)
+ fi
+ # FIXME: Look for DEFTAPE in <sys/mtio.h>.
+ # FIXME: Let DEVICE_PREFIX be configured from the environment.
+ # FIXME: Rearrange, here.
+ case $DEFAULT_ARCHIVE in
+ *[[0-7][lmh]])
+ AC_DEFINE(DENSITY_LETTER, 1,
+ [[Define to 1 if density may be indicated by [lmh] at end of device.]])
+ device_prefix=`echo $DEFAULT_ARCHIVE | sed 's/[0-7][lmh]$//'`
+ ;;
+ *[[0-7]])
+ device_prefix=`echo $DEFAULT_ARCHIVE | sed 's/[0-7]$//'`
+ ;;
+ *)
+ device_prefix=
+ ;;
+ esac
+ case "$device_prefix" in
+ ?*)
+ AC_DEFINE_UNQUOTED(DEVICE_PREFIX, "$device_prefix",
+ [Define to a string giving the prefix of the default device, without the part specifying the unit and density.])
+ ;;
+ esac
+fi
+AC_DEFINE_UNQUOTED(DEFAULT_ARCHIVE, "$DEFAULT_ARCHIVE",
+ [Define to a string giving the full name of the default archive file.])
+AC_MSG_RESULT($DEFAULT_ARCHIVE)
+
+AC_ARG_VAR([DEFAULT_BLOCKING],
+ [Define default blocking factor (default: 20)])
+AC_MSG_CHECKING(for default blocking)
+DEFAULT_BLOCKING=${DEFAULT_BLOCKING-20}
+AC_DEFINE_UNQUOTED(DEFAULT_BLOCKING, $DEFAULT_BLOCKING,
+ [Define to a number giving the default blocking size for archives.])
+AC_MSG_RESULT($DEFAULT_BLOCKING)
+
+# Iconv
+AM_ICONV
+AC_CHECK_HEADERS(iconv.h)
+AC_CHECK_TYPE(iconv_t,:,
+ AC_DEFINE(iconv_t, int,
+ [Conversion descriptor type]),
+ [
+#ifdef HAVE_ICONV_H
+# include <iconv.h>
+#endif
+])
+
+# Gettext.
+AM_GNU_GETTEXT([external], [need-ngettext])
+AM_GNU_GETTEXT_VERSION(0.12.1)
+
+# Initialize the test suite.
+# AC_CONFIG_TESTDIR(tests)
+# AC_CONFIG_FILES([tests/Makefile tests/atlocal])
+AM_MISSING_PROG([AUTOM4TE], [autom4te])
+
+AC_SUBST(BACKUP_LIBEXEC_SCRIPTS)
+AC_SUBST(BACKUP_SBIN_SCRIPTS)
+AC_ARG_ENABLE(backup-scripts,
+ AC_HELP_STRING([--enable-backup-scripts],
+ [Create and install backup and restore scripts]),
+ [case $enableval in
+ yes) BACKUP_LIBEXEC_SCRIPTS='$(BACKUP_LIBEXEC_SCRIPTS_LIST)'
+ BACKUP_SBIN_SCRIPTS='$(BACKUP_SBIN_SCRIPTS_LIST)'
+ ;;
+ esac])
+
+AC_SUBST(BACKUP_SED_COND)
+if date +%Y-%m-%d 2>/dev/null >&2; then
+ BACKUP_SED_COND='/^\#ELSE_DATE_FORMAT_OK/,/^\#ENDIF_DATE_FORMAT_OK/d;/^\#IF_DATE_FORMAT_OK/d'
+else
+ BACKUP_SED_COND='/^\#IF_DATE_FORMAT_OK/,/^\#ELSE_DATE_FORMAT_OK/d;/^\#ENDIF_DATE_FORMAT_OK/d'
+fi
+
+
+AC_OUTPUT([Makefile\
+ lib/Makefile\
+ paxlib/Makefile\
+ po/Makefile.in\
+ paxtest/Makefile])
+
diff --git a/lib/.cvsignore b/lib/.cvsignore
new file mode 100644
index 0000000..bbc9fcb
--- /dev/null
+++ b/lib/.cvsignore
@@ -0,0 +1,75 @@
+.deps
+Makefile
+Makefile.am
+Makefile.in
+alloca.c
+alloca.h
+alloca_.h
+argp-ba.c
+argp-eexst.c
+argp-fmtstream.c
+argp-fmtstream.h
+argp-fs-xinl.c
+argp-help.c
+argp-namefrob.h
+argp-parse.c
+argp-pv.c
+argp-pvh.c
+argp-xinl.c
+argp.h
+asnprintf.c
+basename.c
+dirname.c
+dirname.h
+error.c
+error.h
+fileblocks.c
+full-write.c
+full-write.h
+getopt.c
+getopt.h
+getopt1.c
+getopt_.h
+getopt_int.h
+gettext.h
+imaxtostr.c
+intprops.h
+inttostr.c
+inttostr.h
+mempcpy.c
+mempcpy.h
+minmax.h
+offtostr.c
+paxutils.h
+printf-args.c
+printf-args.h
+printf-parse.c
+printf-parse.h
+safe-read.c
+safe-read.h
+safe-write.c
+safe-write.h
+savedir.c
+savedir.h
+stdbool_.h
+strcase.h
+strcasecmp.c
+strchrnul.c
+strchrnul.h
+stripslash.c
+strncasecmp.c
+strndup.c
+strndup.h
+strnlen.c
+strtol.c
+sysexit_.h
+umaxtostr.c
+unlocked-io.h
+vasnprintf.c
+vasnprintf.h
+vsnprintf.c
+vsnprintf.h
+waitpid.c
+xalloc.h
+xmalloc.c
+xsize.h
diff --git a/lib/Makefile.tmpl b/lib/Makefile.tmpl
new file mode 100644
index 0000000..7ad5ced
--- /dev/null
+++ b/lib/Makefile.tmpl
@@ -0,0 +1,32 @@
+# Makefile for GNU cflow library. -*- Makefile -*-
+
+# Copyright (C) 2005 Free Software Foundation, Inc.
+
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2, or (at your option)
+## any later version.
+
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+## 02111-1307, USA.
+
+noinst_LIBRARIES = libgnu.a
+
+libgnu_a_SOURCES =
+libgnu_a_LIBADD = $(LIBOBJS) $(ALLOCA)
+libgnu_a_DEPENDENCIES = $(libgnu_a_LIBADD)
+
+BUILT_SOURCES =
+EXTRA_DIST = Makefile.tmpl
+MAINTAINERCLEANFILES =
+MOSTLYCLEANFILES =
+lib_OBJECTS = $(libgnu_a_OBJECTS)
+
+# gnulib modules
diff --git a/m4/.cvsignore b/m4/.cvsignore
new file mode 100644
index 0000000..cb68a60
--- /dev/null
+++ b/m4/.cvsignore
@@ -0,0 +1,70 @@
+alloca.m4
+argp.m4
+codeset.m4
+debug.m4
+dirname.m4
+dos.m4
+eoverflow.m4
+error.m4
+extensions.m4
+fileblocks.m4
+getopt.m4
+gettext.m4
+gettext_gl.m4
+glibc2.m4
+glibc21.m4
+glibc21_gl.m4
+gnulib.m4
+iconv.m4
+intdiv0.m4
+intmax.m4
+intmax_t.m4
+inttostr.m4
+inttypes-pri.m4
+inttypes.m4
+inttypes_h.m4
+inttypes_h_gl.m4
+isc-posix.m4
+lcmessage.m4
+lib-ld.m4
+lib-ld_gl.m4
+lib-link.m4
+lib-prefix.m4
+lib-prefix_gl.m4
+longdouble.m4
+longlong.m4
+mempcpy.m4
+nls.m4
+onceonly.m4
+po.m4
+po_gl.m4
+printf-posix.m4
+progtest.m4
+restrict.m4
+safe-read.m4
+safe-write.m4
+savedir.m4
+signed.m4
+size_max.m4
+ssize_t.m4
+stdbool.m4
+stdint_h.m4
+stdint_h_gl.m4
+strcase.m4
+strchrnul.m4
+strerror_r.m4
+strndup.m4
+strnlen.m4
+strtol.m4
+sysexits.m4
+uintmax_t.m4
+uintmax_t_gl.m4
+ulonglong.m4
+ulonglong_gl.m4
+unlocked-io.m4
+vasnprintf.m4
+vsnprintf.m4
+wchar_t.m4
+wint_t.m4
+xalloc.m4
+xsize.m4
diff --git a/paxlib/.cvsignore b/paxlib/.cvsignore
new file mode 100644
index 0000000..9c613e1
--- /dev/null
+++ b/paxlib/.cvsignore
@@ -0,0 +1,4 @@
+.deps
+Makefile
+Makefile.in
+localedir.h
diff --git a/paxlib/Makefile.am b/paxlib/Makefile.am
new file mode 100644
index 0000000..fdf9538
--- /dev/null
+++ b/paxlib/Makefile.am
@@ -0,0 +1,43 @@
+# This file is part of GNU paxutils
+#
+# Copyright (C) 2005 Free Software Foundation, Inc.
+#
+# Written by Sergey Poznyakoff
+#
+# GNU paxutils is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2, or (at your option) any later
+# version.
+#
+# GNU paxutils is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with GNU paxutils; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+INCLUDES = -I$(top_srcdir)/lib -I../ -I../lib -I../pax
+
+noinst_LIBRARIES = libpax.a
+noinst_HEADERS = tar.h paxbuf.h pax.h
+
+libpax_a_SOURCES = \
+ paxbuf.c\
+ tarbuf.c\
+ rtape.c
+
+localedir = $(datadir)/locale
+
+DISTCLEANFILES = localedir.h
+localedir.h : Makefile
+ echo '#define LOCALEDIR "$(localedir)"' >$@
+ echo "#ifndef DEFAULT_RMT_COMMAND" >> $@
+ echo "# define DEFAULT_RMT_COMMAND \"$(DEFAULT_RMT_DIR)/`echo rmt | sed '$(transform)'`$(EXEEXT)\"" >> $@
+ echo "#endif" >> $@
+
+rtapelib.o: localedir.h
+
+
+
diff --git a/paxlib/pax.h b/paxlib/pax.h
new file mode 100644
index 0000000..ce98636
--- /dev/null
+++ b/paxlib/pax.h
@@ -0,0 +1,69 @@
+/* This file is part of GNU paxutils
+
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ Written by Sergey Poznyakoff
+
+ GNU paxutils is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ GNU paxutils program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with GNU paxutils; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+struct tar_stat_info
+{
+ char *orig_file_name; /* name of file read from the archive header */
+ char *file_name; /* name of file for the current archive entry
+ after being normalized. */
+ int had_trailing_slash; /* nonzero if the current archive entry had a
+ trailing slash before it was normalized. */
+ char *link_name; /* name of link for the current archive entry. */
+
+ unsigned int devminor; /* device minor number */
+ unsigned int devmajor; /* device major number */
+ char *uname; /* user name of owner */
+ char *gname; /* group name of owner */
+ struct stat stat; /* regular filesystem stat */
+
+ /* Nanosecond parts of file timestamps (if available) */
+ unsigned long atime_nsec;
+ unsigned long mtime_nsec;
+ unsigned long ctime_nsec;
+
+ off_t archive_file_size; /* Size of file as stored in the archive.
+ Equals stat.st_size for non-sparse files */
+
+ bool is_sparse; /* Is the file sparse */
+
+ size_t sparse_map_avail; /* Index to the first unused element in
+ sparse_map array. Zero if the file is
+ not sparse */
+ size_t sparse_map_size; /* Size of the sparse map */
+ struct sp_array *sparse_map;
+};
+
+
+/* Remote device manipulations */
+int rmt_open (const char *file_name, int open_mode, int bias,
+ const char *remote_shell, const char *rmt_command);
+int rmt_close (int handle);
+size_t rmt_read (int handle, char *buffer, size_t length);
+size_t rmt_write (int handle, char *buffer, size_t length);
+off_t rmt_lseek (int handle, off_t offset, int whence);
+int rmt_ioctl (int handle, int operation, char *argument);
+
+
+/* Tar-specific functions */
+void tar_archive_create (paxbuf_t *pbuf, const char *filename,
+ int remote, int mode, size_t bfactor);
+void tar_set_rmt (paxbuf_t pbuf, const char *rmt);
+void tar_set_rsh (paxbuf_t pbuf, const char *rsh);
+
diff --git a/paxlib/paxbuf.c b/paxlib/paxbuf.c
new file mode 100644
index 0000000..b39fed7
--- /dev/null
+++ b/paxlib/paxbuf.c
@@ -0,0 +1,332 @@
+/* This file is part of GNU paxutils
+
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ Written by Sergey Poznyakoff
+
+ GNU paxutils is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ GNU paxutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with GNU paxutils; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <stdlib.h>
+#include <errno.h>
+#include <gettext.h>
+#include <system.h>
+#include <paxbuf.h>
+
+/* PAX buffer structure */
+struct pax_buffer
+{
+ size_t record_size; /* Size of a record, bytes */
+ size_t record_level; /* Number of bytes stored in the record */
+ size_t pos; /* Current position in buffer */
+ char *record; /* Record buffer, record_size bytes long */
+
+ int status; /* Return code from the latest I/O */
+
+ /* I/O functions */
+ paxbuf_io_fp writer; /* Writes data */
+ paxbuf_io_fp reader; /* Reads data */
+ paxbuf_seek_fp seek; /* Seeks the underlying transport layer */
+ /* Terminal functions */
+ paxbuf_term_fp open; /* Open a new volume */
+ paxbuf_term_fp close; /* Close the existing volume */
+ paxbuf_destroy_fp destroy; /* Destroy the closure data */
+ /* Other callbacks */
+ paxbuf_wrapper_fp wrapper; /* Called when writer or reader returns EOF */
+
+ void *closure; /* Implementation-specific data */
+ int mode; /* Working mode */
+};
+
+
+/* Default callbacks. Do nothing useful, except bailing out */
+
+static void
+noinit (const char *name)
+{
+ fprintf (stderr,
+ _("INTERNAL ERROR: %s is not initialized. Please, report.\n"),
+ name);
+ exit (1);
+}
+
+static pax_io_status_t
+default_reader (void *closure, void *data, size_t size, size_t *ret_size)
+{
+ noinit ("pax_buffer.reader");
+ return pax_io_failure;
+}
+
+static pax_io_status_t
+default_writer (void *closure, void *data, size_t size, size_t *ret_size)
+{
+ noinit ("pax_buffer.writer");
+ return pax_io_failure;
+}
+
+static int
+default_seek (void *closure, off_t offset)
+{
+ noinit ("pax_buffer.seek");
+ return -1;
+}
+
+static int
+default_open (void *closure, int mode)
+{
+ noinit ("pax_buffer.open");
+ return -1;
+}
+
+static int
+default_close (void *closure, int mode)
+{
+ noinit ("pax_buffer.close");
+ return -1;
+}
+
+static int
+default_destroy (void *closure)
+{
+ noinit ("pax_buffer.destroy");
+ return -1;
+}
+
+static int
+default_wrapper (void *closure)
+{
+ noinit ("pax_buffer.wrapper");
+ return -1;
+}
+
+static const char *
+default_error (void *closure)
+{
+ return strerror (errno);
+}
+
+
+/* Interface funtions */
+
+/* 1. Initialize/destroy */
+
+int
+paxbuf_create (paxbuf_t *pbuf, int mode, void *closure, size_t record_size)
+{
+ paxbuf_t buf;
+
+ buf = malloc (sizeof *buf);
+ if (!buf)
+ return ENOMEM;
+ buf->record = malloc (record_size);
+ if (!buf->record)
+ {
+ free (buf);
+ return ENOMEM;
+ }
+
+ buf->record_size = record_size;
+ buf->record_level = 0;
+ buf->closure = closure;
+ buf->mode = mode;
+
+ paxbuf_set_io (buf, default_reader, default_writer, default_seek);
+ paxbuf_set_term (buf, default_open, default_close, default_destroy);
+ paxbuf_set_wrapper (buf, default_wrapper);
+
+ *pbuf = buf;
+ return 0;
+}
+
+void
+paxbuf_destroy (paxbuf_t *pbuf)
+{
+ paxbuf_t buf = *pbuf;
+ free (buf->record);
+ if (buf->destroy)
+ buf->destroy (buf->closure);
+ free (buf);
+ *pbuf = NULL;
+}
+
+void
+paxbuf_set_io (paxbuf_t buf,
+ paxbuf_io_fp rd, paxbuf_io_fp wr, paxbuf_seek_fp seek)
+{
+ buf->writer = wr;
+ buf->reader = rd;
+ buf->seek = seek;
+}
+
+void
+paxbuf_set_term (paxbuf_t buf,
+ paxbuf_term_fp open, paxbuf_term_fp close,
+ paxbuf_destroy_fp destroy)
+{
+ buf->open = open;
+ buf->close = close;
+ buf->destroy = destroy;
+}
+
+void
+paxbuf_set_wrapper (paxbuf_t buf, paxbuf_wrapper_fp wrap)
+{
+ buf->wrapper = wrap;
+}
+
+
+/* 2. I/O operations and seek */
+
+static pax_io_status_t
+fill_buffer (paxbuf_t buf)
+{
+ pax_io_status_t status = pax_io_success;
+
+ buf->record_level = 0;
+ do
+ {
+ size_t s = 0;
+
+ status = buf->reader (buf->closure, buf->record + buf->record_level,
+ buf->record_size - buf->record_level, &s);
+ buf->record_level += s;
+ }
+ while ((status == pax_io_success && buf->record_level < buf->record_size)
+ || (status == pax_io_eof
+ && buf->wrapper
+ && buf->wrapper (buf->closure) == 0));
+
+ buf->pos = 0;
+ return status;
+}
+
+static pax_io_status_t
+flush_buffer (paxbuf_t buf)
+{
+ pax_io_status_t status = pax_io_success;
+
+ buf->record_level = 0;
+ do
+ {
+ size_t s = 0;
+ status = buf->writer (buf->closure, buf->record + buf->record_level,
+ buf->record_size - buf->record_level, &s);
+ buf->record_level += s;
+ }
+ while ((status == pax_io_success && buf->record_level < buf->record_size)
+ || (status == pax_io_eof
+ && buf->wrapper
+ && buf->wrapper (buf->closure) == 0));
+ buf->pos = 0;
+ return status;
+}
+
+pax_io_status_t
+paxbuf_read (paxbuf_t buf, char *data, size_t size, size_t *rsize)
+{
+ pax_io_status_t status = pax_io_success;
+
+ *rsize = 0;
+ while (size && status == pax_io_success)
+ {
+ size_t s;
+
+ if (buf->pos == buf->record_level)
+ {
+ status = fill_buffer (buf);
+ if (status == pax_io_failure)
+ break;
+ }
+ s = buf->record_level - buf->pos;
+ if (s > size)
+ s = size;
+ memcpy (data, buf->record + buf->pos, s);
+ data += s;
+ buf->pos += s;
+ size -= s;
+ *rsize += s;
+ }
+ return status;
+}
+
+pax_io_status_t
+paxbuf_write (paxbuf_t buf, char *data, size_t size, size_t *wsize)
+{
+ pax_io_status_t status = pax_io_success;
+
+ *wsize = 0;
+ while (size && status == pax_io_success)
+ {
+ size_t s;
+
+ if (buf->pos == buf->record_size)
+ {
+ status = flush_buffer (buf);
+ if (status == pax_io_failure)
+ break;
+ }
+ s = buf->record_size - buf->pos;
+ if (s > size)
+ s = size;
+ memcpy (buf->record + buf->pos, data, s);
+ data += s;
+ buf->pos += s;
+ size -= s;
+ *wsize += s;
+ }
+ return status;
+}
+
+int
+paxbuf_seek (paxbuf_t buf, off_t offset)
+{
+ /* FIXME */
+ return buf->seek (buf->closure, offset);
+}
+
+
+/* 3. Open/close */
+int
+paxbuf_open (paxbuf_t buf)
+{
+ return buf->open (buf->closure, buf->mode);
+}
+
+int
+paxbuf_close (paxbuf_t buf)
+{
+ pax_io_status_t status;
+ if ((buf->mode & PAXBUF_WRITE) && buf->pos != 0)
+ status = flush_buffer (buf);
+ return buf->close (buf->closure, buf->mode) || status != pax_io_success;
+}
+
+
+/* Accessors */
+
+void *
+paxbuf_get_data (paxbuf_t buf)
+{
+ return buf->closure;
+}
+
+int
+paxbuf_get_mode (paxbuf_t buf)
+{
+ return buf->mode;
+}
+
diff --git a/paxlib/paxbuf.h b/paxlib/paxbuf.h
new file mode 100644
index 0000000..9d057c9
--- /dev/null
+++ b/paxlib/paxbuf.h
@@ -0,0 +1,65 @@
+/* This file is part of GNU paxutils
+
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ Written by Sergey Poznyakoff
+
+ GNU paxutils is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ GNU paxutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with GNU paxutils; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+typedef struct pax_buffer *paxbuf_t;
+
+typedef enum pax_io_status
+ {
+ pax_io_success,
+ pax_io_failure,
+ pax_io_eof
+ }
+pax_io_status_t;
+
+#define PAXBUF_READ 0x1
+#define PAXBUF_WRITE 0x2
+#define PAXBUF_CREAT 0x4
+
+typedef pax_io_status_t (*paxbuf_io_fp) (void *closure,
+ void *data, size_t size,
+ size_t *ret_size);
+typedef int (*paxbuf_seek_fp) (void *closure, off_t offset);
+typedef int (*paxbuf_term_fp) (void *closure, int mode);
+typedef int (*paxbuf_destroy_fp) (void *closure);
+typedef int (*paxbuf_wrapper_fp) (void *closure);
+typedef const char * (*paxbuf_error_fp) (void *closure);
+
+int paxbuf_create (paxbuf_t *buf, int mode, void *closure, size_t record_size);
+int paxbuf_open (paxbuf_t buf);
+int paxbuf_close (paxbuf_t buf);
+void paxbuf_set_io (paxbuf_t buf, paxbuf_io_fp rd, paxbuf_io_fp wr,
+ paxbuf_seek_fp seek);
+void paxbuf_set_term (paxbuf_t buf,
+ paxbuf_term_fp open, paxbuf_term_fp close,
+ paxbuf_destroy_fp destroy);
+void paxbuf_set_wrapper (paxbuf_t buf, paxbuf_wrapper_fp wrap);
+void paxbuf_set_error (paxbuf_t buf, paxbuf_error_fp err);
+
+pax_io_status_t paxbuf_read (paxbuf_t pbuf, char *buf, size_t size,
+ size_t *rsize);
+pax_io_status_t paxbuf_write (paxbuf_t pbuf, char *buf, size_t size,
+ size_t *rsize);
+int paxbuf_seek (paxbuf_t buf, off_t offset);
+
+void paxbuf_destroy (paxbuf_t *buf);
+
+void *paxbuf_get_data (paxbuf_t buf);
+int paxbuf_get_mode (paxbuf_t buf);
+
diff --git a/paxlib/rtape.c b/paxlib/rtape.c
new file mode 100644
index 0000000..a947b59
--- /dev/null
+++ b/paxlib/rtape.c
@@ -0,0 +1,761 @@
+/* Functions for communicating with a remote tape drive.
+
+ Copyright 1988, 1992, 1994, 1996, 1997, 1999, 2000, 2001, 2004, 2005
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* The man page rmt(8) for /etc/rmt documents the remote mag tape protocol
+ which rdump and rrestore use. Unfortunately, the man page is *WRONG*.
+ The author of the routines I'm including originally wrote his code just
+ based on the man page, and it didn't work, so he went to the rdump source
+ to figure out why. The only thing he had to change was to check for the
+ 'F' return code in addition to the 'E', and to separate the various
+ arguments with \n instead of a space. I personally don't think that this
+ is much of a problem, but I wanted to point it out. -- Arnold Robbins
+
+ Originally written by Jeff Lee, modified some by Arnold Robbins. Redone
+ as a library that can replace open, read, write, etc., by Fred Fish, with
+ some additional work by Arnold Robbins. Modified to make all rmt* calls
+ into macros for speed by Jay Fenlason. Use -DWITH_REXEC for rexec
+ code, courtesy of Dan Kegel. */
+
+#include <system.h>
+#include <safe-read.h>
+#include <full-write.h>
+#include "localedir.h"
+
+/* Try hard to get EOPNOTSUPP defined. 486/ISC has it in net/errno.h,
+ 3B2/SVR3 has it in sys/inet.h. Otherwise, use ENOSYS. */
+
+#ifndef EOPNOTSUPP
+# if HAVE_NET_ERRNO_H
+# include <net/errno.h>
+# endif
+# if HAVE_SYS_INET_H
+# include <sys/inet.h>
+# endif
+# ifndef EOPNOTSUPP
+# define EOPNOTSUPP ENOSYS
+# endif
+#endif
+
+#include <signal.h>
+
+#if HAVE_NETDB_H
+# include <netdb.h>
+#endif
+
+/* Exit status if exec errors. */
+#define EXIT_ON_EXEC_ERROR 128
+
+/* FIXME: Size of buffers for reading and writing commands to rmt. */
+#define COMMAND_BUFFER_SIZE 64
+
+#ifndef RETSIGTYPE
+# define RETSIGTYPE void
+#endif
+
+/* FIXME: Maximum number of simultaneous remote tape connections. */
+#define MAXUNIT 4
+
+#define PREAD 0 /* read file descriptor from pipe() */
+#define PWRITE 1 /* write file descriptor from pipe() */
+
+/* Return the parent's read side of remote tape connection Fd. */
+#define READ_SIDE(Fd) (from_remote[Fd][PREAD])
+
+/* Return the parent's write side of remote tape connection Fd. */
+#define WRITE_SIDE(Fd) (to_remote[Fd][PWRITE])
+
+/* The pipes for receiving data from remote tape drives. */
+static int from_remote[MAXUNIT][2] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}};
+
+/* The pipes for sending data to remote tape drives. */
+static int to_remote[MAXUNIT][2] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}};
+
+
+
+/* Close remote tape connection HANDLE, and reset errno to ERRNO_VALUE. */
+static void
+_rmt_shutdown (int handle, int errno_value)
+{
+ close (READ_SIDE (handle));
+ close (WRITE_SIDE (handle));
+ READ_SIDE (handle) = -1;
+ WRITE_SIDE (handle) = -1;
+ errno = errno_value;
+}
+
+/* Attempt to perform the remote tape command specified in BUFFER on
+ remote tape connection HANDLE. Return 0 if successful, -1 on
+ error. */
+static int
+do_command (int handle, const char *buffer)
+{
+ /* Save the current pipe handler and try to make the request. */
+
+ size_t length = strlen (buffer);
+ RETSIGTYPE (*pipe_handler) () = signal (SIGPIPE, SIG_IGN);
+ ssize_t written = full_write (WRITE_SIDE (handle), buffer, length);
+ signal (SIGPIPE, pipe_handler);
+
+ if (written == length)
+ return 0;
+
+ /* Something went wrong. Close down and go home. */
+
+ _rmt_shutdown (handle, EIO);
+ return -1;
+}
+
+static char *
+get_status_string (int handle, char *command_buffer)
+{
+ char *cursor;
+ int i;
+
+ /* Read the reply command line. */
+
+ for (i = 0, cursor = command_buffer; i < COMMAND_BUFFER_SIZE; i++, cursor++)
+ {
+ if (safe_read (READ_SIDE (handle), cursor, 1) != 1)
+ {
+ _rmt_shutdown (handle, EIO);
+ return 0;
+ }
+ if (*cursor == '\n')
+ {
+ *cursor = '\0';
+ break;
+ }
+ }
+
+ if (i == COMMAND_BUFFER_SIZE)
+ {
+ _rmt_shutdown (handle, EIO);
+ return 0;
+ }
+
+ /* Check the return status. */
+
+ for (cursor = command_buffer; *cursor; cursor++)
+ if (*cursor != ' ')
+ break;
+
+ if (*cursor == 'E' || *cursor == 'F')
+ {
+ /* Skip the error message line. */
+
+ /* FIXME: there is better to do than merely ignoring error messages
+ coming from the remote end. Translate them, too... */
+
+ {
+ char character;
+
+ while (safe_read (READ_SIDE (handle), &character, 1) == 1)
+ if (character == '\n')
+ break;
+ }
+
+ errno = atoi (cursor + 1);
+
+ if (*cursor == 'F')
+ _rmt_shutdown (handle, errno);
+
+ return 0;
+ }
+
+ /* Check for mis-synced pipes. */
+
+ if (*cursor != 'A')
+ {
+ _rmt_shutdown (handle, EIO);
+ return 0;
+ }
+
+ /* Got an `A' (success) response. */
+
+ return cursor + 1;
+}
+
+/* Read and return the status from remote tape connection HANDLE. If
+ an error occurred, return -1 and set errno. */
+static long int
+get_status (int handle)
+{
+ char command_buffer[COMMAND_BUFFER_SIZE];
+ const char *status = get_status_string (handle, command_buffer);
+ if (status)
+ {
+ long int result = atol (status);
+ if (0 <= result)
+ return result;
+ errno = EIO;
+ }
+ return -1;
+}
+
+static off_t
+get_status_off (int handle)
+{
+ char command_buffer[COMMAND_BUFFER_SIZE];
+ const char *status = get_status_string (handle, command_buffer);
+
+ if (!status)
+ return -1;
+ else
+ {
+ /* Parse status, taking care to check for overflow.
+ We can't use standard functions,
+ since off_t might be longer than long. */
+
+ off_t count = 0;
+ int negative;
+
+ for (; *status == ' ' || *status == '\t'; status++)
+ continue;
+
+ negative = *status == '-';
+ status += negative || *status == '+';
+
+ for (;;)
+ {
+ int digit = *status++ - '0';
+ if (9 < (unsigned) digit)
+ break;
+ else
+ {
+ off_t c10 = 10 * count;
+ off_t nc = negative ? c10 - digit : c10 + digit;
+ if (c10 / 10 != count || (negative ? c10 < nc : nc < c10))
+ return -1;
+ count = nc;
+ }
+ }
+
+ return count;
+ }
+}
+
+#if WITH_REXEC
+
+/* Execute /etc/rmt as user USER on remote system HOST using rexec.
+ Return a file descriptor of a bidirectional socket for stdin and
+ stdout. If USER is zero, use the current username.
+
+ By default, this code is not used, since it requires that the user
+ have a .netrc file in his/her home directory, or that the
+ application designer be willing to have rexec prompt for login and
+ password info. This may be unacceptable, and .rhosts files for use
+ with rsh are much more common on BSD systems. */
+static int
+_rmt_rexec (char *host, char *user, char *rmt_command)
+{
+ int saved_stdin = dup (STDIN_FILENO);
+ int saved_stdout = dup (STDOUT_FILENO);
+ struct servent *rexecserv;
+ int result;
+
+ /* When using cpio -o < filename, stdin is no longer the tty. But the
+ rexec subroutine reads the login and the passwd on stdin, to allow
+ remote execution of the command. So, reopen stdin and stdout on
+ /dev/tty before the rexec and give them back their original value
+ after. */
+
+ if (! freopen ("/dev/tty", "r", stdin))
+ freopen ("/dev/null", "r", stdin);
+ if (! freopen ("/dev/tty", "w", stdout))
+ freopen ("/dev/null", "w", stdout);
+
+ if (rexecserv = getservbyname ("exec", "tcp"), !rexecserv)
+ error (EXIT_ON_EXEC_ERROR, 0, _("exec/tcp: Service not available"));
+
+ result = rexec (&host, rexecserv->s_port, user, 0, rmt_command, 0);
+ if (fclose (stdin) == EOF)
+ error (0, errno, _("stdin"));
+ fdopen (saved_stdin, "r");
+ if (fclose (stdout) == EOF)
+ error (0, errno, _("stdout"));
+ fdopen (saved_stdout, "w");
+
+ return result;
+}
+
+#endif /* WITH_REXEC */
+
+/* Place into BUF a string representing OFLAG, which must be suitable
+ as argument 2 of `open'. BUF must be large enough to hold the
+ result. This function should generate a string that decode_oflag
+ can parse. */
+static void
+encode_oflag (char *buf, int oflag)
+{
+ sprintf (buf, "%d ", oflag);
+
+ switch (oflag & O_ACCMODE)
+ {
+ case O_RDONLY:
+ strcat (buf, "O_RDONLY");
+ break;
+
+ case O_RDWR:
+ strcat (buf, "O_RDWR");
+ break;
+
+ case O_WRONLY:
+ strcat (buf, "O_WRONLY");
+ break;
+
+ default:
+ abort ();
+ }
+
+#ifdef O_APPEND
+ if (oflag & O_APPEND)
+ strcat (buf, "|O_APPEND");
+#endif
+ if (oflag & O_CREAT)
+ strcat (buf, "|O_CREAT");
+#ifdef O_DSYNC
+ if (oflag & O_DSYNC)
+ strcat (buf, "|O_DSYNC");
+#endif
+ if (oflag & O_EXCL)
+ strcat (buf, "|O_EXCL");
+#ifdef O_LARGEFILE
+ if (oflag & O_LARGEFILE)
+ strcat (buf, "|O_LARGEFILE");
+#endif
+#ifdef O_NOCTTY
+ if (oflag & O_NOCTTY)
+ strcat (buf, "|O_NOCTTY");
+#endif
+#ifdef O_NONBLOCK
+ if (oflag & O_NONBLOCK)
+ strcat (buf, "|O_NONBLOCK");
+#endif
+#ifdef O_RSYNC
+ if (oflag & O_RSYNC)
+ strcat (buf, "|O_RSYNC");
+#endif
+#ifdef O_SYNC
+ if (oflag & O_SYNC)
+ strcat (buf, "|O_SYNC");
+#endif
+ if (oflag & O_TRUNC)
+ strcat (buf, "|O_TRUNC");
+}
+
+/* Open a remote file on the system specified in FILE_NAME, as the given user.
+ FILE_NAME has the form `[USER@]HOST:FILE'.
+ OPEN_MODE is O_RDONLY, O_WRONLY, etc. If successful, return the
+ remote pipe number plus BIAS. REMOTE_SHELL may be overridden. On
+ error, return -1. */
+int
+rmt_open (const char *file_name, int open_mode, int bias,
+ const char *remote_shell, const char *rmt_command)
+{
+ int remote_pipe_number; /* pseudo, biased file descriptor */
+ char *file_name_copy; /* copy of file_name string */
+ char *remote_host; /* remote host name */
+ char *remote_file; /* remote file name (often a device) */
+ char *remote_user; /* remote user name */
+
+ /* Find an unused pair of file descriptors. */
+
+ for (remote_pipe_number = 0;
+ remote_pipe_number < MAXUNIT;
+ remote_pipe_number++)
+ if (READ_SIDE (remote_pipe_number) == -1
+ && WRITE_SIDE (remote_pipe_number) == -1)
+ break;
+
+ if (remote_pipe_number == MAXUNIT)
+ {
+ errno = EMFILE;
+ return -1;
+ }
+
+ /* Pull apart the system and device, and optional user. */
+
+ {
+ char *cursor;
+
+ file_name_copy = xstrdup (file_name);
+ remote_host = file_name_copy;
+ remote_user = 0;
+ remote_file = 0;
+
+ for (cursor = file_name_copy; *cursor; cursor++)
+ switch (*cursor)
+ {
+ default:
+ break;
+
+ case '\n':
+ /* Do not allow newlines in the file_name, since the protocol
+ uses newline delimiters. */
+ free (file_name_copy);
+ errno = ENOENT;
+ return -1;
+
+ case '@':
+ if (!remote_user)
+ {
+ remote_user = remote_host;
+ *cursor = '\0';
+ remote_host = cursor + 1;
+ }
+ break;
+
+ case ':':
+ if (!remote_file)
+ {
+ *cursor = '\0';
+ remote_file = cursor + 1;
+ }
+ break;
+ }
+ }
+
+ /* FIXME: Should somewhat validate the decoding, here. */
+
+ if (remote_user && *remote_user == '\0')
+ remote_user = 0;
+
+#if WITH_REXEC
+
+ /* Execute the remote command using rexec. */
+
+ READ_SIDE (remote_pipe_number) = _rmt_rexec (remote_host, remote_user);
+ if (READ_SIDE (remote_pipe_number) < 0)
+ {
+ int e = errno;
+ free (file_name_copy);
+ errno = e;
+ return -1;
+ }
+
+ WRITE_SIDE (remote_pipe_number) = READ_SIDE (remote_pipe_number);
+
+#else /* not WITH_REXEC */
+ {
+ const char *remote_shell_basename;
+ pid_t status;
+
+ /* Identify the remote command to be executed. */
+
+ if (!remote_shell)
+ {
+#ifdef REMOTE_SHELL
+ remote_shell = REMOTE_SHELL;
+#else
+ free (file_name_copy);
+ errno = EINVAL;
+ return -1;
+#endif
+ }
+ remote_shell_basename = base_name (remote_shell);
+
+ /* Set up the pipes for the `rsh' command, and fork. */
+
+ if (pipe (to_remote[remote_pipe_number]) == -1
+ || pipe (from_remote[remote_pipe_number]) == -1)
+ {
+ int e = errno;
+ free (file_name_copy);
+ errno = e;
+ return -1;
+ }
+
+ status = fork ();
+ if (status == -1)
+ {
+ int e = errno;
+ free (file_name_copy);
+ errno = e;
+ return -1;
+ }
+
+ if (status == 0)
+ {
+ /* Child. */
+
+ close (STDIN_FILENO);
+ dup (to_remote[remote_pipe_number][PREAD]);
+ close (to_remote[remote_pipe_number][PREAD]);
+ close (to_remote[remote_pipe_number][PWRITE]);
+
+ close (STDOUT_FILENO);
+ dup (from_remote[remote_pipe_number][PWRITE]);
+ close (from_remote[remote_pipe_number][PREAD]);
+ close (from_remote[remote_pipe_number][PWRITE]);
+
+ sys_reset_uid_gid ();
+
+ if (!rmt_command)
+ rmt_command = DEFAULT_RMT_COMMAND;
+
+ if (remote_user)
+ execl (remote_shell, remote_shell_basename, remote_host,
+ "-l", remote_user, rmt_command, (char *) 0);
+ else
+ execl (remote_shell, remote_shell_basename, remote_host,
+ rmt_command, (char *) 0);
+
+ /* Bad problems if we get here. */
+
+ /* In a previous version, _exit was used here instead of exit. */
+ error (EXIT_ON_EXEC_ERROR, errno, _("Cannot execute remote shell"));
+ }
+
+ /* Parent. */
+
+ close (from_remote[remote_pipe_number][PWRITE]);
+ close (to_remote[remote_pipe_number][PREAD]);
+ }
+#endif /* not WITH_REXEC */
+
+ /* Attempt to open the tape device. */
+
+ {
+ size_t remote_file_len = strlen (remote_file);
+ char *command_buffer = xmalloc (remote_file_len + 1000);
+ sprintf (command_buffer, "O%s\n", remote_file);
+ encode_oflag (command_buffer + remote_file_len + 2, open_mode);
+ strcat (command_buffer, "\n");
+ if (do_command (remote_pipe_number, command_buffer) == -1
+ || get_status (remote_pipe_number) == -1)
+ {
+ int e = errno;
+ free (command_buffer);
+ free (file_name_copy);
+ _rmt_shutdown (remote_pipe_number, e);
+ return -1;
+ }
+ free (command_buffer);
+ }
+
+ free (file_name_copy);
+ return remote_pipe_number + bias;
+}
+
+/* Close remote tape connection HANDLE and shut down. Return 0 if
+ successful, -1 on error. */
+int
+rmt_close (int handle)
+{
+ long int status;
+
+ if (do_command (handle, "C\n") == -1)
+ return -1;
+
+ status = get_status (handle);
+ _rmt_shutdown (handle, errno);
+ return status;
+}
+
+/* Read up to LENGTH bytes into BUFFER from remote tape connection HANDLE.
+ Return the number of bytes read on success, SAFE_READ_ERROR on error. */
+size_t
+rmt_read (int handle, char *buffer, size_t length)
+{
+ char command_buffer[COMMAND_BUFFER_SIZE];
+ size_t status;
+ size_t rlen;
+ size_t counter;
+
+ sprintf (command_buffer, "R%lu\n", (unsigned long) length);
+ if (do_command (handle, command_buffer) == -1
+ || (status = get_status (handle)) == SAFE_READ_ERROR)
+ return SAFE_READ_ERROR;
+
+ for (counter = 0; counter < status; counter += rlen, buffer += rlen)
+ {
+ rlen = safe_read (READ_SIDE (handle), buffer, status - counter);
+ if (rlen == SAFE_READ_ERROR || rlen == 0)
+ {
+ _rmt_shutdown (handle, EIO);
+ return SAFE_READ_ERROR;
+ }
+ }
+
+ return status;
+}
+
+/* Write LENGTH bytes from BUFFER to remote tape connection HANDLE.
+ Return the number of bytes written. */
+size_t
+rmt_write (int handle, char *buffer, size_t length)
+{
+ char command_buffer[COMMAND_BUFFER_SIZE];
+ RETSIGTYPE (*pipe_handler) ();
+ size_t written;
+
+ sprintf (command_buffer, "W%lu\n", (unsigned long) length);
+ if (do_command (handle, command_buffer) == -1)
+ return 0;
+
+ pipe_handler = signal (SIGPIPE, SIG_IGN);
+ written = full_write (WRITE_SIDE (handle), buffer, length);
+ signal (SIGPIPE, pipe_handler);
+ if (written == length)
+ {
+ long int r = get_status (handle);
+ if (r < 0)
+ return 0;
+ if (r == length)
+ return length;
+ written = r;
+ }
+
+ /* Write error. */
+
+ _rmt_shutdown (handle, EIO);
+ return written;
+}
+
+/* Perform an imitation lseek operation on remote tape connection
+ HANDLE. Return the new file offset if successful, -1 if on error. */
+off_t
+rmt_lseek (int handle, off_t offset, int whence)
+{
+ char command_buffer[COMMAND_BUFFER_SIZE];
+ char operand_buffer[UINTMAX_STRSIZE_BOUND];
+ uintmax_t u = offset < 0 ? - (uintmax_t) offset : (uintmax_t) offset;
+ char *p = operand_buffer + sizeof operand_buffer;
+
+ *--p = 0;
+ do
+ *--p = '0' + (int) (u % 10);
+ while ((u /= 10) != 0);
+ if (offset < 0)
+ *--p = '-';
+
+ switch (whence)
+ {
+ case SEEK_SET:
+ whence = 0;
+ break;
+
+ case SEEK_CUR:
+ whence = 1;
+ break;
+
+ case SEEK_END:
+ whence = 2;
+ break;
+
+ default:
+ abort ();
+ }
+
+ sprintf (command_buffer, "L%s\n%d\n", p, whence);
+
+ if (do_command (handle, command_buffer) == -1)
+ return -1;
+
+ return get_status_off (handle);
+}
+
+/* Perform a raw tape operation on remote tape connection HANDLE.
+ Return the results of the ioctl, or -1 on error. */
+int
+rmt_ioctl (int handle, int operation, char *argument)
+{
+ switch (operation)
+ {
+ default:
+ errno = EOPNOTSUPP;
+ return -1;
+
+#ifdef MTIOCTOP
+ case MTIOCTOP:
+ {
+ char command_buffer[COMMAND_BUFFER_SIZE];
+ char operand_buffer[UINTMAX_STRSIZE_BOUND];
+ uintmax_t u = (((struct mtop *) argument)->mt_count < 0
+ ? - (uintmax_t) ((struct mtop *) argument)->mt_count
+ : (uintmax_t) ((struct mtop *) argument)->mt_count);
+ char *p = operand_buffer + sizeof operand_buffer;
+
+ *--p = 0;
+ do
+ *--p = '0' + (int) (u % 10);
+ while ((u /= 10) != 0);
+ if (((struct mtop *) argument)->mt_count < 0)
+ *--p = '-';
+
+ /* MTIOCTOP is the easy one. Nothing is transferred in binary. */
+
+ sprintf (command_buffer, "I%d\n%s\n",
+ ((struct mtop *) argument)->mt_op, p);
+ if (do_command (handle, command_buffer) == -1)
+ return -1;
+
+ return get_status (handle);
+ }
+#endif /* MTIOCTOP */
+
+#ifdef MTIOCGET
+ case MTIOCGET:
+ {
+ ssize_t status;
+ size_t counter;
+
+ /* Grab the status and read it directly into the structure. This
+ assumes that the status buffer is not padded and that 2 shorts
+ fit in a long without any word alignment problems; i.e., the
+ whole struct is contiguous. NOTE - this is probably NOT a good
+ assumption. */
+
+ if (do_command (handle, "S") == -1
+ || (status = get_status (handle), status == -1))
+ return -1;
+
+ for (; status > 0; status -= counter, argument += counter)
+ {
+ counter = safe_read (READ_SIDE (handle), argument, status);
+ if (counter == SAFE_READ_ERROR || counter == 0)
+ {
+ _rmt_shutdown (handle, EIO);
+ return -1;
+ }
+ }
+
+ /* Check for byte position. mt_type (or mt_model) is a small integer
+ field (normally) so we will check its magnitude. If it is larger
+ than 256, we will assume that the bytes are swapped and go through
+ and reverse all the bytes. */
+
+ if (((struct mtget *) argument)->MTIO_CHECK_FIELD < 256)
+ return 0;
+
+ for (counter = 0; counter < status; counter += 2)
+ {
+ char copy = argument[counter];
+
+ argument[counter] = argument[counter + 1];
+ argument[counter + 1] = copy;
+ }
+
+ return 0;
+ }
+#endif /* MTIOCGET */
+
+ }
+}
+
diff --git a/paxlib/tar.h b/paxlib/tar.h
new file mode 100644
index 0000000..059287d
--- /dev/null
+++ b/paxlib/tar.h
@@ -0,0 +1,279 @@
+/* GNU tar Archive Format description.
+
+ Copyright (C) 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
+ 2000, 2001, 2003 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* tar Header Block, from POSIX 1003.1-1990. */
+
+/* POSIX header. */
+
+struct posix_header
+{ /* byte offset */
+ char name[100]; /* 0 */
+ char mode[8]; /* 100 */
+ char uid[8]; /* 108 */
+ char gid[8]; /* 116 */
+ char size[12]; /* 124 */
+ char mtime[12]; /* 136 */
+ char chksum[8]; /* 148 */
+ char typeflag; /* 156 */
+ char linkname[100]; /* 157 */
+ char magic[6]; /* 257 */
+ char version[2]; /* 263 */
+ char uname[32]; /* 265 */
+ char gname[32]; /* 297 */
+ char devmajor[8]; /* 329 */
+ char devminor[8]; /* 337 */
+ char prefix[155]; /* 345 */
+ /* 500 */
+};
+
+#define TMAGIC "ustar" /* ustar and a null */
+#define TMAGLEN 6
+#define TVERSION "00" /* 00 and no null */
+#define TVERSLEN 2
+
+/* Values used in typeflag field. */
+#define REGTYPE '0' /* regular file */
+#define AREGTYPE '\0' /* regular file */
+#define LNKTYPE '1' /* link */
+#define SYMTYPE '2' /* reserved */
+#define CHRTYPE '3' /* character special */
+#define BLKTYPE '4' /* block special */
+#define DIRTYPE '5' /* directory */
+#define FIFOTYPE '6' /* FIFO special */
+#define CONTTYPE '7' /* reserved */
+
+#define XHDTYPE 'x' /* Extended header referring to the
+ next file in the archive */
+#define XGLTYPE 'g' /* Global extended header */
+
+/* Bits used in the mode field, values in octal. */
+#define TSUID 04000 /* set UID on execution */
+#define TSGID 02000 /* set GID on execution */
+#define TSVTX 01000 /* reserved */
+ /* file permissions */
+#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 */
+
+/* tar Header Block, GNU extensions. */
+
+/* In GNU tar, SYMTYPE is for to symbolic links, and CONTTYPE is for
+ contiguous files, so maybe disobeying the `reserved' comment in POSIX
+ header description. I suspect these were meant to be used this way, and
+ should not have really been `reserved' in the published standards. */
+
+/* *BEWARE* *BEWARE* *BEWARE* that the following information is still
+ boiling, and may change. Even if the OLDGNU format description should be
+ accurate, the so-called GNU format is not yet fully decided. It is
+ surely meant to use only extensions allowed by POSIX, but the sketch
+ below repeats some ugliness from the OLDGNU format, which should rather
+ go away. Sparse files should be saved in such a way that they do *not*
+ require two passes at archive creation time. Huge files get some POSIX
+ fields to overflow, alternate solutions have to be sought for this. */
+
+/* Descriptor for a single file hole. */
+
+struct sparse
+{ /* byte offset */
+ char offset[12]; /* 0 */
+ char numbytes[12]; /* 12 */
+ /* 24 */
+};
+
+/* Sparse files are not supported in POSIX ustar format. For sparse files
+ with a POSIX header, a GNU extra header is provided which holds overall
+ sparse information and a few sparse descriptors. When an old GNU header
+ replaces both the POSIX header and the GNU extra header, it holds some
+ sparse descriptors too. Whether POSIX or not, if more sparse descriptors
+ are still needed, they are put into as many successive sparse headers as
+ necessary. The following constants tell how many sparse descriptors fit
+ in each kind of header able to hold them. */
+
+#define SPARSES_IN_EXTRA_HEADER 16
+#define SPARSES_IN_OLDGNU_HEADER 4
+#define SPARSES_IN_SPARSE_HEADER 21
+
+/* Extension header for sparse files, used immediately after the GNU extra
+ header, and used only if all sparse information cannot fit into that
+ extra header. There might even be many such extension headers, one after
+ the other, until all sparse information has been recorded. */
+
+struct sparse_header
+{ /* byte offset */
+ struct sparse sp[SPARSES_IN_SPARSE_HEADER];
+ /* 0 */
+ char isextended; /* 504 */
+ /* 505 */
+};
+
+/* The old GNU format header conflicts with POSIX format in such a way that
+ POSIX archives may fool old GNU tar's, and POSIX tar's might well be
+ fooled by old GNU tar archives. An old GNU format header uses the space
+ used by the prefix field in a POSIX header, and cumulates information
+ normally found in a GNU extra header. With an old GNU tar header, we
+ never see any POSIX header nor GNU extra header. Supplementary sparse
+ headers are allowed, however. */
+
+struct oldgnu_header
+{ /* byte offset */
+ char unused_pad1[345]; /* 0 */
+ char atime[12]; /* 345 Incr. archive: atime of the file */
+ char ctime[12]; /* 357 Incr. archive: ctime of the file */
+ char offset[12]; /* 369 Multivolume archive: the offset of
+ the start of this volume */
+ char longnames[4]; /* 381 Not used */
+ char unused_pad2; /* 385 */
+ struct sparse sp[SPARSES_IN_OLDGNU_HEADER];
+ /* 386 */
+ char isextended; /* 482 Sparse file: Extension sparse header
+ follows */
+ char realsize[12]; /* 483 Sparse file: Real size*/
+ /* 495 */
+};
+
+/* OLDGNU_MAGIC uses both magic and version fields, which are contiguous.
+ Found in an archive, it indicates an old GNU header format, which will be
+ hopefully become obsolescent. With OLDGNU_MAGIC, uname and gname are
+ valid, though the header is not truly POSIX conforming. */
+#define OLDGNU_MAGIC "ustar " /* 7 chars and a null */
+
+/* The standards committee allows only capital A through capital Z for
+ user-defined expansion. Other letters in use include:
+
+ 'A' Solaris Access Control List
+ 'E' Solaris Extended Attribute File
+ 'I' Inode only, as in 'star'
+ 'X' POSIX 1003.1-2001 eXtended (VU version) */
+
+/* This is a dir entry that contains the names of files that were in the
+ dir at the time the dump was made. */
+#define GNUTYPE_DUMPDIR 'D'
+
+/* Identifies the *next* file on the tape as having a long linkname. */
+#define GNUTYPE_LONGLINK 'K'
+
+/* Identifies the *next* file on the tape as having a long name. */
+#define GNUTYPE_LONGNAME 'L'
+
+/* This is the continuation of a file that began on another volume. */
+#define GNUTYPE_MULTIVOL 'M'
+
+/* For storing filenames that do not fit into the main header. */
+#define GNUTYPE_NAMES 'N'
+
+/* This is for sparse files. */
+#define GNUTYPE_SPARSE 'S'
+
+/* This file is a tape/volume header. Ignore it on extraction. */
+#define GNUTYPE_VOLHDR 'V'
+
+
+/* Jörg Schilling star header */
+
+struct star_header
+{ /* byte offset */
+ char name[100]; /* 0 */
+ char mode[8]; /* 100 */
+ char uid[8]; /* 108 */
+ char gid[8]; /* 116 */
+ char size[12]; /* 124 */
+ char mtime[12]; /* 136 */
+ char chksum[8]; /* 148 */
+ char typeflag; /* 156 */
+ char linkname[100]; /* 157 */
+ char magic[6]; /* 257 */
+ char version[2]; /* 263 */
+ char uname[32]; /* 265 */
+ char gname[32]; /* 297 */
+ char devmajor[8]; /* 329 */
+ char devminor[8]; /* 337 */
+ char prefix[131]; /* 345 */
+ char atime[12]; /* 476 */
+ char ctime[12]; /* 488 */
+ /* 500 */
+};
+
+#define SPARSES_IN_STAR_HEADER 4
+#define SPARSES_IN_STAR_EXT_HEADER 21
+
+struct star_in_header {
+ char fill[345]; /* 0 Everything that is before t_prefix */
+ char prefix[1]; /* 345 t_name prefix */
+ char fill2; /* 346 */
+ char fill3[8]; /* 347 */
+ char isextended; /* 355 */
+ struct sparse sp[SPARSES_IN_STAR_HEADER]; /* 356 */
+ char realsize[12]; /* 452 Actual size of the file */
+ char offset[12]; /* 464 Offset of multivolume contents */
+ char atime[12]; /* 476 */
+ char ctime[12]; /* 488 */
+ char mfill[8]; /* 500 */
+ char xmagic[4]; /* 508 "tar" */
+};
+
+struct star_ext_header {
+ struct sparse sp[SPARSES_IN_STAR_EXT_HEADER];
+ char isextended;
+};
+
+
+
+/* tar Header Block, overall structure. */
+
+/* tar files are made in basic blocks of this size. */
+#define BLOCKSIZE 512
+
+enum archive_format
+{
+ DEFAULT_FORMAT, /* format to be decided later */
+ V7_FORMAT, /* old V7 tar format */
+ OLDGNU_FORMAT, /* GNU format as per before tar 1.12 */
+ USTAR_FORMAT, /* POSIX.1-1988 (ustar) format */
+ POSIX_FORMAT, /* POSIX.1-2001 format */
+ STAR_FORMAT, /* Star format defined in 1994 */
+ GNU_FORMAT /* Same as OLDGNU_FORMAT with one exception:
+ see FIXME note for to_chars() function
+ (create.c:189) */
+};
+
+/* Information about a sparse file. */
+struct sp_array
+ {
+ off_t offset;
+ size_t numbytes;
+ };
+
+union block
+{
+ char buffer[BLOCKSIZE];
+ struct posix_header header;
+ struct star_header star_header;
+ struct oldgnu_header oldgnu_header;
+ struct sparse_header sparse_header;
+ struct star_in_header star_in_header;
+ struct star_ext_header star_ext_header;
+};
+
+/* End of Format description. */
diff --git a/paxlib/tarbuf.c b/paxlib/tarbuf.c
new file mode 100644
index 0000000..9fa911a
--- /dev/null
+++ b/paxlib/tarbuf.c
@@ -0,0 +1,218 @@
+/* This file is part of GNU paxutils
+
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ Written by Sergey Poznyakoff
+
+ GNU paxutils is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ GNU paxutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with GNU paxutils; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <system.h>
+#include <safe-read.h>
+#include <safe-write.h>
+#include <paxbuf.h>
+#include <pax.h>
+#include <tar.h>
+
+typedef struct tar_archive
+{
+ char *filename; /* Name of the archive file */
+ int fd; /* Archive file descriptor */
+ int bfactor; /* Number of blocks in a record */
+ const char *rsh; /* Full pathname of rsh */
+ const char *rmt; /* Full pathname of the remote command */
+}
+tar_archive_t;
+
+
+/* Operations on local files */
+
+static pax_io_status_t
+local_reader (void *closure, void *data, size_t size, size_t *ret_size)
+{
+ tar_archive_t *tar = closure;
+ ssize_t s;
+
+ s = read (tar->fd, data, size);
+ if (s == -1)
+ return pax_io_failure;
+ if (s == 0)
+ return pax_io_eof;
+ *ret_size = s;
+ return pax_io_success;
+}
+
+static pax_io_status_t
+local_writer (void *closure, void *data, size_t size, size_t *ret_size)
+{
+ tar_archive_t *tar = closure;
+ ssize_t s;
+
+ s = write (tar->fd, data, size);
+ if (s == -1)
+ return pax_io_failure;
+ *ret_size = s;
+ return pax_io_success;
+}
+
+static int
+local_seek (void *closure, off_t offset)
+{
+ tar_archive_t *tar = closure;
+ off_t off;
+
+ off = lseek (tar->fd, offset, SEEK_SET);
+ if (off == -1)
+ return pax_io_failure;
+ return pax_io_success;
+}
+
+static int
+local_open (void *closure, int pax_mode)
+{
+ tar_archive_t *tar = closure;
+ int mode = (pax_mode & PAXBUF_READ) ? O_RDONLY :
+ O_RDWR | ((pax_mode & PAXBUF_CREAT) ? O_CREAT : 0);
+ tar->fd = open (tar->filename, mode, MODE_RW);
+ if (tar->fd == -1)
+ return pax_io_failure;
+ return pax_io_success;
+}
+
+static int
+local_close (void *closure, int mode)
+{
+ tar_archive_t *tar = closure;
+ close (tar->fd);
+ tar->fd = -1;
+ return 0;
+}
+
+
+/* Operations on remote files */
+static pax_io_status_t
+remote_reader (void *closure, void *data, size_t size, size_t *ret_size)
+{
+ tar_archive_t *tar = closure;
+ size_t s;
+
+ s = rmt_read (tar->fd, data, size);
+ if (s == SAFE_READ_ERROR)
+ return pax_io_failure;
+ if (s == 0)
+ return pax_io_eof;
+ *ret_size = s;
+ return pax_io_success;
+}
+
+static pax_io_status_t
+remote_writer (void *closure, void *data, size_t size, size_t *ret_size)
+{
+ tar_archive_t *tar = closure;
+ size_t s;
+
+ s = rmt_write (tar->fd, data, size);
+ if (s == SAFE_WRITE_ERROR)
+ return pax_io_failure;
+ *ret_size = s;
+ return pax_io_success;
+}
+
+static int
+remote_seek (void *closure, off_t offset)
+{
+ tar_archive_t *tar = closure;
+ off_t off = rmt_lseek (tar->fd, offset, SEEK_SET);
+ if (off == -1)
+ return pax_io_failure;
+ return pax_io_success;
+}
+
+static int
+remote_open (void *closure, int pax_mode)
+{
+ tar_archive_t *tar = closure;
+ int mode = (pax_mode & PAXBUF_READ) ? O_RDONLY :
+ O_RDWR | ((pax_mode & PAXBUF_CREAT) ? O_CREAT : 0);
+ tar->fd = rmt_open (tar->filename, mode, 0, tar->rsh, tar->rmt);
+ if (tar->fd == -1)
+ return pax_io_failure;
+ return pax_io_success;
+}
+
+static int
+remote_close (void *closure, int mode)
+{
+ tar_archive_t *tar = closure;
+ int rc = rmt_close (tar->fd);
+ tar->fd = -1;
+ return rc;
+}
+
+
+static int
+tar_destroy (void *closure)
+{
+ tar_archive_t *tar = closure;
+ free (tar->filename);
+ free (tar);
+ return 0;
+}
+
+static int
+tar_wrapper (void *closure)
+{
+ return 1;
+}
+
+void
+tar_archive_create (paxbuf_t *pbuf, const char *filename,
+ int remote, int mode, size_t bfactor)
+{
+ tar_archive_t *tar;
+
+ tar = xmalloc (sizeof (*tar));
+ tar->filename = xstrdup (filename);
+ tar->fd = -1;
+ tar->bfactor = bfactor;
+ tar->rsh = NULL;
+ tar->rmt = NULL;
+ paxbuf_create (pbuf, mode, tar, bfactor * BLOCKSIZE);
+ if (remote)
+ {
+ paxbuf_set_io (*pbuf, remote_reader, remote_writer, remote_seek);
+ paxbuf_set_term (*pbuf, remote_open, remote_close, tar_destroy);
+ }
+ else
+ {
+ paxbuf_set_io (*pbuf, local_reader, local_writer, local_seek);
+ paxbuf_set_term (*pbuf, local_open, local_close, tar_destroy);
+ }
+
+ paxbuf_set_wrapper (*pbuf, tar_wrapper);
+}
+
+void
+tar_set_rmt (paxbuf_t pbuf, const char *rmt)
+{
+ tar_archive_t *tar = paxbuf_get_data (pbuf);
+ tar->rmt = rmt;
+}
+
+void
+tar_set_rsh (paxbuf_t pbuf, const char *rsh)
+{
+ tar_archive_t *tar = paxbuf_get_data (pbuf);
+ tar->rsh = rsh;
+}
diff --git a/paxlib/tardef.h b/paxlib/tardef.h
new file mode 100644
index 0000000..d7068fd
--- /dev/null
+++ b/paxlib/tardef.h
@@ -0,0 +1,54 @@
+/* This file is part of GNU paxutils
+
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ Written by Sergey Poznyakoff
+
+ GNU paxutils is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ GNU paxutils program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with GNU paxutils; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+struct tar_stat_info
+{
+ char *orig_file_name; /* name of file read from the archive header */
+ char *file_name; /* name of file for the current archive entry
+ after being normalized. */
+ int had_trailing_slash; /* nonzero if the current archive entry had a
+ trailing slash before it was normalized. */
+ char *link_name; /* name of link for the current archive entry. */
+
+ unsigned int devminor; /* device minor number */
+ unsigned int devmajor; /* device major number */
+ char *uname; /* user name of owner */
+ char *gname; /* group name of owner */
+ struct stat stat; /* regular filesystem stat */
+
+ /* Nanosecond parts of file timestamps (if available) */
+ unsigned long atime_nsec;
+ unsigned long mtime_nsec;
+ unsigned long ctime_nsec;
+
+ off_t archive_file_size; /* Size of file as stored in the archive.
+ Equals stat.st_size for non-sparse files */
+
+ bool is_sparse; /* Is the file sparse */
+
+ size_t sparse_map_avail; /* Index to the first unused element in
+ sparse_map array. Zero if the file is
+ not sparse */
+ size_t sparse_map_size; /* Size of the sparse map */
+ struct sp_array *sparse_map;
+};
+
+void tar_archive_create (paxbuf_t *pbuf, const char *filename,
+ int mode, size_t bfactor);
diff --git a/paxtest/.cvsignore b/paxtest/.cvsignore
new file mode 100644
index 0000000..4fa7de9
--- /dev/null
+++ b/paxtest/.cvsignore
@@ -0,0 +1,4 @@
+Makefile
+Makefile.in
+paxtest
+.deps \ No newline at end of file
diff --git a/paxtest/Makefile.am b/paxtest/Makefile.am
new file mode 100644
index 0000000..58bea1a
--- /dev/null
+++ b/paxtest/Makefile.am
@@ -0,0 +1,28 @@
+# This file is part of GNU paxutils
+#
+# Copyright (C) 2005 Free Software Foundation, Inc.
+#
+# Written by Sergey Poznyakoff
+#
+# GNU paxutils is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2, or (at your option) any later
+# version.
+#
+# GNU paxutils is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with GNU paxutils; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+noinst_PROGRAMS = paxtest
+paxtest_SOURCES = paxtest.c
+noinst_HEADERS = paxtest.h
+
+INCLUDES = -I$(top_srcdir)/lib -I../ -I../lib -I../paxlib
+
+LDADD = ../paxlib/libpax.a ../lib/libgnu.a $(LIBINTL) $(LIBICONV)
+
diff --git a/paxtest/paxtest.c b/paxtest/paxtest.c
new file mode 100644
index 0000000..47eb365
--- /dev/null
+++ b/paxtest/paxtest.c
@@ -0,0 +1,85 @@
+/* This file is part of GNU paxutils
+
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ Written by Sergey Poznyakoff
+
+ GNU paxutils is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ GNU paxutils program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with GNU paxutils; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <paxtest.h>
+
+#ifndef DEFAULT_BLOCKING_FACTOR
+# define DEFAULT_BLOCKING_FACTOR 20
+#endif
+
+void
+xalloc_die (void)
+{
+ error(1, ENOMEM, "Exiting");
+}
+
+void
+dump (unsigned char *buf, size_t size)
+{
+ while (size)
+ {
+ int i;
+ for (i = 0; i < 16 && size; i++, size--, buf++)
+ printf ("%02X ", *buf);
+ printf ("\n");
+ }
+}
+
+
+void
+read_and_dump (paxbuf_t pbuf)
+{
+ union block block;
+ size_t size;
+ pax_io_status_t rc;
+
+ while ((rc = paxbuf_read (pbuf, block.buffer, sizeof block, &size))
+ == pax_io_success)
+ {
+ dump (block.buffer, size);
+ }
+ if (rc == pax_io_failure)
+ error (1, 0, "Read error");
+}
+
+int
+main (int argc, char **argv)
+{
+ paxbuf_t pbuf;
+ int rc;
+
+ if (argc == 1)
+ error (1, 0, "Not enough arguments");
+
+ tar_archive_create (&pbuf, argv[1], 0, PAXBUF_READ, DEFAULT_BLOCKING_FACTOR);
+
+ rc = paxbuf_open (pbuf);
+ printf ("Open: %d\n", rc);
+ if (rc)
+ abort ();
+ read_and_dump (pbuf);
+ paxbuf_close (pbuf);
+ paxbuf_destroy (&pbuf);
+ return 0;
+}
diff --git a/paxtest/paxtest.h b/paxtest/paxtest.h
new file mode 100644
index 0000000..5aee693
--- /dev/null
+++ b/paxtest/paxtest.h
@@ -0,0 +1,25 @@
+/* This file is part of GNU paxutils
+
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ Written by Sergey Poznyakoff
+
+ GNU paxutils is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ GNU paxutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with GNU paxutils; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <stdlib.h>
+#include <system.h>
+#include <paxbuf.h>
+#include <tar.h>
+#include <pax.h>