summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKim Kibum <kb0929.kim@samsung.com>2012-05-21 17:40:28 +0900
committerKim Kibum <kb0929.kim@samsung.com>2012-05-21 17:40:28 +0900
commit5fab833656f8722f000d40da4733c164690a18df (patch)
tree06c6b7063a663592937cbcd47dd400ac931e0490 /src
parent43e15e32d26b017f436da3dd40334b4df292e5a5 (diff)
downloadcpio-5fab833656f8722f000d40da4733c164690a18df.tar.gz
cpio-5fab833656f8722f000d40da4733c164690a18df.tar.bz2
cpio-5fab833656f8722f000d40da4733c164690a18df.zip
Upload Tizen:Base source
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am53
-rw-r--r--src/Makefile.in1175
-rw-r--r--src/copyin.c1502
-rw-r--r--src/copyout.c898
-rw-r--r--src/copypass.c398
-rw-r--r--src/cpio.h72
-rw-r--r--src/cpiohdr.h132
-rw-r--r--src/defer.c44
-rw-r--r--src/defer.h27
-rw-r--r--src/dstring.c104
-rw-r--r--src/dstring.h51
-rw-r--r--src/extern.h219
-rw-r--r--src/fatal.c27
-rw-r--r--src/filemode.c244
-rw-r--r--src/filetypes.h85
-rw-r--r--src/global.c195
-rw-r--r--src/idcache.c198
-rw-r--r--src/main.c743
-rw-r--r--src/makepath.c188
-rw-r--r--src/mt.c361
-rw-r--r--src/safe-stat.h1
-rw-r--r--src/tar.c480
-rw-r--r--src/tar.h112
-rw-r--r--src/tarhdr.h63
-rw-r--r--src/userspec.c233
-rw-r--r--src/util.c1620
26 files changed, 9225 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..ec71397
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,53 @@
+# This file is part of GNU cpio
+# Copyright (C) 2003, 2004, 2007, 2009, 2010 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 3, 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., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 USA.
+
+INCLUDES=-I. -I.. -I$(top_srcdir)/gnu -I$(top_builddir)/gnu -I$(top_srcdir)/lib -I$(top_builddir)/lib
+
+bin_PROGRAMS=cpio @CPIO_MT_PROG@
+EXTRA_PROGRAMS=mt
+
+cpio_SOURCES = \
+ copyin.c\
+ copyout.c\
+ copypass.c\
+ defer.c\
+ dstring.c\
+ global.c\
+ fatal.c\
+ main.c\
+ tar.c\
+ util.c\
+ filemode.c\
+ idcache.c\
+ makepath.c\
+ userspec.c
+
+noinst_HEADERS =\
+ cpio.h\
+ cpiohdr.h\
+ tar.h\
+ tarhdr.h\
+ defer.h\
+ dstring.h\
+ extern.h\
+ filetypes.h\
+ safe-stat.h
+
+LDADD=../lib/libpax.a ../gnu/libgnu.a @INTLLIBS@
+
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..c69433d
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,1175 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# This file is part of GNU cpio
+# Copyright (C) 2003, 2004, 2007, 2009, 2010 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 3, 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., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 USA.
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+bin_PROGRAMS = cpio$(EXEEXT) @CPIO_MT_PROG@
+EXTRA_PROGRAMS = mt$(EXEEXT)
+subdir = src
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/am/flushleft.m4 \
+ $(top_srcdir)/am/pack.m4 $(top_srcdir)/am/sysdep.m4 \
+ $(top_srcdir)/m4/00gnulib.m4 $(top_srcdir)/m4/alloca.m4 \
+ $(top_srcdir)/m4/argmatch.m4 $(top_srcdir)/m4/argp.m4 \
+ $(top_srcdir)/m4/bison.m4 $(top_srcdir)/m4/chdir-long.m4 \
+ $(top_srcdir)/m4/chown.m4 $(top_srcdir)/m4/clock_time.m4 \
+ $(top_srcdir)/m4/close-stream.m4 $(top_srcdir)/m4/close.m4 \
+ $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
+ $(top_srcdir)/m4/d-ino.m4 $(top_srcdir)/m4/dirent-safer.m4 \
+ $(top_srcdir)/m4/dirent_h.m4 $(top_srcdir)/m4/dirfd.m4 \
+ $(top_srcdir)/m4/dirname.m4 $(top_srcdir)/m4/dos.m4 \
+ $(top_srcdir)/m4/double-slash-root.m4 $(top_srcdir)/m4/dup2.m4 \
+ $(top_srcdir)/m4/eealloc.m4 $(top_srcdir)/m4/environ.m4 \
+ $(top_srcdir)/m4/errno_h.m4 $(top_srcdir)/m4/error.m4 \
+ $(top_srcdir)/m4/extensions.m4 $(top_srcdir)/m4/fchdir.m4 \
+ $(top_srcdir)/m4/fclose.m4 $(top_srcdir)/m4/fcntl-o.m4 \
+ $(top_srcdir)/m4/fcntl.m4 $(top_srcdir)/m4/fcntl_h.m4 \
+ $(top_srcdir)/m4/fdopendir.m4 $(top_srcdir)/m4/fileblocks.m4 \
+ $(top_srcdir)/m4/float_h.m4 $(top_srcdir)/m4/fnmatch.m4 \
+ $(top_srcdir)/m4/fpending.m4 $(top_srcdir)/m4/fseeko.m4 \
+ $(top_srcdir)/m4/getcwd-abort-bug.m4 \
+ $(top_srcdir)/m4/getcwd-path-max.m4 $(top_srcdir)/m4/getcwd.m4 \
+ $(top_srcdir)/m4/getdate.m4 $(top_srcdir)/m4/getdtablesize.m4 \
+ $(top_srcdir)/m4/getopt.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gettime.m4 $(top_srcdir)/m4/gettimeofday.m4 \
+ $(top_srcdir)/m4/glibc21.m4 $(top_srcdir)/m4/gnulib-common.m4 \
+ $(top_srcdir)/m4/gnulib-comp.m4 $(top_srcdir)/m4/hash.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/include_next.m4 \
+ $(top_srcdir)/m4/inline.m4 $(top_srcdir)/m4/intlmacosx.m4 \
+ $(top_srcdir)/m4/intmax_t.m4 $(top_srcdir)/m4/inttostr.m4 \
+ $(top_srcdir)/m4/inttypes-pri.m4 $(top_srcdir)/m4/inttypes.m4 \
+ $(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/lchown.m4 \
+ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
+ $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/localcharset.m4 $(top_srcdir)/m4/locale-fr.m4 \
+ $(top_srcdir)/m4/locale-ja.m4 $(top_srcdir)/m4/locale-zh.m4 \
+ $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/lseek.m4 \
+ $(top_srcdir)/m4/lstat.m4 $(top_srcdir)/m4/malloc.m4 \
+ $(top_srcdir)/m4/malloca.m4 $(top_srcdir)/m4/mbrtowc.m4 \
+ $(top_srcdir)/m4/mbsinit.m4 $(top_srcdir)/m4/mbsrtowcs.m4 \
+ $(top_srcdir)/m4/mbstate_t.m4 $(top_srcdir)/m4/memchr.m4 \
+ $(top_srcdir)/m4/mempcpy.m4 $(top_srcdir)/m4/memrchr.m4 \
+ $(top_srcdir)/m4/mkdir.m4 $(top_srcdir)/m4/mktime.m4 \
+ $(top_srcdir)/m4/mmap-anon.m4 $(top_srcdir)/m4/mode_t.m4 \
+ $(top_srcdir)/m4/multiarch.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/open.m4 $(top_srcdir)/m4/openat.m4 \
+ $(top_srcdir)/m4/paxutils.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/printf.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/m4/quote.m4 $(top_srcdir)/m4/quotearg.m4 \
+ $(top_srcdir)/m4/rawmemchr.m4 $(top_srcdir)/m4/realloc.m4 \
+ $(top_srcdir)/m4/rmdir.m4 $(top_srcdir)/m4/rmt.m4 \
+ $(top_srcdir)/m4/rtapelib.m4 $(top_srcdir)/m4/safe-read.m4 \
+ $(top_srcdir)/m4/safe-write.m4 $(top_srcdir)/m4/save-cwd.m4 \
+ $(top_srcdir)/m4/savedir.m4 $(top_srcdir)/m4/setenv.m4 \
+ $(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/sleep.m4 \
+ $(top_srcdir)/m4/ssize_t.m4 $(top_srcdir)/m4/stat-time.m4 \
+ $(top_srcdir)/m4/stat.m4 $(top_srcdir)/m4/stdarg.m4 \
+ $(top_srcdir)/m4/stdbool.m4 $(top_srcdir)/m4/stddef_h.m4 \
+ $(top_srcdir)/m4/stdint.m4 $(top_srcdir)/m4/stdint_h.m4 \
+ $(top_srcdir)/m4/stdio_h.m4 $(top_srcdir)/m4/stdlib_h.m4 \
+ $(top_srcdir)/m4/stpcpy.m4 $(top_srcdir)/m4/strcase.m4 \
+ $(top_srcdir)/m4/strchrnul.m4 $(top_srcdir)/m4/strdup.m4 \
+ $(top_srcdir)/m4/strerror.m4 $(top_srcdir)/m4/string_h.m4 \
+ $(top_srcdir)/m4/strings_h.m4 $(top_srcdir)/m4/strndup.m4 \
+ $(top_srcdir)/m4/strnlen.m4 $(top_srcdir)/m4/strtol.m4 \
+ $(top_srcdir)/m4/sys_stat_h.m4 $(top_srcdir)/m4/sys_time_h.m4 \
+ $(top_srcdir)/m4/sysexits.m4 $(top_srcdir)/m4/system.m4 \
+ $(top_srcdir)/m4/time_h.m4 $(top_srcdir)/m4/time_r.m4 \
+ $(top_srcdir)/m4/timespec.m4 $(top_srcdir)/m4/tm_gmtoff.m4 \
+ $(top_srcdir)/m4/unistd-safer.m4 $(top_srcdir)/m4/unistd_h.m4 \
+ $(top_srcdir)/m4/unlink.m4 $(top_srcdir)/m4/unlocked-io.m4 \
+ $(top_srcdir)/m4/utimbuf.m4 $(top_srcdir)/m4/utimens.m4 \
+ $(top_srcdir)/m4/utimes.m4 $(top_srcdir)/m4/vasnprintf.m4 \
+ $(top_srcdir)/m4/version-etc.m4 $(top_srcdir)/m4/vsnprintf.m4 \
+ $(top_srcdir)/m4/warn-on-use.m4 $(top_srcdir)/m4/wchar_h.m4 \
+ $(top_srcdir)/m4/wchar_t.m4 $(top_srcdir)/m4/wctype_h.m4 \
+ $(top_srcdir)/m4/wint_t.m4 $(top_srcdir)/m4/write.m4 \
+ $(top_srcdir)/m4/xalloc.m4 $(top_srcdir)/m4/xgetcwd.m4 \
+ $(top_srcdir)/m4/xsize.m4 $(top_srcdir)/m4/xstrndup.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)"
+PROGRAMS = $(bin_PROGRAMS)
+am_cpio_OBJECTS = copyin.$(OBJEXT) copyout.$(OBJEXT) \
+ copypass.$(OBJEXT) defer.$(OBJEXT) dstring.$(OBJEXT) \
+ global.$(OBJEXT) fatal.$(OBJEXT) main.$(OBJEXT) tar.$(OBJEXT) \
+ util.$(OBJEXT) filemode.$(OBJEXT) idcache.$(OBJEXT) \
+ makepath.$(OBJEXT) userspec.$(OBJEXT)
+cpio_OBJECTS = $(am_cpio_OBJECTS)
+cpio_LDADD = $(LDADD)
+cpio_DEPENDENCIES = ../lib/libpax.a ../gnu/libgnu.a
+mt_SOURCES = mt.c
+mt_OBJECTS = mt.$(OBJEXT)
+mt_LDADD = $(LDADD)
+mt_DEPENDENCIES = ../lib/libpax.a ../gnu/libgnu.a
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(cpio_SOURCES) mt.c
+DIST_SOURCES = $(cpio_SOURCES) mt.c
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALLOCA_H = @ALLOCA_H@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APPLE_UNIVERSAL_BUILD = @APPLE_UNIVERSAL_BUILD@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOM4TE = @AUTOM4TE@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BITSIZEOF_PTRDIFF_T = @BITSIZEOF_PTRDIFF_T@
+BITSIZEOF_SIG_ATOMIC_T = @BITSIZEOF_SIG_ATOMIC_T@
+BITSIZEOF_SIZE_T = @BITSIZEOF_SIZE_T@
+BITSIZEOF_WCHAR_T = @BITSIZEOF_WCHAR_T@
+BITSIZEOF_WINT_T = @BITSIZEOF_WINT_T@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPIO_MT_PROG = @CPIO_MT_PROG@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_RMT_COMMAND = @DEFAULT_RMT_COMMAND@
+DEFAULT_RMT_DIR = @DEFAULT_RMT_DIR@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EMULTIHOP_HIDDEN = @EMULTIHOP_HIDDEN@
+EMULTIHOP_VALUE = @EMULTIHOP_VALUE@
+ENOLINK_HIDDEN = @ENOLINK_HIDDEN@
+ENOLINK_VALUE = @ENOLINK_VALUE@
+EOVERFLOW_HIDDEN = @EOVERFLOW_HIDDEN@
+EOVERFLOW_VALUE = @EOVERFLOW_VALUE@
+ERRNO_H = @ERRNO_H@
+EXEEXT = @EXEEXT@
+FLOAT_H = @FLOAT_H@
+FNMATCH_H = @FNMATCH_H@
+GETOPT_H = @GETOPT_H@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GLIBC21 = @GLIBC21@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GNULIB_ALPHASORT = @GNULIB_ALPHASORT@
+GNULIB_ATOLL = @GNULIB_ATOLL@
+GNULIB_BTOWC = @GNULIB_BTOWC@
+GNULIB_CALLOC_POSIX = @GNULIB_CALLOC_POSIX@
+GNULIB_CANONICALIZE_FILE_NAME = @GNULIB_CANONICALIZE_FILE_NAME@
+GNULIB_CHOWN = @GNULIB_CHOWN@
+GNULIB_CLOSE = @GNULIB_CLOSE@
+GNULIB_DIRFD = @GNULIB_DIRFD@
+GNULIB_DPRINTF = @GNULIB_DPRINTF@
+GNULIB_DUP2 = @GNULIB_DUP2@
+GNULIB_DUP3 = @GNULIB_DUP3@
+GNULIB_ENVIRON = @GNULIB_ENVIRON@
+GNULIB_EUIDACCESS = @GNULIB_EUIDACCESS@
+GNULIB_FACCESSAT = @GNULIB_FACCESSAT@
+GNULIB_FCHDIR = @GNULIB_FCHDIR@
+GNULIB_FCHMODAT = @GNULIB_FCHMODAT@
+GNULIB_FCHOWNAT = @GNULIB_FCHOWNAT@
+GNULIB_FCLOSE = @GNULIB_FCLOSE@
+GNULIB_FCNTL = @GNULIB_FCNTL@
+GNULIB_FDOPENDIR = @GNULIB_FDOPENDIR@
+GNULIB_FFLUSH = @GNULIB_FFLUSH@
+GNULIB_FOPEN = @GNULIB_FOPEN@
+GNULIB_FPRINTF = @GNULIB_FPRINTF@
+GNULIB_FPRINTF_POSIX = @GNULIB_FPRINTF_POSIX@
+GNULIB_FPURGE = @GNULIB_FPURGE@
+GNULIB_FPUTC = @GNULIB_FPUTC@
+GNULIB_FPUTS = @GNULIB_FPUTS@
+GNULIB_FREOPEN = @GNULIB_FREOPEN@
+GNULIB_FSEEK = @GNULIB_FSEEK@
+GNULIB_FSEEKO = @GNULIB_FSEEKO@
+GNULIB_FSTATAT = @GNULIB_FSTATAT@
+GNULIB_FSYNC = @GNULIB_FSYNC@
+GNULIB_FTELL = @GNULIB_FTELL@
+GNULIB_FTELLO = @GNULIB_FTELLO@
+GNULIB_FTRUNCATE = @GNULIB_FTRUNCATE@
+GNULIB_FUTIMENS = @GNULIB_FUTIMENS@
+GNULIB_FWRITE = @GNULIB_FWRITE@
+GNULIB_GETCWD = @GNULIB_GETCWD@
+GNULIB_GETDELIM = @GNULIB_GETDELIM@
+GNULIB_GETDOMAINNAME = @GNULIB_GETDOMAINNAME@
+GNULIB_GETDTABLESIZE = @GNULIB_GETDTABLESIZE@
+GNULIB_GETGROUPS = @GNULIB_GETGROUPS@
+GNULIB_GETHOSTNAME = @GNULIB_GETHOSTNAME@
+GNULIB_GETLINE = @GNULIB_GETLINE@
+GNULIB_GETLOADAVG = @GNULIB_GETLOADAVG@
+GNULIB_GETLOGIN = @GNULIB_GETLOGIN@
+GNULIB_GETLOGIN_R = @GNULIB_GETLOGIN_R@
+GNULIB_GETPAGESIZE = @GNULIB_GETPAGESIZE@
+GNULIB_GETSUBOPT = @GNULIB_GETSUBOPT@
+GNULIB_GETTIMEOFDAY = @GNULIB_GETTIMEOFDAY@
+GNULIB_GETUSERSHELL = @GNULIB_GETUSERSHELL@
+GNULIB_IMAXABS = @GNULIB_IMAXABS@
+GNULIB_IMAXDIV = @GNULIB_IMAXDIV@
+GNULIB_LCHMOD = @GNULIB_LCHMOD@
+GNULIB_LCHOWN = @GNULIB_LCHOWN@
+GNULIB_LINK = @GNULIB_LINK@
+GNULIB_LINKAT = @GNULIB_LINKAT@
+GNULIB_LSEEK = @GNULIB_LSEEK@
+GNULIB_LSTAT = @GNULIB_LSTAT@
+GNULIB_MALLOC_POSIX = @GNULIB_MALLOC_POSIX@
+GNULIB_MBRLEN = @GNULIB_MBRLEN@
+GNULIB_MBRTOWC = @GNULIB_MBRTOWC@
+GNULIB_MBSCASECMP = @GNULIB_MBSCASECMP@
+GNULIB_MBSCASESTR = @GNULIB_MBSCASESTR@
+GNULIB_MBSCHR = @GNULIB_MBSCHR@
+GNULIB_MBSCSPN = @GNULIB_MBSCSPN@
+GNULIB_MBSINIT = @GNULIB_MBSINIT@
+GNULIB_MBSLEN = @GNULIB_MBSLEN@
+GNULIB_MBSNCASECMP = @GNULIB_MBSNCASECMP@
+GNULIB_MBSNLEN = @GNULIB_MBSNLEN@
+GNULIB_MBSNRTOWCS = @GNULIB_MBSNRTOWCS@
+GNULIB_MBSPBRK = @GNULIB_MBSPBRK@
+GNULIB_MBSPCASECMP = @GNULIB_MBSPCASECMP@
+GNULIB_MBSRCHR = @GNULIB_MBSRCHR@
+GNULIB_MBSRTOWCS = @GNULIB_MBSRTOWCS@
+GNULIB_MBSSEP = @GNULIB_MBSSEP@
+GNULIB_MBSSPN = @GNULIB_MBSSPN@
+GNULIB_MBSSTR = @GNULIB_MBSSTR@
+GNULIB_MBSTOK_R = @GNULIB_MBSTOK_R@
+GNULIB_MEMCHR = @GNULIB_MEMCHR@
+GNULIB_MEMMEM = @GNULIB_MEMMEM@
+GNULIB_MEMPCPY = @GNULIB_MEMPCPY@
+GNULIB_MEMRCHR = @GNULIB_MEMRCHR@
+GNULIB_MKDIRAT = @GNULIB_MKDIRAT@
+GNULIB_MKDTEMP = @GNULIB_MKDTEMP@
+GNULIB_MKFIFO = @GNULIB_MKFIFO@
+GNULIB_MKFIFOAT = @GNULIB_MKFIFOAT@
+GNULIB_MKNOD = @GNULIB_MKNOD@
+GNULIB_MKNODAT = @GNULIB_MKNODAT@
+GNULIB_MKOSTEMP = @GNULIB_MKOSTEMP@
+GNULIB_MKOSTEMPS = @GNULIB_MKOSTEMPS@
+GNULIB_MKSTEMP = @GNULIB_MKSTEMP@
+GNULIB_MKSTEMPS = @GNULIB_MKSTEMPS@
+GNULIB_MKTIME = @GNULIB_MKTIME@
+GNULIB_NANOSLEEP = @GNULIB_NANOSLEEP@
+GNULIB_OBSTACK_PRINTF = @GNULIB_OBSTACK_PRINTF@
+GNULIB_OBSTACK_PRINTF_POSIX = @GNULIB_OBSTACK_PRINTF_POSIX@
+GNULIB_OPEN = @GNULIB_OPEN@
+GNULIB_OPENAT = @GNULIB_OPENAT@
+GNULIB_PERROR = @GNULIB_PERROR@
+GNULIB_PIPE2 = @GNULIB_PIPE2@
+GNULIB_POPEN = @GNULIB_POPEN@
+GNULIB_PREAD = @GNULIB_PREAD@
+GNULIB_PRINTF = @GNULIB_PRINTF@
+GNULIB_PRINTF_POSIX = @GNULIB_PRINTF_POSIX@
+GNULIB_PUTC = @GNULIB_PUTC@
+GNULIB_PUTCHAR = @GNULIB_PUTCHAR@
+GNULIB_PUTENV = @GNULIB_PUTENV@
+GNULIB_PUTS = @GNULIB_PUTS@
+GNULIB_RANDOM_R = @GNULIB_RANDOM_R@
+GNULIB_RAWMEMCHR = @GNULIB_RAWMEMCHR@
+GNULIB_READLINK = @GNULIB_READLINK@
+GNULIB_READLINKAT = @GNULIB_READLINKAT@
+GNULIB_REALLOC_POSIX = @GNULIB_REALLOC_POSIX@
+GNULIB_REALPATH = @GNULIB_REALPATH@
+GNULIB_REMOVE = @GNULIB_REMOVE@
+GNULIB_RENAME = @GNULIB_RENAME@
+GNULIB_RENAMEAT = @GNULIB_RENAMEAT@
+GNULIB_RMDIR = @GNULIB_RMDIR@
+GNULIB_RPMATCH = @GNULIB_RPMATCH@
+GNULIB_SCANDIR = @GNULIB_SCANDIR@
+GNULIB_SETENV = @GNULIB_SETENV@
+GNULIB_SLEEP = @GNULIB_SLEEP@
+GNULIB_SNPRINTF = @GNULIB_SNPRINTF@
+GNULIB_SPRINTF_POSIX = @GNULIB_SPRINTF_POSIX@
+GNULIB_STAT = @GNULIB_STAT@
+GNULIB_STDIO_H_SIGPIPE = @GNULIB_STDIO_H_SIGPIPE@
+GNULIB_STPCPY = @GNULIB_STPCPY@
+GNULIB_STPNCPY = @GNULIB_STPNCPY@
+GNULIB_STRCASESTR = @GNULIB_STRCASESTR@
+GNULIB_STRCHRNUL = @GNULIB_STRCHRNUL@
+GNULIB_STRDUP = @GNULIB_STRDUP@
+GNULIB_STRERROR = @GNULIB_STRERROR@
+GNULIB_STRNDUP = @GNULIB_STRNDUP@
+GNULIB_STRNLEN = @GNULIB_STRNLEN@
+GNULIB_STRPBRK = @GNULIB_STRPBRK@
+GNULIB_STRPTIME = @GNULIB_STRPTIME@
+GNULIB_STRSEP = @GNULIB_STRSEP@
+GNULIB_STRSIGNAL = @GNULIB_STRSIGNAL@
+GNULIB_STRSTR = @GNULIB_STRSTR@
+GNULIB_STRTOD = @GNULIB_STRTOD@
+GNULIB_STRTOIMAX = @GNULIB_STRTOIMAX@
+GNULIB_STRTOK_R = @GNULIB_STRTOK_R@
+GNULIB_STRTOLL = @GNULIB_STRTOLL@
+GNULIB_STRTOULL = @GNULIB_STRTOULL@
+GNULIB_STRTOUMAX = @GNULIB_STRTOUMAX@
+GNULIB_STRVERSCMP = @GNULIB_STRVERSCMP@
+GNULIB_SYMLINK = @GNULIB_SYMLINK@
+GNULIB_SYMLINKAT = @GNULIB_SYMLINKAT@
+GNULIB_TIMEGM = @GNULIB_TIMEGM@
+GNULIB_UNISTD_H_GETOPT = @GNULIB_UNISTD_H_GETOPT@
+GNULIB_UNISTD_H_SIGPIPE = @GNULIB_UNISTD_H_SIGPIPE@
+GNULIB_UNLINK = @GNULIB_UNLINK@
+GNULIB_UNLINKAT = @GNULIB_UNLINKAT@
+GNULIB_UNSETENV = @GNULIB_UNSETENV@
+GNULIB_USLEEP = @GNULIB_USLEEP@
+GNULIB_UTIMENSAT = @GNULIB_UTIMENSAT@
+GNULIB_VASPRINTF = @GNULIB_VASPRINTF@
+GNULIB_VDPRINTF = @GNULIB_VDPRINTF@
+GNULIB_VFPRINTF = @GNULIB_VFPRINTF@
+GNULIB_VFPRINTF_POSIX = @GNULIB_VFPRINTF_POSIX@
+GNULIB_VPRINTF = @GNULIB_VPRINTF@
+GNULIB_VPRINTF_POSIX = @GNULIB_VPRINTF_POSIX@
+GNULIB_VSNPRINTF = @GNULIB_VSNPRINTF@
+GNULIB_VSPRINTF_POSIX = @GNULIB_VSPRINTF_POSIX@
+GNULIB_WCRTOMB = @GNULIB_WCRTOMB@
+GNULIB_WCSNRTOMBS = @GNULIB_WCSNRTOMBS@
+GNULIB_WCSRTOMBS = @GNULIB_WCSRTOMBS@
+GNULIB_WCTOB = @GNULIB_WCTOB@
+GNULIB_WCWIDTH = @GNULIB_WCWIDTH@
+GNULIB_WRITE = @GNULIB_WRITE@
+GREP = @GREP@
+HAVE_ALPHASORT = @HAVE_ALPHASORT@
+HAVE_ATOLL = @HAVE_ATOLL@
+HAVE_BTOWC = @HAVE_BTOWC@
+HAVE_CALLOC_POSIX = @HAVE_CALLOC_POSIX@
+HAVE_CANONICALIZE_FILE_NAME = @HAVE_CANONICALIZE_FILE_NAME@
+HAVE_CHOWN = @HAVE_CHOWN@
+HAVE_DECL_DIRFD = @HAVE_DECL_DIRFD@
+HAVE_DECL_ENVIRON = @HAVE_DECL_ENVIRON@
+HAVE_DECL_FPURGE = @HAVE_DECL_FPURGE@
+HAVE_DECL_GETDELIM = @HAVE_DECL_GETDELIM@
+HAVE_DECL_GETLINE = @HAVE_DECL_GETLINE@
+HAVE_DECL_GETLOADAVG = @HAVE_DECL_GETLOADAVG@
+HAVE_DECL_GETLOGIN_R = @HAVE_DECL_GETLOGIN_R@
+HAVE_DECL_IMAXABS = @HAVE_DECL_IMAXABS@
+HAVE_DECL_IMAXDIV = @HAVE_DECL_IMAXDIV@
+HAVE_DECL_MEMMEM = @HAVE_DECL_MEMMEM@
+HAVE_DECL_MEMRCHR = @HAVE_DECL_MEMRCHR@
+HAVE_DECL_OBSTACK_PRINTF = @HAVE_DECL_OBSTACK_PRINTF@
+HAVE_DECL_SNPRINTF = @HAVE_DECL_SNPRINTF@
+HAVE_DECL_STRDUP = @HAVE_DECL_STRDUP@
+HAVE_DECL_STRERROR = @HAVE_DECL_STRERROR@
+HAVE_DECL_STRNCASECMP = @HAVE_DECL_STRNCASECMP@
+HAVE_DECL_STRNDUP = @HAVE_DECL_STRNDUP@
+HAVE_DECL_STRNLEN = @HAVE_DECL_STRNLEN@
+HAVE_DECL_STRSIGNAL = @HAVE_DECL_STRSIGNAL@
+HAVE_DECL_STRTOIMAX = @HAVE_DECL_STRTOIMAX@
+HAVE_DECL_STRTOK_R = @HAVE_DECL_STRTOK_R@
+HAVE_DECL_STRTOUMAX = @HAVE_DECL_STRTOUMAX@
+HAVE_DECL_VSNPRINTF = @HAVE_DECL_VSNPRINTF@
+HAVE_DECL_WCTOB = @HAVE_DECL_WCTOB@
+HAVE_DECL_WCWIDTH = @HAVE_DECL_WCWIDTH@
+HAVE_DPRINTF = @HAVE_DPRINTF@
+HAVE_DUP2 = @HAVE_DUP2@
+HAVE_DUP3 = @HAVE_DUP3@
+HAVE_EUIDACCESS = @HAVE_EUIDACCESS@
+HAVE_FACCESSAT = @HAVE_FACCESSAT@
+HAVE_FCHMODAT = @HAVE_FCHMODAT@
+HAVE_FCHOWNAT = @HAVE_FCHOWNAT@
+HAVE_FCNTL = @HAVE_FCNTL@
+HAVE_FDOPENDIR = @HAVE_FDOPENDIR@
+HAVE_FSTATAT = @HAVE_FSTATAT@
+HAVE_FSYNC = @HAVE_FSYNC@
+HAVE_FTRUNCATE = @HAVE_FTRUNCATE@
+HAVE_FUTIMENS = @HAVE_FUTIMENS@
+HAVE_GETDOMAINNAME = @HAVE_GETDOMAINNAME@
+HAVE_GETDTABLESIZE = @HAVE_GETDTABLESIZE@
+HAVE_GETGROUPS = @HAVE_GETGROUPS@
+HAVE_GETHOSTNAME = @HAVE_GETHOSTNAME@
+HAVE_GETLOGIN = @HAVE_GETLOGIN@
+HAVE_GETOPT_H = @HAVE_GETOPT_H@
+HAVE_GETPAGESIZE = @HAVE_GETPAGESIZE@
+HAVE_GETSUBOPT = @HAVE_GETSUBOPT@
+HAVE_GETTIMEOFDAY = @HAVE_GETTIMEOFDAY@
+HAVE_GETUSERSHELL = @HAVE_GETUSERSHELL@
+HAVE_INTTYPES_H = @HAVE_INTTYPES_H@
+HAVE_ISWCNTRL = @HAVE_ISWCNTRL@
+HAVE_LCHMOD = @HAVE_LCHMOD@
+HAVE_LCHOWN = @HAVE_LCHOWN@
+HAVE_LINK = @HAVE_LINK@
+HAVE_LINKAT = @HAVE_LINKAT@
+HAVE_LONG_LONG_INT = @HAVE_LONG_LONG_INT@
+HAVE_LSTAT = @HAVE_LSTAT@
+HAVE_MALLOC_POSIX = @HAVE_MALLOC_POSIX@
+HAVE_MBRLEN = @HAVE_MBRLEN@
+HAVE_MBRTOWC = @HAVE_MBRTOWC@
+HAVE_MBSINIT = @HAVE_MBSINIT@
+HAVE_MBSLEN = @HAVE_MBSLEN@
+HAVE_MBSNRTOWCS = @HAVE_MBSNRTOWCS@
+HAVE_MBSRTOWCS = @HAVE_MBSRTOWCS@
+HAVE_MEMPCPY = @HAVE_MEMPCPY@
+HAVE_MKDIRAT = @HAVE_MKDIRAT@
+HAVE_MKDTEMP = @HAVE_MKDTEMP@
+HAVE_MKFIFO = @HAVE_MKFIFO@
+HAVE_MKFIFOAT = @HAVE_MKFIFOAT@
+HAVE_MKNOD = @HAVE_MKNOD@
+HAVE_MKNODAT = @HAVE_MKNODAT@
+HAVE_MKOSTEMP = @HAVE_MKOSTEMP@
+HAVE_MKOSTEMPS = @HAVE_MKOSTEMPS@
+HAVE_MKSTEMPS = @HAVE_MKSTEMPS@
+HAVE_OPENAT = @HAVE_OPENAT@
+HAVE_OS_H = @HAVE_OS_H@
+HAVE_PIPE2 = @HAVE_PIPE2@
+HAVE_PREAD = @HAVE_PREAD@
+HAVE_RANDOM_H = @HAVE_RANDOM_H@
+HAVE_RANDOM_R = @HAVE_RANDOM_R@
+HAVE_RAWMEMCHR = @HAVE_RAWMEMCHR@
+HAVE_READLINK = @HAVE_READLINK@
+HAVE_READLINKAT = @HAVE_READLINKAT@
+HAVE_REALLOC_POSIX = @HAVE_REALLOC_POSIX@
+HAVE_REALPATH = @HAVE_REALPATH@
+HAVE_RENAMEAT = @HAVE_RENAMEAT@
+HAVE_RPMATCH = @HAVE_RPMATCH@
+HAVE_SCANDIR = @HAVE_SCANDIR@
+HAVE_SETENV = @HAVE_SETENV@
+HAVE_SIGNED_SIG_ATOMIC_T = @HAVE_SIGNED_SIG_ATOMIC_T@
+HAVE_SIGNED_WCHAR_T = @HAVE_SIGNED_WCHAR_T@
+HAVE_SIGNED_WINT_T = @HAVE_SIGNED_WINT_T@
+HAVE_SLEEP = @HAVE_SLEEP@
+HAVE_STDINT_H = @HAVE_STDINT_H@
+HAVE_STPCPY = @HAVE_STPCPY@
+HAVE_STPNCPY = @HAVE_STPNCPY@
+HAVE_STRCASECMP = @HAVE_STRCASECMP@
+HAVE_STRCASESTR = @HAVE_STRCASESTR@
+HAVE_STRCHRNUL = @HAVE_STRCHRNUL@
+HAVE_STRPBRK = @HAVE_STRPBRK@
+HAVE_STRSEP = @HAVE_STRSEP@
+HAVE_STRTOD = @HAVE_STRTOD@
+HAVE_STRTOLL = @HAVE_STRTOLL@
+HAVE_STRTOULL = @HAVE_STRTOULL@
+HAVE_STRUCT_RANDOM_DATA = @HAVE_STRUCT_RANDOM_DATA@
+HAVE_STRUCT_TIMEVAL = @HAVE_STRUCT_TIMEVAL@
+HAVE_STRVERSCMP = @HAVE_STRVERSCMP@
+HAVE_SYMLINK = @HAVE_SYMLINK@
+HAVE_SYMLINKAT = @HAVE_SYMLINKAT@
+HAVE_SYSEXITS_H = @HAVE_SYSEXITS_H@
+HAVE_SYS_BITYPES_H = @HAVE_SYS_BITYPES_H@
+HAVE_SYS_INTTYPES_H = @HAVE_SYS_INTTYPES_H@
+HAVE_SYS_LOADAVG_H = @HAVE_SYS_LOADAVG_H@
+HAVE_SYS_PARAM_H = @HAVE_SYS_PARAM_H@
+HAVE_SYS_TIME_H = @HAVE_SYS_TIME_H@
+HAVE_SYS_TYPES_H = @HAVE_SYS_TYPES_H@
+HAVE_UNISTD_H = @HAVE_UNISTD_H@
+HAVE_UNLINKAT = @HAVE_UNLINKAT@
+HAVE_UNSETENV = @HAVE_UNSETENV@
+HAVE_UNSIGNED_LONG_LONG_INT = @HAVE_UNSIGNED_LONG_LONG_INT@
+HAVE_USLEEP = @HAVE_USLEEP@
+HAVE_UTIMENSAT = @HAVE_UTIMENSAT@
+HAVE_VASPRINTF = @HAVE_VASPRINTF@
+HAVE_VDPRINTF = @HAVE_VDPRINTF@
+HAVE_WCHAR_H = @HAVE_WCHAR_H@
+HAVE_WCHAR_T = @HAVE_WCHAR_T@
+HAVE_WCRTOMB = @HAVE_WCRTOMB@
+HAVE_WCSNRTOMBS = @HAVE_WCSNRTOMBS@
+HAVE_WCSRTOMBS = @HAVE_WCSRTOMBS@
+HAVE_WCTYPE_H = @HAVE_WCTYPE_H@
+HAVE_WINT_T = @HAVE_WINT_T@
+HAVE__BOOL = @HAVE__BOOL@
+INCLUDE_NEXT = @INCLUDE_NEXT@
+INCLUDE_NEXT_AS_FIRST_DIRECTIVE = @INCLUDE_NEXT_AS_FIRST_DIRECTIVE@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INT32_MAX_LT_INTMAX_MAX = @INT32_MAX_LT_INTMAX_MAX@
+INT64_MAX_EQ_LONG_MAX = @INT64_MAX_EQ_LONG_MAX@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBGNU_LIBDEPS = @LIBGNU_LIBDEPS@
+LIBGNU_LTLIBDEPS = @LIBGNU_LTLIBDEPS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_SETSOCKOPT = @LIB_SETSOCKOPT@
+LOCALCHARSET_TESTS_ENVIRONMENT = @LOCALCHARSET_TESTS_ENVIRONMENT@
+LOCALE_FR_UTF8 = @LOCALE_FR_UTF8@
+LOCALE_JA = @LOCALE_JA@
+LOCALE_ZH_CN = @LOCALE_ZH_CN@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NEXT_AS_FIRST_DIRECTIVE_DIRENT_H = @NEXT_AS_FIRST_DIRECTIVE_DIRENT_H@
+NEXT_AS_FIRST_DIRECTIVE_ERRNO_H = @NEXT_AS_FIRST_DIRECTIVE_ERRNO_H@
+NEXT_AS_FIRST_DIRECTIVE_FCNTL_H = @NEXT_AS_FIRST_DIRECTIVE_FCNTL_H@
+NEXT_AS_FIRST_DIRECTIVE_FLOAT_H = @NEXT_AS_FIRST_DIRECTIVE_FLOAT_H@
+NEXT_AS_FIRST_DIRECTIVE_GETOPT_H = @NEXT_AS_FIRST_DIRECTIVE_GETOPT_H@
+NEXT_AS_FIRST_DIRECTIVE_INTTYPES_H = @NEXT_AS_FIRST_DIRECTIVE_INTTYPES_H@
+NEXT_AS_FIRST_DIRECTIVE_STDARG_H = @NEXT_AS_FIRST_DIRECTIVE_STDARG_H@
+NEXT_AS_FIRST_DIRECTIVE_STDDEF_H = @NEXT_AS_FIRST_DIRECTIVE_STDDEF_H@
+NEXT_AS_FIRST_DIRECTIVE_STDINT_H = @NEXT_AS_FIRST_DIRECTIVE_STDINT_H@
+NEXT_AS_FIRST_DIRECTIVE_STDIO_H = @NEXT_AS_FIRST_DIRECTIVE_STDIO_H@
+NEXT_AS_FIRST_DIRECTIVE_STDLIB_H = @NEXT_AS_FIRST_DIRECTIVE_STDLIB_H@
+NEXT_AS_FIRST_DIRECTIVE_STRINGS_H = @NEXT_AS_FIRST_DIRECTIVE_STRINGS_H@
+NEXT_AS_FIRST_DIRECTIVE_STRING_H = @NEXT_AS_FIRST_DIRECTIVE_STRING_H@
+NEXT_AS_FIRST_DIRECTIVE_SYSEXITS_H = @NEXT_AS_FIRST_DIRECTIVE_SYSEXITS_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_TIME_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_TIME_H@
+NEXT_AS_FIRST_DIRECTIVE_TIME_H = @NEXT_AS_FIRST_DIRECTIVE_TIME_H@
+NEXT_AS_FIRST_DIRECTIVE_UNISTD_H = @NEXT_AS_FIRST_DIRECTIVE_UNISTD_H@
+NEXT_AS_FIRST_DIRECTIVE_WCHAR_H = @NEXT_AS_FIRST_DIRECTIVE_WCHAR_H@
+NEXT_AS_FIRST_DIRECTIVE_WCTYPE_H = @NEXT_AS_FIRST_DIRECTIVE_WCTYPE_H@
+NEXT_DIRENT_H = @NEXT_DIRENT_H@
+NEXT_ERRNO_H = @NEXT_ERRNO_H@
+NEXT_FCNTL_H = @NEXT_FCNTL_H@
+NEXT_FLOAT_H = @NEXT_FLOAT_H@
+NEXT_GETOPT_H = @NEXT_GETOPT_H@
+NEXT_INTTYPES_H = @NEXT_INTTYPES_H@
+NEXT_STDARG_H = @NEXT_STDARG_H@
+NEXT_STDDEF_H = @NEXT_STDDEF_H@
+NEXT_STDINT_H = @NEXT_STDINT_H@
+NEXT_STDIO_H = @NEXT_STDIO_H@
+NEXT_STDLIB_H = @NEXT_STDLIB_H@
+NEXT_STRINGS_H = @NEXT_STRINGS_H@
+NEXT_STRING_H = @NEXT_STRING_H@
+NEXT_SYSEXITS_H = @NEXT_SYSEXITS_H@
+NEXT_SYS_STAT_H = @NEXT_SYS_STAT_H@
+NEXT_SYS_TIME_H = @NEXT_SYS_TIME_H@
+NEXT_TIME_H = @NEXT_TIME_H@
+NEXT_UNISTD_H = @NEXT_UNISTD_H@
+NEXT_WCHAR_H = @NEXT_WCHAR_H@
+NEXT_WCTYPE_H = @NEXT_WCTYPE_H@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+POSUB = @POSUB@
+PRAGMA_SYSTEM_HEADER = @PRAGMA_SYSTEM_HEADER@
+PRIPTR_PREFIX = @PRIPTR_PREFIX@
+PRI_MACROS_BROKEN = @PRI_MACROS_BROKEN@
+PTRDIFF_T_SUFFIX = @PTRDIFF_T_SUFFIX@
+PU_RMT_PROG = @PU_RMT_PROG@
+RANLIB = @RANLIB@
+REPLACE_BTOWC = @REPLACE_BTOWC@
+REPLACE_CANONICALIZE_FILE_NAME = @REPLACE_CANONICALIZE_FILE_NAME@
+REPLACE_CHOWN = @REPLACE_CHOWN@
+REPLACE_CLOSE = @REPLACE_CLOSE@
+REPLACE_CLOSEDIR = @REPLACE_CLOSEDIR@
+REPLACE_DPRINTF = @REPLACE_DPRINTF@
+REPLACE_DUP = @REPLACE_DUP@
+REPLACE_DUP2 = @REPLACE_DUP2@
+REPLACE_FCHDIR = @REPLACE_FCHDIR@
+REPLACE_FCHOWNAT = @REPLACE_FCHOWNAT@
+REPLACE_FCLOSE = @REPLACE_FCLOSE@
+REPLACE_FCNTL = @REPLACE_FCNTL@
+REPLACE_FDOPENDIR = @REPLACE_FDOPENDIR@
+REPLACE_FFLUSH = @REPLACE_FFLUSH@
+REPLACE_FOPEN = @REPLACE_FOPEN@
+REPLACE_FPRINTF = @REPLACE_FPRINTF@
+REPLACE_FPURGE = @REPLACE_FPURGE@
+REPLACE_FREOPEN = @REPLACE_FREOPEN@
+REPLACE_FSEEK = @REPLACE_FSEEK@
+REPLACE_FSEEKO = @REPLACE_FSEEKO@
+REPLACE_FSTAT = @REPLACE_FSTAT@
+REPLACE_FSTATAT = @REPLACE_FSTATAT@
+REPLACE_FTELL = @REPLACE_FTELL@
+REPLACE_FTELLO = @REPLACE_FTELLO@
+REPLACE_FUTIMENS = @REPLACE_FUTIMENS@
+REPLACE_GETCWD = @REPLACE_GETCWD@
+REPLACE_GETDELIM = @REPLACE_GETDELIM@
+REPLACE_GETGROUPS = @REPLACE_GETGROUPS@
+REPLACE_GETLINE = @REPLACE_GETLINE@
+REPLACE_GETPAGESIZE = @REPLACE_GETPAGESIZE@
+REPLACE_GETTIMEOFDAY = @REPLACE_GETTIMEOFDAY@
+REPLACE_ISWCNTRL = @REPLACE_ISWCNTRL@
+REPLACE_LCHOWN = @REPLACE_LCHOWN@
+REPLACE_LINK = @REPLACE_LINK@
+REPLACE_LINKAT = @REPLACE_LINKAT@
+REPLACE_LOCALTIME_R = @REPLACE_LOCALTIME_R@
+REPLACE_LSEEK = @REPLACE_LSEEK@
+REPLACE_LSTAT = @REPLACE_LSTAT@
+REPLACE_MBRLEN = @REPLACE_MBRLEN@
+REPLACE_MBRTOWC = @REPLACE_MBRTOWC@
+REPLACE_MBSINIT = @REPLACE_MBSINIT@
+REPLACE_MBSNRTOWCS = @REPLACE_MBSNRTOWCS@
+REPLACE_MBSRTOWCS = @REPLACE_MBSRTOWCS@
+REPLACE_MBSTATE_T = @REPLACE_MBSTATE_T@
+REPLACE_MEMCHR = @REPLACE_MEMCHR@
+REPLACE_MEMMEM = @REPLACE_MEMMEM@
+REPLACE_MKDIR = @REPLACE_MKDIR@
+REPLACE_MKFIFO = @REPLACE_MKFIFO@
+REPLACE_MKNOD = @REPLACE_MKNOD@
+REPLACE_MKSTEMP = @REPLACE_MKSTEMP@
+REPLACE_MKTIME = @REPLACE_MKTIME@
+REPLACE_NANOSLEEP = @REPLACE_NANOSLEEP@
+REPLACE_NULL = @REPLACE_NULL@
+REPLACE_OBSTACK_PRINTF = @REPLACE_OBSTACK_PRINTF@
+REPLACE_OPEN = @REPLACE_OPEN@
+REPLACE_OPENAT = @REPLACE_OPENAT@
+REPLACE_OPENDIR = @REPLACE_OPENDIR@
+REPLACE_PERROR = @REPLACE_PERROR@
+REPLACE_POPEN = @REPLACE_POPEN@
+REPLACE_PREAD = @REPLACE_PREAD@
+REPLACE_PRINTF = @REPLACE_PRINTF@
+REPLACE_PUTENV = @REPLACE_PUTENV@
+REPLACE_READLINK = @REPLACE_READLINK@
+REPLACE_REALPATH = @REPLACE_REALPATH@
+REPLACE_REMOVE = @REPLACE_REMOVE@
+REPLACE_RENAME = @REPLACE_RENAME@
+REPLACE_RENAMEAT = @REPLACE_RENAMEAT@
+REPLACE_RMDIR = @REPLACE_RMDIR@
+REPLACE_SETENV = @REPLACE_SETENV@
+REPLACE_SLEEP = @REPLACE_SLEEP@
+REPLACE_SNPRINTF = @REPLACE_SNPRINTF@
+REPLACE_SPRINTF = @REPLACE_SPRINTF@
+REPLACE_STAT = @REPLACE_STAT@
+REPLACE_STDIO_WRITE_FUNCS = @REPLACE_STDIO_WRITE_FUNCS@
+REPLACE_STRCASESTR = @REPLACE_STRCASESTR@
+REPLACE_STRDUP = @REPLACE_STRDUP@
+REPLACE_STRERROR = @REPLACE_STRERROR@
+REPLACE_STRNDUP = @REPLACE_STRNDUP@
+REPLACE_STRPTIME = @REPLACE_STRPTIME@
+REPLACE_STRSIGNAL = @REPLACE_STRSIGNAL@
+REPLACE_STRSTR = @REPLACE_STRSTR@
+REPLACE_STRTOD = @REPLACE_STRTOD@
+REPLACE_STRTOK_R = @REPLACE_STRTOK_R@
+REPLACE_SYMLINK = @REPLACE_SYMLINK@
+REPLACE_TIMEGM = @REPLACE_TIMEGM@
+REPLACE_UNLINK = @REPLACE_UNLINK@
+REPLACE_UNLINKAT = @REPLACE_UNLINKAT@
+REPLACE_UNSETENV = @REPLACE_UNSETENV@
+REPLACE_USLEEP = @REPLACE_USLEEP@
+REPLACE_UTIMENSAT = @REPLACE_UTIMENSAT@
+REPLACE_VASPRINTF = @REPLACE_VASPRINTF@
+REPLACE_VDPRINTF = @REPLACE_VDPRINTF@
+REPLACE_VFPRINTF = @REPLACE_VFPRINTF@
+REPLACE_VPRINTF = @REPLACE_VPRINTF@
+REPLACE_VSNPRINTF = @REPLACE_VSNPRINTF@
+REPLACE_VSPRINTF = @REPLACE_VSPRINTF@
+REPLACE_WCRTOMB = @REPLACE_WCRTOMB@
+REPLACE_WCSNRTOMBS = @REPLACE_WCSNRTOMBS@
+REPLACE_WCSRTOMBS = @REPLACE_WCSRTOMBS@
+REPLACE_WCTOB = @REPLACE_WCTOB@
+REPLACE_WCWIDTH = @REPLACE_WCWIDTH@
+REPLACE_WRITE = @REPLACE_WRITE@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SIG_ATOMIC_T_SUFFIX = @SIG_ATOMIC_T_SUFFIX@
+SIZE_T_SUFFIX = @SIZE_T_SUFFIX@
+STDARG_H = @STDARG_H@
+STDBOOL_H = @STDBOOL_H@
+STDDEF_H = @STDDEF_H@
+STDINT_H = @STDINT_H@
+STRIP = @STRIP@
+SYSEXITS_H = @SYSEXITS_H@
+SYS_TIME_H_DEFINES_STRUCT_TIMESPEC = @SYS_TIME_H_DEFINES_STRUCT_TIMESPEC@
+TIME_H_DEFINES_STRUCT_TIMESPEC = @TIME_H_DEFINES_STRUCT_TIMESPEC@
+UINT32_MAX_LT_UINTMAX_MAX = @UINT32_MAX_LT_UINTMAX_MAX@
+UINT64_MAX_EQ_ULONG_MAX = @UINT64_MAX_EQ_ULONG_MAX@
+UNDEFINE_STRTOK_R = @UNDEFINE_STRTOK_R@
+UNISTD_H_HAVE_WINSOCK2_H = @UNISTD_H_HAVE_WINSOCK2_H@
+UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS = @UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+WCHAR_T_SUFFIX = @WCHAR_T_SUFFIX@
+WINT_T_SUFFIX = @WINT_T_SUFFIX@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gl_LIBOBJS = @gl_LIBOBJS@
+gl_LTLIBOBJS = @gl_LTLIBOBJS@
+gltests_LIBOBJS = @gltests_LIBOBJS@
+gltests_LTLIBOBJS = @gltests_LTLIBOBJS@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+INCLUDES = -I. -I.. -I$(top_srcdir)/gnu -I$(top_builddir)/gnu -I$(top_srcdir)/lib -I$(top_builddir)/lib
+cpio_SOURCES = \
+ copyin.c\
+ copyout.c\
+ copypass.c\
+ defer.c\
+ dstring.c\
+ global.c\
+ fatal.c\
+ main.c\
+ tar.c\
+ util.c\
+ filemode.c\
+ idcache.c\
+ makepath.c\
+ userspec.c
+
+noinst_HEADERS = \
+ cpio.h\
+ cpiohdr.h\
+ tar.h\
+ tarhdr.h\
+ defer.h\
+ dstring.h\
+ extern.h\
+ filetypes.h\
+ safe-stat.h
+
+LDADD = ../lib/libpax.a ../gnu/libgnu.a @INTLLIBS@
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits src/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnits src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p; \
+ then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+
+installcheck-binPROGRAMS: $(bin_PROGRAMS)
+ bad=0; pid=$$$$; list="$(bin_PROGRAMS)"; for p in $$list; do \
+ case ' $(AM_INSTALLCHECK_STD_OPTIONS_EXEMPT) ' in \
+ *" $$p "* | *" $(srcdir)/$$p "*) continue;; \
+ esac; \
+ f=`echo "$$p" | \
+ sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ for opt in --help --version; do \
+ if "$(DESTDIR)$(bindir)/$$f" $$opt >c$${pid}_.out \
+ 2>c$${pid}_.err </dev/null \
+ && test -n "`cat c$${pid}_.out`" \
+ && test -z "`cat c$${pid}_.err`"; then :; \
+ else echo "$$f does not support $$opt" 1>&2; bad=1; fi; \
+ done; \
+ done; rm -f c$${pid}_.???; exit $$bad
+cpio$(EXEEXT): $(cpio_OBJECTS) $(cpio_DEPENDENCIES)
+ @rm -f cpio$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(cpio_OBJECTS) $(cpio_LDADD) $(LIBS)
+mt$(EXEEXT): $(mt_OBJECTS) $(mt_DEPENDENCIES)
+ @rm -f mt$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(mt_OBJECTS) $(mt_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/copyin.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/copyout.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/copypass.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/defer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dstring.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fatal.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filemode.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/global.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/idcache.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/makepath.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mt.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tar.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/userspec.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am: installcheck-binPROGRAMS
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+ clean-generic ctags distclean distclean-compile \
+ distclean-generic distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-binPROGRAMS \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installcheck-binPROGRAMS \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic pdf pdf-am \
+ ps ps-am tags uninstall uninstall-am uninstall-binPROGRAMS
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/copyin.c b/src/copyin.c
new file mode 100644
index 0000000..ac921e1
--- /dev/null
+++ b/src/copyin.c
@@ -0,0 +1,1502 @@
+/* copyin.c - extract or list a cpio archive
+ Copyright (C) 1990, 1991, 1992, 2001, 2002, 2003, 2004, 2005, 2006,
+ 2007, 2009, 2010 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 3, 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA. */
+
+#include <system.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "filetypes.h"
+#include "cpiohdr.h"
+#include "dstring.h"
+#include "extern.h"
+#include "defer.h"
+#include <rmt.h>
+#ifndef FNM_PATHNAME
+# include <fnmatch.h>
+#endif
+
+#ifndef HAVE_LCHOWN
+# define lchown(f,u,g) 0
+#endif
+
+static void copyin_regular_file(struct cpio_file_stat* file_hdr,
+ int in_file_des);
+
+void
+warn_junk_bytes (long bytes_skipped)
+{
+ error (0, 0, ngettext ("warning: skipped %ld byte of junk",
+ "warning: skipped %ld bytes of junk", bytes_skipped),
+ bytes_skipped);
+}
+
+
+static int
+query_rename(struct cpio_file_stat* file_hdr, FILE *tty_in, FILE *tty_out,
+ FILE *rename_in)
+{
+ char *str_res; /* Result for string function. */
+ static dynamic_string new_name; /* New file name for rename option. */
+ static int initialized_new_name = false;
+ if (!initialized_new_name)
+ {
+ ds_init (&new_name, 128);
+ initialized_new_name = true;
+ }
+
+ if (rename_flag)
+ {
+ fprintf (tty_out, _("rename %s -> "), file_hdr->c_name);
+ fflush (tty_out);
+ str_res = ds_fgets (tty_in, &new_name);
+ }
+ else
+ {
+ str_res = ds_fgetstr (rename_in, &new_name, '\n');
+ }
+ if (str_res == NULL || str_res[0] == 0)
+ {
+ return -1;
+ }
+ else
+ /* Debian hack: file_hrd.c_name is sometimes set to
+ point to static memory by code in tar.c. This
+ causes a segfault. This has been fixed and an
+ additional check to ensure that the file name
+ is not too long has been added. (Reported by
+ Horst Knobloch.) This bug has been reported to
+ "bug-gnu-utils@prep.ai.mit.edu". (99/1/6) -BEM */
+ {
+ if (archive_format != arf_tar && archive_format != arf_ustar)
+ {
+ free (file_hdr->c_name);
+ file_hdr->c_name = xstrdup (new_name.ds_string);
+ }
+ else
+ {
+ if (is_tar_filename_too_long (new_name.ds_string))
+ error (0, 0, _("%s: file name too long"),
+ new_name.ds_string);
+ else
+ strcpy (file_hdr->c_name, new_name.ds_string);
+ }
+ }
+ return 0;
+}
+
+/* Skip the padding on IN_FILE_DES after a header or file,
+ up to the next header.
+ The number of bytes skipped is based on OFFSET -- the current offset
+ from the last start of a header (or file) -- and the current
+ header type. */
+
+static void
+tape_skip_padding (int in_file_des, off_t offset)
+{
+ off_t pad;
+
+ if (archive_format == arf_crcascii || archive_format == arf_newascii)
+ pad = (4 - (offset % 4)) % 4;
+ else if (archive_format == arf_binary || archive_format == arf_hpbinary)
+ pad = (2 - (offset % 2)) % 2;
+ else if (archive_format == arf_tar || archive_format == arf_ustar)
+ pad = (512 - (offset % 512)) % 512;
+ else
+ pad = 0;
+
+ if (pad != 0)
+ tape_toss_input (in_file_des, pad);
+}
+
+
+static void
+list_file(struct cpio_file_stat* file_hdr, int in_file_des)
+{
+ if (verbose_flag)
+ {
+#ifdef CP_IFLNK
+ if ((file_hdr->c_mode & CP_IFMT) == CP_IFLNK)
+ {
+ if (archive_format != arf_tar && archive_format != arf_ustar)
+ {
+ char *link_name = NULL; /* Name of hard and symbolic links. */
+
+ link_name = (char *) xmalloc ((unsigned int) file_hdr->c_filesize + 1);
+ link_name[file_hdr->c_filesize] = '\0';
+ tape_buffered_read (link_name, in_file_des, file_hdr->c_filesize);
+ long_format (file_hdr, link_name);
+ free (link_name);
+ tape_skip_padding (in_file_des, file_hdr->c_filesize);
+ return;
+ }
+ else
+ {
+ long_format (file_hdr, file_hdr->c_tar_linkname);
+ return;
+ }
+ }
+ else
+#endif
+ long_format (file_hdr, (char *) 0);
+ }
+ else
+ {
+ /* Debian hack: Modified to print a list of filenames
+ terminiated by a null character when the -t and -0
+ flags are used. This has been submitted as a
+ suggestion to "bug-gnu-utils@prep.ai.mit.edu". -BEM */
+ printf ("%s%c", file_hdr->c_name, name_end);
+ }
+
+ crc = 0;
+ tape_toss_input (in_file_des, file_hdr->c_filesize);
+ tape_skip_padding (in_file_des, file_hdr->c_filesize);
+ if (only_verify_crc_flag)
+ {
+#ifdef CP_IFLNK
+ if ((file_hdr->c_mode & CP_IFMT) == CP_IFLNK)
+ {
+ return; /* links don't have a checksum */
+ }
+#endif
+ if (crc != file_hdr->c_chksum)
+ {
+ error (0, 0, _("%s: checksum error (0x%lx, should be 0x%lx)"),
+ file_hdr->c_name, crc, file_hdr->c_chksum);
+ }
+ }
+}
+
+static int
+try_existing_file (struct cpio_file_stat* file_hdr, int in_file_des,
+ int *existing_dir)
+{
+ struct stat file_stat;
+
+ *existing_dir = false;
+ if (lstat (file_hdr->c_name, &file_stat) == 0)
+ {
+ if (S_ISDIR (file_stat.st_mode)
+ && ((file_hdr->c_mode & CP_IFMT) == CP_IFDIR))
+ {
+ /* If there is already a directory there that
+ we are trying to create, don't complain about
+ it. */
+ *existing_dir = true;
+ return 0;
+ }
+ else if (!unconditional_flag
+ && file_hdr->c_mtime <= file_stat.st_mtime)
+ {
+ error (0, 0, _("%s not created: newer or same age version exists"),
+ file_hdr->c_name);
+ tape_toss_input (in_file_des, file_hdr->c_filesize);
+ tape_skip_padding (in_file_des, file_hdr->c_filesize);
+ return -1; /* Go to the next file. */
+ }
+ else if (S_ISDIR (file_stat.st_mode)
+ ? rmdir (file_hdr->c_name)
+ : unlink (file_hdr->c_name))
+ {
+ error (0, errno, _("cannot remove current %s"),
+ file_hdr->c_name);
+ tape_toss_input (in_file_des, file_hdr->c_filesize);
+ tape_skip_padding (in_file_des, file_hdr->c_filesize);
+ return -1; /* Go to the next file. */
+ }
+ }
+ return 0;
+}
+
+/* The newc and crc formats store multiply linked copies of the same file
+ in the archive only once. The actual data is attached to the last link
+ in the archive, and the other links all have a filesize of 0. When a
+ file in the archive has multiple links and a filesize of 0, its data is
+ probably "attatched" to another file in the archive, so we can't create
+ it right away. We have to "defer" creating it until we have created
+ the file that has the data "attatched" to it. We keep a list of the
+ "defered" links on deferments. */
+
+struct deferment *deferments = NULL;
+
+/* Add a file header to the deferments list. For now they all just
+ go on one list, although we could optimize this if necessary. */
+
+static void
+defer_copyin (struct cpio_file_stat *file_hdr)
+{
+ struct deferment *d;
+ d = create_deferment (file_hdr);
+ d->next = deferments;
+ deferments = d;
+ return;
+}
+
+/* We just created a file that (probably) has some other links to it
+ which have been defered. Go through all of the links on the deferments
+ list and create any which are links to this file. */
+
+static void
+create_defered_links (struct cpio_file_stat *file_hdr)
+{
+ struct deferment *d;
+ struct deferment *d_prev;
+ ino_t ino;
+ int maj;
+ int min;
+ int link_res;
+ ino = file_hdr->c_ino;
+ maj = file_hdr->c_dev_maj;
+ min = file_hdr->c_dev_min;
+ d = deferments;
+ d_prev = NULL;
+ while (d != NULL)
+ {
+ if ( (d->header.c_ino == ino) && (d->header.c_dev_maj == maj)
+ && (d->header.c_dev_min == min) )
+ {
+ struct deferment *d_free;
+ link_res = link_to_name (d->header.c_name, file_hdr->c_name);
+ if (link_res < 0)
+ {
+ error (0, errno, _("cannot link %s to %s"),
+ d->header.c_name, file_hdr->c_name);
+ }
+ if (d_prev != NULL)
+ d_prev->next = d->next;
+ else
+ deferments = d->next;
+ d_free = d;
+ d = d->next;
+ free_deferment (d_free);
+ }
+ else
+ {
+ d_prev = d;
+ d = d->next;
+ }
+ }
+}
+
+/* We are skipping a file but there might be other links to it that we
+ did not skip, so we have to copy its data for the other links. Find
+ the first link that we didn't skip and try to create that. That will
+ then create the other deferred links. */
+
+static int
+create_defered_links_to_skipped (struct cpio_file_stat *file_hdr,
+ int in_file_des)
+{
+ struct deferment *d;
+ struct deferment *d_prev;
+ ino_t ino;
+ int maj;
+ int min;
+ if (file_hdr->c_filesize == 0)
+ {
+ /* The file doesn't have any data attached to it so we don't have
+ to bother. */
+ return -1;
+ }
+ ino = file_hdr->c_ino;
+ maj = file_hdr->c_dev_maj;
+ min = file_hdr->c_dev_min;
+ d = deferments;
+ d_prev = NULL;
+ while (d != NULL)
+ {
+ if ( (d->header.c_ino == ino) && (d->header.c_dev_maj == maj)
+ && (d->header.c_dev_min == min) )
+ {
+ if (d_prev != NULL)
+ d_prev->next = d->next;
+ else
+ deferments = d->next;
+ free (file_hdr->c_name);
+ file_hdr->c_name = xstrdup(d->header.c_name);
+ free_deferment (d);
+ copyin_regular_file(file_hdr, in_file_des);
+ return 0;
+ }
+ else
+ {
+ d_prev = d;
+ d = d->next;
+ }
+ }
+ return -1;
+}
+
+/* If we had a multiply linked file that really was empty then we would
+ have defered all of its links, since we never found any with data
+ "attached", and they will still be on the deferment list even when
+ we are done reading the whole archive. Write out all of these
+ empty links that are still on the deferments list. */
+
+static void
+create_final_defers ()
+{
+ struct deferment *d;
+ int link_res;
+ int out_file_des;
+
+ for (d = deferments; d != NULL; d = d->next)
+ {
+ /* Debian hack: A line, which could cause an endless loop, was
+ removed (97/1/2). It was reported by Ronald F. Guilmette to
+ the upstream maintainers. -BEM */
+ /* Debian hack: This was reported by Horst Knobloch. This bug has
+ been reported to "bug-gnu-utils@prep.ai.mit.edu". (99/1/6) -BEM
+ */
+ link_res = link_to_maj_min_ino (d->header.c_name,
+ d->header.c_dev_maj, d->header.c_dev_min,
+ d->header.c_ino);
+ if (link_res == 0)
+ {
+ continue;
+ }
+ out_file_des = open (d->header.c_name,
+ O_CREAT | O_WRONLY | O_BINARY, 0600);
+ if (out_file_des < 0 && create_dir_flag)
+ {
+ create_all_directories (d->header.c_name);
+ out_file_des = open (d->header.c_name,
+ O_CREAT | O_WRONLY | O_BINARY,
+ 0600);
+ }
+ if (out_file_des < 0)
+ {
+ open_error (d->header.c_name);
+ continue;
+ }
+
+ set_perms (out_file_des, &d->header);
+
+ if (close (out_file_des) < 0)
+ close_error (d->header.c_name);
+
+ }
+}
+
+static void
+copyin_regular_file (struct cpio_file_stat* file_hdr, int in_file_des)
+{
+ int out_file_des; /* Output file descriptor. */
+
+ if (to_stdout_option)
+ out_file_des = STDOUT_FILENO;
+ else
+ {
+ /* Can the current file be linked to a previously copied file? */
+ if (file_hdr->c_nlink > 1
+ && (archive_format == arf_newascii
+ || archive_format == arf_crcascii) )
+ {
+ int link_res;
+ if (file_hdr->c_filesize == 0)
+ {
+ /* The newc and crc formats store multiply linked copies
+ of the same file in the archive only once. The
+ actual data is attached to the last link in the
+ archive, and the other links all have a filesize
+ of 0. Since this file has multiple links and a
+ filesize of 0, its data is probably attatched to
+ another file in the archive. Save the link, and
+ process it later when we get the actual data. We
+ can't just create it with length 0 and add the
+ data later, in case the file is readonly. We still
+ lose if its parent directory is readonly (and we aren't
+ running as root), but there's nothing we can do about
+ that. */
+ defer_copyin (file_hdr);
+ tape_toss_input (in_file_des, file_hdr->c_filesize);
+ tape_skip_padding (in_file_des, file_hdr->c_filesize);
+ return;
+ }
+ /* If the file has data (filesize != 0), then presumably
+ any other links have already been defer_copyin'ed(),
+ but GNU cpio version 2.0-2.2 didn't do that, so we
+ still have to check for links here (and also in case
+ the archive was created and later appeneded to). */
+ /* Debian hack: (97/1/2) This was reported by Ronald
+ F. Guilmette to the upstream maintainers. -BEM */
+ link_res = link_to_maj_min_ino (file_hdr->c_name,
+ file_hdr->c_dev_maj, file_hdr->c_dev_min,
+ file_hdr->c_ino);
+ if (link_res == 0)
+ {
+ tape_toss_input (in_file_des, file_hdr->c_filesize);
+ tape_skip_padding (in_file_des, file_hdr->c_filesize);
+ return;
+ }
+ }
+ else if (file_hdr->c_nlink > 1
+ && archive_format != arf_tar
+ && archive_format != arf_ustar)
+ {
+ int link_res;
+ /* Debian hack: (97/1/2) This was reported by Ronald
+ F. Guilmette to the upstream maintainers. -BEM */
+ link_res = link_to_maj_min_ino (file_hdr->c_name,
+ file_hdr->c_dev_maj,
+ file_hdr->c_dev_min,
+ file_hdr->c_ino);
+ if (link_res == 0)
+ {
+ tape_toss_input (in_file_des, file_hdr->c_filesize);
+ tape_skip_padding (in_file_des, file_hdr->c_filesize);
+ return;
+ }
+ }
+ else if ((archive_format == arf_tar || archive_format == arf_ustar)
+ && file_hdr->c_tar_linkname
+ && file_hdr->c_tar_linkname[0] != '\0')
+ {
+ int link_res;
+ link_res = link_to_name (file_hdr->c_name, file_hdr->c_tar_linkname);
+ if (link_res < 0)
+ {
+ error (0, errno, _("cannot link %s to %s"),
+ file_hdr->c_tar_linkname, file_hdr->c_name);
+ }
+ return;
+ }
+
+ /* If not linked, copy the contents of the file. */
+ out_file_des = open (file_hdr->c_name,
+ O_CREAT | O_WRONLY | O_BINARY, 0600);
+
+ if (out_file_des < 0 && create_dir_flag)
+ {
+ create_all_directories (file_hdr->c_name);
+ out_file_des = open (file_hdr->c_name,
+ O_CREAT | O_WRONLY | O_BINARY,
+ 0600);
+ }
+
+ if (out_file_des < 0)
+ {
+ open_error (file_hdr->c_name);
+ tape_toss_input (in_file_des, file_hdr->c_filesize);
+ tape_skip_padding (in_file_des, file_hdr->c_filesize);
+ return;
+ }
+ }
+
+ crc = 0;
+ if (swap_halfwords_flag)
+ {
+ if ((file_hdr->c_filesize % 4) == 0)
+ swapping_halfwords = true;
+ else
+ error (0, 0, _("cannot swap halfwords of %s: odd number of halfwords"),
+ file_hdr->c_name);
+ }
+ if (swap_bytes_flag)
+ {
+ if ((file_hdr->c_filesize % 2) == 0)
+ swapping_bytes = true;
+ else
+ error (0, 0, _("cannot swap bytes of %s: odd number of bytes"),
+ file_hdr->c_name);
+ }
+ copy_files_tape_to_disk (in_file_des, out_file_des, file_hdr->c_filesize);
+ disk_empty_output_buffer (out_file_des);
+
+ if (to_stdout_option)
+ {
+ if (archive_format == arf_crcascii)
+ {
+ if (crc != file_hdr->c_chksum)
+ error (0, 0, _("%s: checksum error (0x%lx, should be 0x%lx)"),
+ file_hdr->c_name, crc, file_hdr->c_chksum);
+ }
+ tape_skip_padding (in_file_des, file_hdr->c_filesize);
+ return;
+ }
+
+ /* Debian hack to fix a bug in the --sparse option.
+ This bug has been reported to
+ "bug-gnu-utils@prep.ai.mit.edu". (96/7/10) -BEM */
+ if (delayed_seek_count > 0)
+ {
+ lseek (out_file_des, delayed_seek_count-1, SEEK_CUR);
+ write (out_file_des, "", 1);
+ delayed_seek_count = 0;
+ }
+
+ set_perms (out_file_des, file_hdr);
+
+ if (close (out_file_des) < 0)
+ close_error (file_hdr->c_name);
+
+ if (archive_format == arf_crcascii)
+ {
+ if (crc != file_hdr->c_chksum)
+ error (0, 0, _("%s: checksum error (0x%lx, should be 0x%lx)"),
+ file_hdr->c_name, crc, file_hdr->c_chksum);
+ }
+
+ tape_skip_padding (in_file_des, file_hdr->c_filesize);
+ if (file_hdr->c_nlink > 1
+ && (archive_format == arf_newascii || archive_format == arf_crcascii) )
+ {
+ /* (see comment above for how the newc and crc formats
+ store multiple links). Now that we have the data
+ for this file, create any other links to it which
+ we defered. */
+ create_defered_links (file_hdr);
+ }
+}
+
+static void
+copyin_device (struct cpio_file_stat* file_hdr)
+{
+ int res; /* Result of various function calls. */
+
+ if (to_stdout_option)
+ return;
+
+ if (file_hdr->c_nlink > 1 && archive_format != arf_tar
+ && archive_format != arf_ustar)
+ {
+ int link_res;
+ /* Debian hack: This was reported by Horst
+ Knobloch. This bug has been reported to
+ "bug-gnu-utils@prep.ai.mit.edu". (99/1/6) -BEM */
+ link_res = link_to_maj_min_ino (file_hdr->c_name,
+ file_hdr->c_dev_maj, file_hdr->c_dev_min,
+ file_hdr->c_ino);
+ if (link_res == 0)
+ {
+ return;
+ }
+ }
+ else if (archive_format == arf_ustar &&
+ file_hdr->c_tar_linkname &&
+ file_hdr->c_tar_linkname [0] != '\0')
+ {
+ int link_res;
+ link_res = link_to_name (file_hdr->c_name,
+ file_hdr->c_tar_linkname);
+ if (link_res < 0)
+ {
+ error (0, errno, _("cannot link %s to %s"),
+ file_hdr->c_tar_linkname, file_hdr->c_name);
+ /* Something must be wrong, because we couldn't
+ find the file to link to. But can we assume
+ that the device maj/min numbers are correct
+ and fall through to the mknod? It's probably
+ safer to just return, rather than possibly
+ creating a bogus device file. */
+ }
+ return;
+ }
+
+ res = mknod (file_hdr->c_name, file_hdr->c_mode,
+ makedev (file_hdr->c_rdev_maj, file_hdr->c_rdev_min));
+ if (res < 0 && create_dir_flag)
+ {
+ create_all_directories (file_hdr->c_name);
+ res = mknod (file_hdr->c_name, file_hdr->c_mode,
+ makedev (file_hdr->c_rdev_maj, file_hdr->c_rdev_min));
+ }
+ if (res < 0)
+ {
+ mknod_error (file_hdr->c_name);
+ return;
+ }
+ if (!no_chown_flag)
+ {
+ uid_t uid = set_owner_flag ? set_owner : file_hdr->c_uid;
+ gid_t gid = set_group_flag ? set_group : file_hdr->c_gid;
+ if ((chown (file_hdr->c_name, uid, gid) < 0)
+ && errno != EPERM)
+ chown_error_details (file_hdr->c_name, uid, gid);
+ }
+ /* chown may have turned off some permissions we wanted. */
+ if (chmod (file_hdr->c_name, file_hdr->c_mode) < 0)
+ chmod_error_details (file_hdr->c_name, file_hdr->c_mode);
+ if (retain_time_flag)
+ set_file_times (-1, file_hdr->c_name, file_hdr->c_mtime,
+ file_hdr->c_mtime);
+}
+
+static void
+copyin_link(struct cpio_file_stat *file_hdr, int in_file_des)
+{
+ char *link_name = NULL; /* Name of hard and symbolic links. */
+ int res; /* Result of various function calls. */
+
+ if (to_stdout_option)
+ return;
+
+ if (archive_format != arf_tar && archive_format != arf_ustar)
+ {
+ link_name = (char *) xmalloc ((unsigned int) file_hdr->c_filesize + 1);
+ link_name[file_hdr->c_filesize] = '\0';
+ tape_buffered_read (link_name, in_file_des, file_hdr->c_filesize);
+ tape_skip_padding (in_file_des, file_hdr->c_filesize);
+ }
+ else
+ {
+ link_name = xstrdup (file_hdr->c_tar_linkname);
+ }
+
+ res = UMASKED_SYMLINK (link_name, file_hdr->c_name,
+ file_hdr->c_mode);
+ if (res < 0 && create_dir_flag)
+ {
+ create_all_directories (file_hdr->c_name);
+ res = UMASKED_SYMLINK (link_name, file_hdr->c_name,
+ file_hdr->c_mode);
+ }
+ if (res < 0)
+ {
+ error (0, errno, _("%s: Cannot symlink to %s"),
+ quotearg_colon (link_name), quote_n (1, file_hdr->c_name));
+ free (link_name);
+ return;
+ }
+ if (!no_chown_flag)
+ {
+ uid_t uid = set_owner_flag ? set_owner : file_hdr->c_uid;
+ gid_t gid = set_group_flag ? set_group : file_hdr->c_gid;
+ if ((lchown (file_hdr->c_name, uid, gid) < 0)
+ && errno != EPERM)
+ chown_error_details (file_hdr->c_name, uid, gid);
+ }
+ free (link_name);
+}
+
+static void
+copyin_file (struct cpio_file_stat *file_hdr, int in_file_des)
+{
+ int existing_dir;
+
+ if (!to_stdout_option
+ && try_existing_file (file_hdr, in_file_des, &existing_dir) < 0)
+ return;
+
+ /* Do the real copy or link. */
+ switch (file_hdr->c_mode & CP_IFMT)
+ {
+ case CP_IFREG:
+ copyin_regular_file (file_hdr, in_file_des);
+ break;
+
+ case CP_IFDIR:
+ cpio_create_dir (file_hdr, existing_dir);
+ break;
+
+ case CP_IFCHR:
+ case CP_IFBLK:
+#ifdef CP_IFSOCK
+ case CP_IFSOCK:
+#endif
+#ifdef CP_IFIFO
+ case CP_IFIFO:
+#endif
+ copyin_device (file_hdr);
+ break;
+
+#ifdef CP_IFLNK
+ case CP_IFLNK:
+ copyin_link (file_hdr, in_file_des);
+ break;
+#endif
+
+ default:
+ error (0, 0, _("%s: unknown file type"), file_hdr->c_name);
+ tape_toss_input (in_file_des, file_hdr->c_filesize);
+ tape_skip_padding (in_file_des, file_hdr->c_filesize);
+ }
+}
+
+
+/* Current time for verbose table. */
+static time_t current_time;
+
+
+/* Print the file described by FILE_HDR in long format.
+ If LINK_NAME is nonzero, it is the name of the file that
+ this file is a symbolic link to. */
+
+void
+long_format (struct cpio_file_stat *file_hdr, char *link_name)
+{
+ char mbuf[11];
+ char tbuf[40];
+ time_t when;
+
+ mode_string (file_hdr->c_mode, mbuf);
+ mbuf[10] = '\0';
+
+ /* Get time values ready to print. */
+ when = file_hdr->c_mtime;
+ strcpy (tbuf, ctime (&when));
+ if (current_time - when > 6L * 30L * 24L * 60L * 60L
+ || current_time - when < 0L)
+ {
+ /* The file is older than 6 months, or in the future.
+ Show the year instead of the time of day. */
+ strcpy (tbuf + 11, tbuf + 19);
+ }
+ tbuf[16] = '\0';
+
+ printf ("%s %3lu ", mbuf, (unsigned long) file_hdr->c_nlink);
+
+ if (numeric_uid)
+ printf ("%-8u %-8u ", (unsigned int) file_hdr->c_uid,
+ (unsigned int) file_hdr->c_gid);
+ else
+ printf ("%-8.8s %-8.8s ", getuser (file_hdr->c_uid),
+ getgroup (file_hdr->c_gid));
+
+ if ((file_hdr->c_mode & CP_IFMT) == CP_IFCHR
+ || (file_hdr->c_mode & CP_IFMT) == CP_IFBLK)
+ printf ("%3lu, %3lu ", file_hdr->c_rdev_maj,
+ file_hdr->c_rdev_min);
+ else
+ printf ("%8"PRIuMAX" ", (uintmax_t) file_hdr->c_filesize);
+
+ printf ("%s ", tbuf + 4);
+
+ print_name_with_quoting (file_hdr->c_name);
+ if (link_name)
+ {
+ printf (" -> ");
+ print_name_with_quoting (link_name);
+ }
+ putc ('\n', stdout);
+}
+
+void
+print_name_with_quoting (register char *p)
+{
+ register unsigned char c;
+
+ while ( (c = *p++) )
+ {
+ switch (c)
+ {
+ case '\\':
+ printf ("\\\\");
+ break;
+
+ case '\n':
+ printf ("\\n");
+ break;
+
+ case '\b':
+ printf ("\\b");
+ break;
+
+ case '\r':
+ printf ("\\r");
+ break;
+
+ case '\t':
+ printf ("\\t");
+ break;
+
+ case '\f':
+ printf ("\\f");
+ break;
+
+ case ' ':
+ printf ("\\ ");
+ break;
+
+ case '"':
+ printf ("\\\"");
+ break;
+
+ default:
+ if (c > 040 && c < 0177)
+ putchar (c);
+ else
+ printf ("\\%03o", (unsigned int) c);
+ }
+ }
+}
+
+/* Read a pattern file (for the -E option). Put a list of
+ `num_patterns' elements in `save_patterns'. Any patterns that were
+ already in `save_patterns' (from the command line) are preserved. */
+
+static void
+read_pattern_file ()
+{
+ int max_new_patterns;
+ char **new_save_patterns;
+ int new_num_patterns;
+ int i;
+ dynamic_string pattern_name;
+ FILE *pattern_fp;
+
+ if (num_patterns < 0)
+ num_patterns = 0;
+ max_new_patterns = 1 + num_patterns;
+ new_save_patterns = (char **) xmalloc (max_new_patterns * sizeof (char *));
+ new_num_patterns = num_patterns;
+ ds_init (&pattern_name, 128);
+
+ pattern_fp = fopen (pattern_file_name, "r");
+ if (pattern_fp == NULL)
+ open_error (pattern_file_name);
+ while (ds_fgetstr (pattern_fp, &pattern_name, '\n') != NULL)
+ {
+ if (new_num_patterns >= max_new_patterns)
+ {
+ max_new_patterns += 1;
+ new_save_patterns = (char **)
+ xrealloc ((char *) new_save_patterns,
+ max_new_patterns * sizeof (char *));
+ }
+ new_save_patterns[new_num_patterns] = xstrdup (pattern_name.ds_string);
+ ++new_num_patterns;
+ }
+ if (ferror (pattern_fp) || fclose (pattern_fp) == EOF)
+ close_error (pattern_file_name);
+
+ for (i = 0; i < num_patterns; ++i)
+ new_save_patterns[i] = save_patterns[i];
+
+ save_patterns = new_save_patterns;
+ num_patterns = new_num_patterns;
+}
+
+
+uintmax_t
+from_ascii (char const *where, size_t digs, unsigned logbase)
+{
+ uintmax_t value = 0;
+ char const *buf = where;
+ char const *end = buf + digs;
+ int overflow = 0;
+ static char codetab[] = "0123456789ABCDEF";
+
+ for (; *buf == ' '; buf++)
+ {
+ if (buf == end)
+ return 0;
+ }
+
+ if (buf == end || *buf == 0)
+ return 0;
+ while (1)
+ {
+ unsigned d;
+
+ char *p = strchr (codetab, toupper (*buf));
+ if (!p)
+ {
+ error (0, 0, _("Malformed number %.*s"), digs, where);
+ break;
+ }
+
+ d = p - codetab;
+ if ((d >> logbase) > 1)
+ {
+ error (0, 0, _("Malformed number %.*s"), digs, where);
+ break;
+ }
+ value += d;
+ if (++buf == end || *buf == 0)
+ break;
+ overflow |= value ^ (value << logbase >> logbase);
+ value <<= logbase;
+ }
+ if (overflow)
+ error (0, 0, _("Archive value %.*s is out of range"),
+ digs, where);
+ return value;
+}
+
+
+
+/* Return 16-bit integer I with the bytes swapped. */
+#define swab_short(i) ((((i) << 8) & 0xff00) | (((i) >> 8) & 0x00ff))
+
+/* Read the header, including the name of the file, from file
+ descriptor IN_DES into FILE_HDR. */
+
+void
+read_in_header (struct cpio_file_stat *file_hdr, int in_des)
+{
+ union {
+ char str[6];
+ unsigned short num;
+ struct old_cpio_header old_header;
+ } magic;
+ long bytes_skipped = 0; /* Bytes of junk found before magic number. */
+
+ /* Search for a valid magic number. */
+
+ if (archive_format == arf_unknown)
+ {
+ char tmpbuf[512];
+ int check_tar;
+ int peeked_bytes;
+
+ while (archive_format == arf_unknown)
+ {
+ peeked_bytes = tape_buffered_peek (tmpbuf, in_des, 512);
+ if (peeked_bytes < 6)
+ error (1, 0, _("premature end of archive"));
+
+ if (!strncmp (tmpbuf, "070701", 6))
+ archive_format = arf_newascii;
+ else if (!strncmp (tmpbuf, "070707", 6))
+ archive_format = arf_oldascii;
+ else if (!strncmp (tmpbuf, "070702", 6))
+ {
+ archive_format = arf_crcascii;
+ crc_i_flag = true;
+ }
+ else if ((*((unsigned short *) tmpbuf) == 070707) ||
+ (*((unsigned short *) tmpbuf) == swab_short ((unsigned short) 070707)))
+ archive_format = arf_binary;
+ else if (peeked_bytes >= 512
+ && (check_tar = is_tar_header (tmpbuf)))
+ {
+ if (check_tar == 2)
+ archive_format = arf_ustar;
+ else
+ archive_format = arf_tar;
+ }
+ else
+ {
+ tape_buffered_read ((char *) tmpbuf, in_des, 1L);
+ ++bytes_skipped;
+ }
+ }
+ }
+
+ if (archive_format == arf_tar || archive_format == arf_ustar)
+ {
+ if (append_flag)
+ last_header_start = input_bytes - io_block_size +
+ (in_buff - input_buffer);
+ if (bytes_skipped > 0)
+ warn_junk_bytes (bytes_skipped);
+
+ read_in_tar_header (file_hdr, in_des);
+ return;
+ }
+
+ file_hdr->c_tar_linkname = NULL;
+
+ tape_buffered_read (magic.str, in_des, 6L);
+ while (1)
+ {
+ if (append_flag)
+ last_header_start = input_bytes - io_block_size
+ + (in_buff - input_buffer) - 6;
+ if (archive_format == arf_newascii
+ && !strncmp (magic.str, "070701", 6))
+ {
+ if (bytes_skipped > 0)
+ warn_junk_bytes (bytes_skipped);
+ file_hdr->c_magic = 070701;
+ read_in_new_ascii (file_hdr, in_des);
+ break;
+ }
+ if (archive_format == arf_crcascii
+ && !strncmp (magic.str, "070702", 6))
+ {
+ if (bytes_skipped > 0)
+ warn_junk_bytes (bytes_skipped);
+ file_hdr->c_magic = 070702;
+ read_in_new_ascii (file_hdr, in_des);
+ break;
+ }
+ if ( (archive_format == arf_oldascii || archive_format == arf_hpoldascii)
+ && !strncmp (magic.str, "070707", 6))
+ {
+ if (bytes_skipped > 0)
+ warn_junk_bytes (bytes_skipped);
+ file_hdr->c_magic = 070707;
+ read_in_old_ascii (file_hdr, in_des);
+ break;
+ }
+ if ( (archive_format == arf_binary || archive_format == arf_hpbinary)
+ && (magic.num == 070707
+ || magic.num == swab_short ((unsigned short) 070707)))
+ {
+ /* Having to skip 1 byte because of word alignment is normal. */
+ if (bytes_skipped > 0)
+ warn_junk_bytes (bytes_skipped);
+ file_hdr->c_magic = 070707;
+ read_in_binary (file_hdr, &magic.old_header, in_des);
+ break;
+ }
+ bytes_skipped++;
+ memmove (magic.str, magic.str + 1, 5);
+ tape_buffered_read (magic.str, in_des, 1L);
+ }
+}
+
+/* Fill in FILE_HDR by reading an old-format ASCII format cpio header from
+ file descriptor IN_DES, except for the magic number, which is
+ already filled in. */
+
+void
+read_in_old_ascii (struct cpio_file_stat *file_hdr, int in_des)
+{
+ struct old_ascii_header ascii_header;
+ unsigned long dev;
+
+ tape_buffered_read (ascii_header.c_dev, in_des,
+ sizeof ascii_header - sizeof ascii_header.c_magic);
+ dev = FROM_OCTAL (ascii_header.c_dev);
+ file_hdr->c_dev_maj = major (dev);
+ file_hdr->c_dev_min = minor (dev);
+
+ file_hdr->c_ino = FROM_OCTAL (ascii_header.c_ino);
+ file_hdr->c_mode = FROM_OCTAL (ascii_header.c_mode);
+ file_hdr->c_uid = FROM_OCTAL (ascii_header.c_uid);
+ file_hdr->c_gid = FROM_OCTAL (ascii_header.c_gid);
+ file_hdr->c_nlink = FROM_OCTAL (ascii_header.c_nlink);
+ dev = FROM_OCTAL (ascii_header.c_rdev);
+ file_hdr->c_rdev_maj = major (dev);
+ file_hdr->c_rdev_min = minor (dev);
+
+ file_hdr->c_mtime = FROM_OCTAL (ascii_header.c_mtime);
+ file_hdr->c_namesize = FROM_OCTAL (ascii_header.c_namesize);
+ file_hdr->c_filesize = FROM_OCTAL (ascii_header.c_filesize);
+
+ /* Read file name from input. */
+ if (file_hdr->c_name != NULL)
+ free (file_hdr->c_name);
+ file_hdr->c_name = (char *) xmalloc (file_hdr->c_namesize + 1);
+ tape_buffered_read (file_hdr->c_name, in_des, (long) file_hdr->c_namesize);
+
+ /* HP/UX cpio creates archives that look just like ordinary archives,
+ but for devices it sets major = 0, minor = 1, and puts the
+ actual major/minor number in the filesize field. See if this
+ is an HP/UX cpio archive, and if so fix it. We have to do this
+ here because process_copy_in() assumes filesize is always 0
+ for devices. */
+ switch (file_hdr->c_mode & CP_IFMT)
+ {
+ case CP_IFCHR:
+ case CP_IFBLK:
+#ifdef CP_IFSOCK
+ case CP_IFSOCK:
+#endif
+#ifdef CP_IFIFO
+ case CP_IFIFO:
+#endif
+ if (file_hdr->c_filesize != 0
+ && file_hdr->c_rdev_maj == 0
+ && file_hdr->c_rdev_min == 1)
+ {
+ file_hdr->c_rdev_maj = major (file_hdr->c_filesize);
+ file_hdr->c_rdev_min = minor (file_hdr->c_filesize);
+ file_hdr->c_filesize = 0;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/* Fill in FILE_HDR by reading a new-format ASCII format cpio header from
+ file descriptor IN_DES, except for the magic number, which is
+ already filled in. */
+
+void
+read_in_new_ascii (struct cpio_file_stat *file_hdr, int in_des)
+{
+ struct new_ascii_header ascii_header;
+
+ tape_buffered_read (ascii_header.c_ino, in_des,
+ sizeof ascii_header - sizeof ascii_header.c_magic);
+
+ file_hdr->c_ino = FROM_HEX (ascii_header.c_ino);
+ file_hdr->c_mode = FROM_HEX (ascii_header.c_mode);
+ file_hdr->c_uid = FROM_HEX (ascii_header.c_uid);
+ file_hdr->c_gid = FROM_HEX (ascii_header.c_gid);
+ file_hdr->c_nlink = FROM_HEX (ascii_header.c_nlink);
+ file_hdr->c_mtime = FROM_HEX (ascii_header.c_mtime);
+ file_hdr->c_filesize = FROM_HEX (ascii_header.c_filesize);
+ file_hdr->c_dev_maj = FROM_HEX (ascii_header.c_dev_maj);
+ file_hdr->c_dev_min = FROM_HEX (ascii_header.c_dev_min);
+ file_hdr->c_rdev_maj = FROM_HEX (ascii_header.c_rdev_maj);
+ file_hdr->c_rdev_min = FROM_HEX (ascii_header.c_rdev_min);
+ file_hdr->c_namesize = FROM_HEX (ascii_header.c_namesize);
+ file_hdr->c_chksum = FROM_HEX (ascii_header.c_chksum);
+
+ /* Read file name from input. */
+ if (file_hdr->c_name != NULL)
+ free (file_hdr->c_name);
+ file_hdr->c_name = (char *) xmalloc (file_hdr->c_namesize);
+ tape_buffered_read (file_hdr->c_name, in_des, (long) file_hdr->c_namesize);
+
+ /* In SVR4 ASCII format, the amount of space allocated for the header
+ is rounded up to the next long-word, so we might need to drop
+ 1-3 bytes. */
+ tape_skip_padding (in_des, file_hdr->c_namesize + 110);
+}
+
+/* Fill in FILE_HDR by reading a binary format cpio header from
+ file descriptor IN_DES, except for the first 6 bytes (the magic
+ number, device, and inode number), which are already filled in. */
+
+void
+read_in_binary (struct cpio_file_stat *file_hdr,
+ struct old_cpio_header *short_hdr,
+ int in_des)
+{
+ file_hdr->c_magic = short_hdr->c_magic;
+
+ tape_buffered_read (((char *) short_hdr) + 6, in_des,
+ sizeof *short_hdr - 6 /* = 20 */);
+
+ /* If the magic number is byte swapped, fix the header. */
+ if (file_hdr->c_magic == swab_short ((unsigned short) 070707))
+ {
+ static int warned = 0;
+
+ /* Alert the user that they might have to do byte swapping on
+ the file contents. */
+ if (warned == 0)
+ {
+ error (0, 0, _("warning: archive header has reverse byte-order"));
+ warned = 1;
+ }
+ swab_array ((char *) short_hdr, 13);
+ }
+
+ file_hdr->c_dev_maj = major (short_hdr->c_dev);
+ file_hdr->c_dev_min = minor (short_hdr->c_dev);
+ file_hdr->c_ino = short_hdr->c_ino;
+ file_hdr->c_mode = short_hdr->c_mode;
+ file_hdr->c_uid = short_hdr->c_uid;
+ file_hdr->c_gid = short_hdr->c_gid;
+ file_hdr->c_nlink = short_hdr->c_nlink;
+ file_hdr->c_rdev_maj = major (short_hdr->c_rdev);
+ file_hdr->c_rdev_min = minor (short_hdr->c_rdev);
+ file_hdr->c_mtime = (unsigned long) short_hdr->c_mtimes[0] << 16
+ | short_hdr->c_mtimes[1];
+
+ file_hdr->c_namesize = short_hdr->c_namesize;
+ file_hdr->c_filesize = (unsigned long) short_hdr->c_filesizes[0] << 16
+ | short_hdr->c_filesizes[1];
+
+ /* Read file name from input. */
+ if (file_hdr->c_name != NULL)
+ free (file_hdr->c_name);
+ file_hdr->c_name = (char *) xmalloc (file_hdr->c_namesize);
+ tape_buffered_read (file_hdr->c_name, in_des, (long) file_hdr->c_namesize);
+
+ /* In binary mode, the amount of space allocated in the header for
+ the filename is `c_namesize' rounded up to the next short-word,
+ so we might need to drop a byte. */
+ if (file_hdr->c_namesize % 2)
+ tape_toss_input (in_des, 1L);
+
+ /* HP/UX cpio creates archives that look just like ordinary archives,
+ but for devices it sets major = 0, minor = 1, and puts the
+ actual major/minor number in the filesize field. See if this
+ is an HP/UX cpio archive, and if so fix it. We have to do this
+ here because process_copy_in() assumes filesize is always 0
+ for devices. */
+ switch (file_hdr->c_mode & CP_IFMT)
+ {
+ case CP_IFCHR:
+ case CP_IFBLK:
+#ifdef CP_IFSOCK
+ case CP_IFSOCK:
+#endif
+#ifdef CP_IFIFO
+ case CP_IFIFO:
+#endif
+ if (file_hdr->c_filesize != 0
+ && file_hdr->c_rdev_maj == 0
+ && file_hdr->c_rdev_min == 1)
+ {
+ file_hdr->c_rdev_maj = major (file_hdr->c_filesize);
+ file_hdr->c_rdev_min = minor (file_hdr->c_filesize);
+ file_hdr->c_filesize = 0;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/* Exchange the bytes of each element of the array of COUNT shorts
+ starting at PTR. */
+
+void
+swab_array (char *ptr, int count)
+{
+ char tmp;
+
+ while (count-- > 0)
+ {
+ tmp = *ptr;
+ *ptr = *(ptr + 1);
+ ++ptr;
+ *ptr = tmp;
+ ++ptr;
+ }
+}
+
+/* Read the collection from standard input and create files
+ in the file system. */
+
+void
+process_copy_in ()
+{
+ char done = false; /* True if trailer reached. */
+ FILE *tty_in = NULL; /* Interactive file for rename option. */
+ FILE *tty_out = NULL; /* Interactive file for rename option. */
+ FILE *rename_in = NULL; /* Batch file for rename option. */
+ struct stat file_stat; /* Output file stat record. */
+ struct cpio_file_stat file_hdr; /* Output header information. */
+ int in_file_des; /* Input file descriptor. */
+ char skip_file; /* Flag for use with patterns. */
+ int i; /* Loop index variable. */
+
+ newdir_umask = umask (0); /* Reset umask to preserve modes of
+ created files */
+
+ /* Initialize the copy in. */
+ if (pattern_file_name)
+ {
+ read_pattern_file ();
+ }
+ file_hdr.c_name = NULL;
+
+ if (rename_batch_file)
+ {
+ rename_in = fopen (rename_batch_file, "r");
+ if (rename_in == NULL)
+ {
+ error (2, errno, TTY_NAME);
+ }
+ }
+ else if (rename_flag)
+ {
+ /* Open interactive file pair for rename operation. */
+ tty_in = fopen (TTY_NAME, "r");
+ if (tty_in == NULL)
+ {
+ error (2, errno, TTY_NAME);
+ }
+ tty_out = fopen (TTY_NAME, "w");
+ if (tty_out == NULL)
+ {
+ error (2, errno, TTY_NAME);
+ }
+ }
+
+ /* Get date and time if needed for processing the table option. */
+ if (table_flag && verbose_flag)
+ {
+ time (&current_time);
+ }
+
+ /* Check whether the input file might be a tape. */
+ in_file_des = archive_des;
+ if (_isrmt (in_file_des))
+ {
+ input_is_special = 1;
+ input_is_seekable = 0;
+ }
+ else
+ {
+ if (fstat (in_file_des, &file_stat))
+ error (1, errno, _("standard input is closed"));
+ input_is_special =
+#ifdef S_ISBLK
+ S_ISBLK (file_stat.st_mode) ||
+#endif
+ S_ISCHR (file_stat.st_mode);
+ input_is_seekable = S_ISREG (file_stat.st_mode);
+ }
+ output_is_seekable = true;
+
+ /* While there is more input in the collection, process the input. */
+ while (!done)
+ {
+ swapping_halfwords = swapping_bytes = false;
+
+ /* Start processing the next file by reading the header. */
+ read_in_header (&file_hdr, in_file_des);
+
+#ifdef DEBUG_CPIO
+ if (debug_flag)
+ {
+ struct cpio_file_stat *h;
+ h = &file_hdr;
+ fprintf (stderr,
+ "magic = 0%o, ino = %ld, mode = 0%o, uid = %d, gid = %d\n",
+ h->c_magic, (long)h->c_ino, h->c_mode, h->c_uid, h->c_gid);
+ fprintf (stderr,
+ "nlink = %d, mtime = %d, filesize = %d, dev_maj = 0x%x\n",
+ h->c_nlink, h->c_mtime, h->c_filesize, h->c_dev_maj);
+ fprintf (stderr,
+ "dev_min = 0x%x, rdev_maj = 0x%x, rdev_min = 0x%x, namesize = %d\n",
+ h->c_dev_min, h->c_rdev_maj, h->c_rdev_min, h->c_namesize);
+ fprintf (stderr,
+ "chksum = %d, name = \"%s\", tar_linkname = \"%s\"\n",
+ h->c_chksum, h->c_name,
+ h->c_tar_linkname ? h->c_tar_linkname : "(null)" );
+
+ }
+#endif
+ /* Is this the header for the TRAILER file? */
+ if (strcmp (CPIO_TRAILER_NAME, file_hdr.c_name) == 0)
+ {
+ done = true;
+ break;
+ }
+
+ cpio_safer_name_suffix (file_hdr.c_name, false, !no_abs_paths_flag,
+ false);
+
+ /* Does the file name match one of the given patterns? */
+ if (num_patterns <= 0)
+ skip_file = false;
+ else
+ {
+ skip_file = copy_matching_files;
+ for (i = 0; i < num_patterns
+ && skip_file == copy_matching_files; i++)
+ {
+ if (fnmatch (save_patterns[i], file_hdr.c_name, 0) == 0)
+ skip_file = !copy_matching_files;
+ }
+ }
+
+ if (skip_file)
+ {
+ /* If we're skipping a file with links, there might be other
+ links that we didn't skip, and this file might have the
+ data for the links. If it does, we'll copy in the data
+ to the links, but not to this file. */
+ if (file_hdr.c_nlink > 1 && (archive_format == arf_newascii
+ || archive_format == arf_crcascii) )
+ {
+ if (create_defered_links_to_skipped(&file_hdr, in_file_des) < 0)
+ {
+ tape_toss_input (in_file_des, file_hdr.c_filesize);
+ tape_skip_padding (in_file_des, file_hdr.c_filesize);
+ }
+ }
+ else
+ {
+ tape_toss_input (in_file_des, file_hdr.c_filesize);
+ tape_skip_padding (in_file_des, file_hdr.c_filesize);
+ }
+ }
+ else if (table_flag)
+ {
+ list_file(&file_hdr, in_file_des);
+ }
+ else if (append_flag)
+ {
+ tape_toss_input (in_file_des, file_hdr.c_filesize);
+ tape_skip_padding (in_file_des, file_hdr.c_filesize);
+ }
+ else if (only_verify_crc_flag)
+ {
+#ifdef CP_IFLNK
+ if ((file_hdr.c_mode & CP_IFMT) == CP_IFLNK)
+ {
+ if (archive_format != arf_tar && archive_format != arf_ustar)
+ {
+ tape_toss_input (in_file_des, file_hdr.c_filesize);
+ tape_skip_padding (in_file_des, file_hdr.c_filesize);
+ continue;
+ }
+ }
+#endif
+ crc = 0;
+ tape_toss_input (in_file_des, file_hdr.c_filesize);
+ tape_skip_padding (in_file_des, file_hdr.c_filesize);
+ if (crc != file_hdr.c_chksum)
+ {
+ error (0, 0, _("%s: checksum error (0x%lx, should be 0x%lx)"),
+ file_hdr.c_name, crc, file_hdr.c_chksum);
+ }
+ /* Debian hack: -v and -V now work with --only-verify-crc.
+ (99/11/10) -BEM */
+ if (verbose_flag)
+ {
+ fprintf (stderr, "%s\n", file_hdr.c_name);
+ }
+ if (dot_flag)
+ {
+ fputc ('.', stderr);
+ }
+ }
+ else
+ {
+ /* Copy the input file into the directory structure. */
+
+ /* Do we need to rename the file? */
+ if (rename_flag || rename_batch_file)
+ {
+ if (query_rename(&file_hdr, tty_in, tty_out, rename_in) < 0)
+ {
+ tape_toss_input (in_file_des, file_hdr.c_filesize);
+ tape_skip_padding (in_file_des, file_hdr.c_filesize);
+ continue;
+ }
+ }
+
+ copyin_file(&file_hdr, in_file_des);
+
+ if (verbose_flag)
+ fprintf (stderr, "%s\n", file_hdr.c_name);
+ if (dot_flag)
+ fputc ('.', stderr);
+ }
+ }
+
+ if (dot_flag)
+ fputc ('\n', stderr);
+
+ apply_delayed_set_stat ();
+
+ if (append_flag)
+ return;
+
+ if (archive_format == arf_newascii || archive_format == arf_crcascii)
+ {
+ create_final_defers ();
+ }
+ if (!quiet_flag)
+ {
+ size_t blocks;
+ blocks = (input_bytes + io_block_size - 1) / io_block_size;
+ fprintf (stderr,
+ ngettext ("%lu block\n", "%lu blocks\n",
+ (unsigned long) blocks),
+ (unsigned long) blocks);
+ }
+}
+
diff --git a/src/copyout.c b/src/copyout.c
new file mode 100644
index 0000000..7e6b624
--- /dev/null
+++ b/src/copyout.c
@@ -0,0 +1,898 @@
+/* copyout.c - create a cpio archive
+ Copyright (C) 1990, 1991, 1992, 2001, 2003, 2004, 2006, 2007, 2009,
+ 2010 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 3, 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA. */
+
+#include <system.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "filetypes.h"
+#include "cpiohdr.h"
+#include "dstring.h"
+#include "extern.h"
+#include "defer.h"
+#include <rmt.h>
+#include <paxlib.h>
+
+/* Read FILE_SIZE bytes of FILE_NAME from IN_FILE_DES and
+ compute and return a checksum for them. */
+
+static unsigned long
+read_for_checksum (int in_file_des, int file_size, char *file_name)
+{
+ unsigned long crc;
+ char buf[BUFSIZ];
+ int bytes_left;
+ int bytes_read;
+ int i;
+
+ crc = 0;
+
+ for (bytes_left = file_size; bytes_left > 0; bytes_left -= bytes_read)
+ {
+ bytes_read = read (in_file_des, buf, BUFSIZ);
+ if (bytes_read < 0)
+ error (1, errno, _("cannot read checksum for %s"), file_name);
+ if (bytes_read == 0)
+ break;
+ if (bytes_left < bytes_read)
+ bytes_read = bytes_left;
+ for (i = 0; i < bytes_read; ++i)
+ crc += buf[i] & 0xff;
+ }
+ if (lseek (in_file_des, 0L, SEEK_SET))
+ error (1, errno, _("cannot read checksum for %s"), file_name);
+
+ return crc;
+}
+
+/* Write out NULs to fill out the rest of the current block on
+ OUT_FILE_DES. */
+
+static void
+tape_clear_rest_of_block (int out_file_des)
+{
+ write_nuls_to_file (io_block_size - output_size, out_file_des,
+ tape_buffered_write);
+}
+
+/* Write NULs on OUT_FILE_DES to move from OFFSET (the current location)
+ to the end of the header. */
+
+static void
+tape_pad_output (int out_file_des, int offset)
+{
+ size_t pad;
+
+ if (archive_format == arf_newascii || archive_format == arf_crcascii)
+ pad = (4 - (offset % 4)) % 4;
+ else if (archive_format == arf_tar || archive_format == arf_ustar)
+ pad = (512 - (offset % 512)) % 512;
+ else if (archive_format != arf_oldascii && archive_format != arf_hpoldascii)
+ pad = (2 - (offset % 2)) % 2;
+ else
+ pad = 0;
+
+ if (pad != 0)
+ write_nuls_to_file (pad, out_file_des, tape_buffered_write);
+}
+
+
+/* When creating newc and crc archives if a file has multiple (hard)
+ links, we don't put any of them into the archive until we have seen
+ all of them (or until we get to the end of the list of files that
+ are going into the archive and know that we have seen all of the links
+ to the file that we will see). We keep these "defered" files on
+ this list. */
+
+struct deferment *deferouts = NULL;
+
+/* Count the number of other (hard) links to this file that have
+ already been defered. */
+
+static int
+count_defered_links_to_dev_ino (struct cpio_file_stat *file_hdr)
+{
+ struct deferment *d;
+ ino_t ino;
+ int maj;
+ int min;
+ int count;
+ ino = file_hdr->c_ino;
+ maj = file_hdr->c_dev_maj;
+ min = file_hdr->c_dev_min;
+ count = 0;
+ for (d = deferouts; d != NULL; d = d->next)
+ {
+ if ( (d->header.c_ino == ino) && (d->header.c_dev_maj == maj)
+ && (d->header.c_dev_min == min) )
+ ++count;
+ }
+ return count;
+}
+
+/* Is this file_hdr the last (hard) link to a file? I.e., have
+ we already seen and defered all of the other links? */
+
+static int
+last_link (struct cpio_file_stat *file_hdr)
+{
+ int other_files_sofar;
+
+ other_files_sofar = count_defered_links_to_dev_ino (file_hdr);
+ if (file_hdr->c_nlink == (other_files_sofar + 1) )
+ {
+ return 1;
+ }
+ return 0;
+}
+
+
+/* Add the file header for a link that is being defered to the deferouts
+ list. */
+
+static void
+add_link_defer (struct cpio_file_stat *file_hdr)
+{
+ struct deferment *d;
+ d = create_deferment (file_hdr);
+ d->next = deferouts;
+ deferouts = d;
+}
+
+/* We are about to put a file into a newc or crc archive that is
+ multiply linked. We have already seen and deferred all of the
+ other links to the file but haven't written them into the archive.
+ Write the other links into the archive, and remove them from the
+ deferouts list. */
+
+static void
+writeout_other_defers (struct cpio_file_stat *file_hdr, int out_des)
+{
+ struct deferment *d;
+ struct deferment *d_prev;
+ ino_t ino;
+ int maj;
+ int min;
+ ino = file_hdr->c_ino;
+ maj = file_hdr->c_dev_maj;
+ min = file_hdr->c_dev_min;
+ d_prev = NULL;
+ d = deferouts;
+ while (d != NULL)
+ {
+ if ( (d->header.c_ino == ino) && (d->header.c_dev_maj == maj)
+ && (d->header.c_dev_min == min) )
+ {
+ struct deferment *d_free;
+ d->header.c_filesize = 0;
+ write_out_header (&d->header, out_des);
+ if (d_prev != NULL)
+ d_prev->next = d->next;
+ else
+ deferouts = d->next;
+ d_free = d;
+ d = d->next;
+ free_deferment (d_free);
+ }
+ else
+ {
+ d_prev = d;
+ d = d->next;
+ }
+ }
+ return;
+}
+
+/* Write a file into the archive. This code is the same as
+ the code in process_copy_out(), but we need it here too
+ for writeout_final_defers() to call. */
+
+static void
+writeout_defered_file (struct cpio_file_stat *header, int out_file_des)
+{
+ int in_file_des;
+ struct cpio_file_stat file_hdr;
+
+ file_hdr = *header;
+
+
+ in_file_des = open (header->c_name,
+ O_RDONLY | O_BINARY, 0);
+ if (in_file_des < 0)
+ {
+ open_error (header->c_name);
+ return;
+ }
+
+ if (archive_format == arf_crcascii)
+ file_hdr.c_chksum = read_for_checksum (in_file_des,
+ file_hdr.c_filesize,
+ header->c_name);
+
+ if (write_out_header (&file_hdr, out_file_des))
+ return;
+ copy_files_disk_to_tape (in_file_des, out_file_des, file_hdr.c_filesize,
+ header->c_name);
+ warn_if_file_changed(header->c_name, file_hdr.c_filesize, file_hdr.c_mtime);
+
+ if (archive_format == arf_tar || archive_format == arf_ustar)
+ add_inode (file_hdr.c_ino, file_hdr.c_name, file_hdr.c_dev_maj,
+ file_hdr.c_dev_min);
+
+ tape_pad_output (out_file_des, file_hdr.c_filesize);
+
+ if (reset_time_flag)
+ set_file_times (in_file_des, file_hdr.c_name, file_hdr.c_mtime,
+ file_hdr.c_mtime);
+ if (close (in_file_des) < 0)
+ close_error (header->c_name);
+}
+
+/* When writing newc and crc format archives we defer multiply linked
+ files until we have seen all of the links to the file. If a file
+ has links to it that aren't going into the archive, then we will
+ never see the "last" link to the file, so at the end we just write
+ all of the leftover defered files into the archive. */
+
+static void
+writeout_final_defers (int out_des)
+{
+ struct deferment *d;
+ int other_count;
+ while (deferouts != NULL)
+ {
+ d = deferouts;
+ other_count = count_defered_links_to_dev_ino (&d->header);
+ if (other_count == 1)
+ {
+ writeout_defered_file (&d->header, out_des);
+ }
+ else
+ {
+ struct cpio_file_stat file_hdr;
+ file_hdr = d->header;
+ file_hdr.c_filesize = 0;
+ write_out_header (&file_hdr, out_des);
+ }
+ deferouts = deferouts->next;
+ }
+}
+
+/* FIXME: to_ascii could be used instead of to_oct() and to_octal() from tar,
+ so it should be moved to paxutils too.
+ Allowed values for logbase are: 1 (binary), 2, 3 (octal), 4 (hex) */
+int
+to_ascii (char *where, uintmax_t v, size_t digits, unsigned logbase)
+{
+ static char codetab[] = "0123456789ABCDEF";
+ int i = digits;
+
+ do
+ {
+ where[--i] = codetab[(v & ((1 << logbase) - 1))];
+ v >>= logbase;
+ }
+ while (i);
+
+ return v != 0;
+}
+
+static void
+field_width_error (const char *filename, const char *fieldname)
+{
+ error (0, 0, _("%s: field width not sufficient for storing %s"),
+ filename, fieldname);
+}
+
+static void
+field_width_warning (const char *filename, const char *fieldname)
+{
+ if (warn_option & CPIO_WARN_TRUNCATE)
+ error (0, 0, _("%s: truncating %s"), filename, fieldname);
+}
+
+void
+to_ascii_or_warn (char *where, uintmax_t n, size_t digits,
+ unsigned logbase,
+ const char *filename, const char *fieldname)
+{
+ if (to_ascii (where, n, digits, logbase))
+ field_width_warning (filename, fieldname);
+}
+
+int
+to_ascii_or_error (char *where, uintmax_t n, size_t digits,
+ unsigned logbase,
+ const char *filename, const char *fieldname)
+{
+ if (to_ascii (where, n, digits, logbase))
+ {
+ field_width_error (filename, fieldname);
+ return 1;
+ }
+ return 0;
+}
+
+
+int
+write_out_new_ascii_header (const char *magic_string,
+ struct cpio_file_stat *file_hdr, int out_des)
+{
+ char ascii_header[110];
+ char *p;
+
+ p = stpcpy (ascii_header, magic_string);
+ to_ascii_or_warn (p, file_hdr->c_ino, 8, LG_16,
+ file_hdr->c_name, _("inode number"));
+ p += 8;
+ to_ascii_or_warn (p, file_hdr->c_mode, 8, LG_16, file_hdr->c_name,
+ _("file mode"));
+ p += 8;
+ to_ascii_or_warn (p, file_hdr->c_uid, 8, LG_16, file_hdr->c_name,
+ _("uid"));
+ p += 8;
+ to_ascii_or_warn (p, file_hdr->c_gid, 8, LG_16, file_hdr->c_name,
+ _("gid"));
+ p += 8;
+ to_ascii_or_warn (p, file_hdr->c_nlink, 8, LG_16, file_hdr->c_name,
+ _("number of links"));
+ p += 8;
+ to_ascii_or_warn (p, file_hdr->c_mtime, 8, LG_16, file_hdr->c_name,
+ _("modification time"));
+ p += 8;
+ if (to_ascii_or_error (p, file_hdr->c_filesize, 8, LG_16, file_hdr->c_name,
+ _("file size")))
+ return 1;
+ p += 8;
+ if (to_ascii_or_error (p, file_hdr->c_dev_maj, 8, LG_16, file_hdr->c_name,
+ _("device major number")))
+ return 1;
+ p += 8;
+ if (to_ascii_or_error (p, file_hdr->c_dev_min, 8, LG_16, file_hdr->c_name,
+ _("device minor number")))
+ return 1;
+ p += 8;
+ if (to_ascii_or_error (p, file_hdr->c_rdev_maj, 8, LG_16, file_hdr->c_name,
+ _("rdev major")))
+ return 1;
+ p += 8;
+ if (to_ascii_or_error (p, file_hdr->c_rdev_min, 8, LG_16, file_hdr->c_name,
+ _("rdev minor")))
+ return 1;
+ p += 8;
+ if (to_ascii_or_error (p, file_hdr->c_namesize, 8, LG_16, file_hdr->c_name,
+ _("name size")))
+ return 1;
+ p += 8;
+ to_ascii (p, file_hdr->c_chksum & 0xffffffff, 8, LG_16);
+
+ tape_buffered_write (ascii_header, out_des, sizeof ascii_header);
+
+ /* Write file name to output. */
+ tape_buffered_write (file_hdr->c_name, out_des, (long) file_hdr->c_namesize);
+ tape_pad_output (out_des, file_hdr->c_namesize + sizeof ascii_header);
+ return 0;
+}
+
+int
+write_out_old_ascii_header (dev_t dev, dev_t rdev,
+ struct cpio_file_stat *file_hdr, int out_des)
+{
+ char ascii_header[76];
+ char *p = ascii_header;
+
+ to_ascii (p, file_hdr->c_magic, 6, LG_8);
+ p += 6;
+ to_ascii_or_warn (p, dev, 6, LG_8, file_hdr->c_name, _("device number"));
+ p += 6;
+ to_ascii_or_warn (p, file_hdr->c_ino, 6, LG_8, file_hdr->c_name,
+ _("inode number"));
+ p += 6;
+ to_ascii_or_warn (p, file_hdr->c_mode, 6, LG_8, file_hdr->c_name,
+ _("file mode"));
+ p += 6;
+ to_ascii_or_warn (p, file_hdr->c_uid, 6, LG_8, file_hdr->c_name, _("uid"));
+ p += 6;
+ to_ascii_or_warn (p, file_hdr->c_gid, 6, LG_8, file_hdr->c_name, _("gid"));
+ p += 6;
+ to_ascii_or_warn (p, file_hdr->c_nlink, 6, LG_8, file_hdr->c_name,
+ _("number of links"));
+ p += 6;
+ to_ascii_or_warn (p, rdev, 6, LG_8, file_hdr->c_name, _("rdev"));
+ p += 6;
+ to_ascii_or_warn (p, file_hdr->c_mtime, 11, LG_8, file_hdr->c_name,
+ _("modification time"));
+ p += 11;
+ if (to_ascii_or_error (p, file_hdr->c_namesize, 6, LG_8, file_hdr->c_name,
+ _("name size")))
+ return 1;
+ p += 6;
+ if (to_ascii_or_error (p, file_hdr->c_filesize, 11, LG_8, file_hdr->c_name,
+ _("file size")))
+ return 1;
+
+ tape_buffered_write (ascii_header, out_des, sizeof ascii_header);
+
+ /* Write file name to output. */
+ tape_buffered_write (file_hdr->c_name, out_des, file_hdr->c_namesize);
+ return 0;
+}
+
+void
+hp_compute_dev (struct cpio_file_stat *file_hdr, dev_t *pdev, dev_t *prdev)
+{
+ /* HP/UX cpio creates archives that look just like ordinary archives,
+ but for devices it sets major = 0, minor = 1, and puts the
+ actual major/minor number in the filesize field. */
+ switch (file_hdr->c_mode & CP_IFMT)
+ {
+ case CP_IFCHR:
+ case CP_IFBLK:
+#ifdef CP_IFSOCK
+ case CP_IFSOCK:
+#endif
+#ifdef CP_IFIFO
+ case CP_IFIFO:
+#endif
+ file_hdr->c_filesize = makedev (file_hdr->c_rdev_maj,
+ file_hdr->c_rdev_min);
+ *pdev = *prdev = makedev (0, 1);
+ break;
+
+ default:
+ *pdev = makedev (file_hdr->c_dev_maj, file_hdr->c_dev_min);
+ *prdev = makedev (file_hdr->c_rdev_maj, file_hdr->c_rdev_min);
+ break;
+ }
+}
+
+int
+write_out_binary_header (dev_t rdev,
+ struct cpio_file_stat *file_hdr, int out_des)
+{
+ struct old_cpio_header short_hdr;
+
+ short_hdr.c_magic = 070707;
+ short_hdr.c_dev = makedev (file_hdr->c_dev_maj, file_hdr->c_dev_min);
+
+ if ((warn_option & CPIO_WARN_TRUNCATE) && (file_hdr->c_ino >> 16) != 0)
+ error (0, 0, _("%s: truncating inode number"), file_hdr->c_name);
+
+ short_hdr.c_ino = file_hdr->c_ino & 0xFFFF;
+ if (short_hdr.c_ino != file_hdr->c_ino)
+ field_width_warning (file_hdr->c_name, _("inode number"));
+
+ short_hdr.c_mode = file_hdr->c_mode & 0xFFFF;
+ if (short_hdr.c_mode != file_hdr->c_mode)
+ field_width_warning (file_hdr->c_name, _("file mode"));
+
+ short_hdr.c_uid = file_hdr->c_uid & 0xFFFF;
+ if (short_hdr.c_uid != file_hdr->c_uid)
+ field_width_warning (file_hdr->c_name, _("uid"));
+
+ short_hdr.c_gid = file_hdr->c_gid & 0xFFFF;
+ if (short_hdr.c_gid != file_hdr->c_gid)
+ field_width_warning (file_hdr->c_name, _("gid"));
+
+ short_hdr.c_nlink = file_hdr->c_nlink & 0xFFFF;
+ if (short_hdr.c_nlink != file_hdr->c_nlink)
+ field_width_warning (file_hdr->c_name, _("number of links"));
+
+ short_hdr.c_rdev = rdev;
+ short_hdr.c_mtimes[0] = file_hdr->c_mtime >> 16;
+ short_hdr.c_mtimes[1] = file_hdr->c_mtime & 0xFFFF;
+
+ short_hdr.c_namesize = file_hdr->c_namesize & 0xFFFF;
+ if (short_hdr.c_namesize != file_hdr->c_namesize)
+ {
+ field_width_error (file_hdr->c_name, _("name size"));
+ return 1;
+ }
+
+ short_hdr.c_filesizes[0] = file_hdr->c_filesize >> 16;
+ short_hdr.c_filesizes[1] = file_hdr->c_filesize & 0xFFFF;
+
+ if (((off_t)short_hdr.c_filesizes[0] << 16) + short_hdr.c_filesizes[1]
+ != file_hdr->c_filesize)
+ {
+ field_width_error (file_hdr->c_name, _("file size"));
+ return 1;
+ }
+
+ /* Output the file header. */
+ tape_buffered_write ((char *) &short_hdr, out_des, 26);
+
+ /* Write file name to output. */
+ tape_buffered_write (file_hdr->c_name, out_des, file_hdr->c_namesize);
+
+ tape_pad_output (out_des, file_hdr->c_namesize + 26);
+ return 0;
+}
+
+
+/* Write out header FILE_HDR, including the file name, to file
+ descriptor OUT_DES. */
+
+int
+write_out_header (struct cpio_file_stat *file_hdr, int out_des)
+{
+ dev_t dev;
+ dev_t rdev;
+
+ switch (archive_format)
+ {
+ case arf_newascii:
+ return write_out_new_ascii_header ("070701", file_hdr, out_des);
+
+ case arf_crcascii:
+ return write_out_new_ascii_header ("070702", file_hdr, out_des);
+
+ case arf_oldascii:
+ return write_out_old_ascii_header (makedev (file_hdr->c_dev_maj,
+ file_hdr->c_dev_min),
+ makedev (file_hdr->c_rdev_maj,
+ file_hdr->c_rdev_min),
+ file_hdr, out_des);
+
+ case arf_hpoldascii:
+ hp_compute_dev (file_hdr, &dev, &rdev);
+ return write_out_old_ascii_header (dev, rdev, file_hdr, out_des);
+
+ case arf_tar:
+ case arf_ustar:
+ if (is_tar_filename_too_long (file_hdr->c_name))
+ {
+ error (0, 0, _("%s: file name too long"), file_hdr->c_name);
+ return 1;
+ }
+ write_out_tar_header (file_hdr, out_des); /* FIXME: No error checking */
+ return 0;
+
+ case arf_binary:
+ return write_out_binary_header (makedev (file_hdr->c_rdev_maj,
+ file_hdr->c_rdev_min),
+ file_hdr, out_des);
+
+ case arf_hpbinary:
+ hp_compute_dev (file_hdr, &dev, &rdev);
+ /* FIXME: dev ignored. Should it be? */
+ return write_out_binary_header (rdev, file_hdr, out_des);
+
+ default:
+ abort ();
+ }
+}
+
+static void
+assign_string (char **pvar, char *value)
+{
+ char *p = xrealloc (*pvar, strlen (value) + 1);
+ strcpy (p, value);
+ *pvar = p;
+}
+
+/* Read a list of file names from the standard input
+ and write a cpio collection on the standard output.
+ The format of the header depends on the compatibility (-c) flag. */
+
+void
+process_copy_out ()
+{
+ dynamic_string input_name; /* Name of file read from stdin. */
+ struct stat file_stat; /* Stat record for file. */
+ struct cpio_file_stat file_hdr; /* Output header information. */
+ int in_file_des; /* Source file descriptor. */
+ int out_file_des; /* Output file descriptor. */
+ char *orig_file_name = NULL;
+
+ /* Initialize the copy out. */
+ ds_init (&input_name, 128);
+ file_hdr.c_magic = 070707;
+
+ /* Check whether the output file might be a tape. */
+ out_file_des = archive_des;
+ if (_isrmt (out_file_des))
+ {
+ output_is_special = 1;
+ output_is_seekable = 0;
+ }
+ else
+ {
+ if (fstat (out_file_des, &file_stat))
+ error (1, errno, _("standard output is closed"));
+ output_is_special =
+#ifdef S_ISBLK
+ S_ISBLK (file_stat.st_mode) ||
+#endif
+ S_ISCHR (file_stat.st_mode);
+ output_is_seekable = S_ISREG (file_stat.st_mode);
+ }
+
+ if (append_flag)
+ {
+ process_copy_in ();
+ prepare_append (out_file_des);
+ }
+
+ /* Copy files with names read from stdin. */
+ while (ds_fgetstr (stdin, &input_name, name_end) != NULL)
+ {
+ /* Check for blank line. */
+ if (input_name.ds_string[0] == 0)
+ {
+ error (0, 0, _("blank line ignored"));
+ continue;
+ }
+
+ /* Process next file. */
+ if ((*xstat) (input_name.ds_string, &file_stat) < 0)
+ stat_error (input_name.ds_string);
+ else
+ {
+ /* Set values in output header. */
+ stat_to_cpio (&file_hdr, &file_stat);
+
+ if (archive_format == arf_tar || archive_format == arf_ustar)
+ {
+ if (file_hdr.c_mode & CP_IFDIR)
+ {
+ int len = strlen (input_name.ds_string);
+ /* Make sure the name ends with a slash */
+ if (input_name.ds_string[len-1] != '/')
+ {
+ ds_resize (&input_name, len + 2);
+ input_name.ds_string[len] = '/';
+ input_name.ds_string[len+1] = 0;
+ }
+ }
+ }
+
+ assign_string (&orig_file_name, input_name.ds_string);
+ cpio_safer_name_suffix (input_name.ds_string, false,
+ !no_abs_paths_flag, true);
+#ifndef HPUX_CDF
+ file_hdr.c_name = input_name.ds_string;
+ file_hdr.c_namesize = strlen (input_name.ds_string) + 1;
+#else
+ if ( (archive_format != arf_tar) && (archive_format != arf_ustar) )
+ {
+ /* We mark CDF's in cpio files by adding a 2nd `/' after the
+ "hidden" directory name. We need to do this so we can
+ properly recreate the directory as hidden (in case the
+ files of a directory go into the archive before the
+ directory itself (e.g from "find ... -depth ... | cpio")). */
+ file_hdr.c_name = add_cdf_double_slashes (input_name.ds_string);
+ file_hdr.c_namesize = strlen (file_hdr.c_name) + 1;
+ }
+ else
+ {
+ /* We don't mark CDF's in tar files. We assume the "hidden"
+ directory will always go into the archive before any of
+ its files. */
+ file_hdr.c_name = input_name.ds_string;
+ file_hdr.c_namesize = strlen (input_name.ds_string) + 1;
+ }
+#endif
+
+ /* Copy the named file to the output. */
+ switch (file_hdr.c_mode & CP_IFMT)
+ {
+ case CP_IFREG:
+ if (archive_format == arf_tar || archive_format == arf_ustar)
+ {
+ char *otherfile;
+ if ((otherfile = find_inode_file (file_hdr.c_ino,
+ file_hdr.c_dev_maj,
+ file_hdr.c_dev_min)))
+ {
+ file_hdr.c_tar_linkname = otherfile;
+ if (write_out_header (&file_hdr, out_file_des))
+ continue;
+ break;
+ }
+ }
+ if ( (archive_format == arf_newascii || archive_format == arf_crcascii)
+ && (file_hdr.c_nlink > 1) )
+ {
+ if (last_link (&file_hdr) )
+ {
+ writeout_other_defers (&file_hdr, out_file_des);
+ }
+ else
+ {
+ add_link_defer (&file_hdr);
+ break;
+ }
+ }
+ in_file_des = open (orig_file_name,
+ O_RDONLY | O_BINARY, 0);
+ if (in_file_des < 0)
+ {
+ open_error (orig_file_name);
+ continue;
+ }
+
+ if (archive_format == arf_crcascii)
+ file_hdr.c_chksum = read_for_checksum (in_file_des,
+ file_hdr.c_filesize,
+ orig_file_name);
+
+ if (write_out_header (&file_hdr, out_file_des))
+ continue;
+ copy_files_disk_to_tape (in_file_des,
+ out_file_des, file_hdr.c_filesize,
+ orig_file_name);
+ warn_if_file_changed(orig_file_name, file_hdr.c_filesize,
+ file_hdr.c_mtime);
+
+ if (archive_format == arf_tar || archive_format == arf_ustar)
+ add_inode (file_hdr.c_ino, orig_file_name, file_hdr.c_dev_maj,
+ file_hdr.c_dev_min);
+
+ tape_pad_output (out_file_des, file_hdr.c_filesize);
+
+ if (reset_time_flag)
+ set_file_times (in_file_des,
+ orig_file_name,
+ file_stat.st_atime, file_stat.st_mtime);
+ if (close (in_file_des) < 0)
+ close_error (orig_file_name);
+ break;
+
+ case CP_IFDIR:
+ file_hdr.c_filesize = 0;
+ if (write_out_header (&file_hdr, out_file_des))
+ continue;
+ break;
+
+ case CP_IFCHR:
+ case CP_IFBLK:
+#ifdef CP_IFSOCK
+ case CP_IFSOCK:
+#endif
+#ifdef CP_IFIFO
+ case CP_IFIFO:
+#endif
+ if (archive_format == arf_tar)
+ {
+ error (0, 0, _("%s not dumped: not a regular file"),
+ orig_file_name);
+ continue;
+ }
+ else if (archive_format == arf_ustar)
+ {
+ char *otherfile;
+ if ((otherfile = find_inode_file (file_hdr.c_ino,
+ file_hdr.c_dev_maj,
+ file_hdr.c_dev_min)))
+ {
+ /* This file is linked to another file already in the
+ archive, so write it out as a hard link. */
+ file_hdr.c_mode = (file_stat.st_mode & 07777);
+ file_hdr.c_mode |= CP_IFREG;
+ file_hdr.c_tar_linkname = otherfile;
+ if (write_out_header (&file_hdr, out_file_des))
+ continue;
+ break;
+ }
+ add_inode (file_hdr.c_ino, orig_file_name,
+ file_hdr.c_dev_maj, file_hdr.c_dev_min);
+ }
+ file_hdr.c_filesize = 0;
+ if (write_out_header (&file_hdr, out_file_des))
+ continue;
+ break;
+
+#ifdef CP_IFLNK
+ case CP_IFLNK:
+ {
+ char *link_name = (char *) xmalloc (file_stat.st_size + 1);
+ int link_size;
+
+ link_size = readlink (orig_file_name, link_name,
+ file_stat.st_size);
+ if (link_size < 0)
+ {
+ readlink_warn (orig_file_name);
+ free (link_name);
+ continue;
+ }
+ link_name[link_size] = 0;
+ cpio_safer_name_suffix (link_name, false,
+ !no_abs_paths_flag, true);
+ link_size = strlen (link_name);
+ file_hdr.c_filesize = link_size;
+ if (archive_format == arf_tar || archive_format == arf_ustar)
+ {
+ if (link_size + 1 > 100)
+ {
+ error (0, 0, _("%s: symbolic link too long"),
+ file_hdr.c_name);
+ }
+ else
+ {
+ link_name[link_size] = '\0';
+ file_hdr.c_tar_linkname = link_name;
+ if (write_out_header (&file_hdr, out_file_des))
+ continue;
+ }
+ }
+ else
+ {
+ if (write_out_header (&file_hdr, out_file_des))
+ continue;
+ tape_buffered_write (link_name, out_file_des, link_size);
+ tape_pad_output (out_file_des, link_size);
+ }
+ free (link_name);
+ }
+ break;
+#endif
+
+ default:
+ error (0, 0, _("%s: unknown file type"), orig_file_name);
+ }
+
+ if (verbose_flag)
+ fprintf (stderr, "%s\n", orig_file_name);
+ if (dot_flag)
+ fputc ('.', stderr);
+ }
+ }
+
+ free (orig_file_name);
+
+ writeout_final_defers(out_file_des);
+ /* The collection is complete; append the trailer. */
+ file_hdr.c_ino = 0;
+ file_hdr.c_mode = 0;
+ file_hdr.c_uid = 0;
+ file_hdr.c_gid = 0;
+ file_hdr.c_nlink = 1; /* Must be 1 for crc format. */
+ file_hdr.c_dev_maj = 0;
+ file_hdr.c_dev_min = 0;
+ file_hdr.c_rdev_maj = 0;
+ file_hdr.c_rdev_min = 0;
+ file_hdr.c_mtime = 0;
+ file_hdr.c_chksum = 0;
+
+ file_hdr.c_filesize = 0;
+ file_hdr.c_namesize = 11;
+ file_hdr.c_name = CPIO_TRAILER_NAME;
+ if (archive_format != arf_tar && archive_format != arf_ustar)
+ write_out_header (&file_hdr, out_file_des);
+ else
+ write_nuls_to_file (1024, out_file_des, tape_buffered_write);
+
+ /* Fill up the output block. */
+ tape_clear_rest_of_block (out_file_des);
+ tape_empty_output_buffer (out_file_des);
+ if (dot_flag)
+ fputc ('\n', stderr);
+ if (!quiet_flag)
+ {
+ size_t blocks = (output_bytes + io_block_size - 1) / io_block_size;
+ fprintf (stderr,
+ ngettext ("%lu block\n", "%lu blocks\n",
+ (unsigned long) blocks), (unsigned long) blocks);
+ }
+}
+
+
diff --git a/src/copypass.c b/src/copypass.c
new file mode 100644
index 0000000..d249a31
--- /dev/null
+++ b/src/copypass.c
@@ -0,0 +1,398 @@
+/* copypass.c - cpio copy pass sub-function.
+ Copyright (C) 1990, 1991, 1992, 2001, 2003, 2004, 2006, 2007, 2010
+ 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 3, 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA. */
+
+#include <system.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "filetypes.h"
+#include "cpiohdr.h"
+#include "dstring.h"
+#include "extern.h"
+#include "paxlib.h"
+
+#ifndef HAVE_LCHOWN
+# define lchown chown
+#endif
+
+
+/* A wrapper around set_perms using another set of arguments */
+static void
+set_copypass_perms (int fd, const char *name, struct stat *st)
+{
+ struct cpio_file_stat header;
+ header.c_name = (char*)name;
+ stat_to_cpio (&header, st);
+ set_perms (fd, &header);
+}
+
+/* Copy files listed on the standard input into directory `directory_name'.
+ If `link_flag', link instead of copying. */
+
+void
+process_copy_pass ()
+{
+ dynamic_string input_name; /* Name of file from stdin. */
+ dynamic_string output_name; /* Name of new file. */
+ int dirname_len; /* Length of `directory_name'. */
+ int res; /* Result of functions. */
+ char *slash; /* For moving past slashes in input name. */
+ struct stat in_file_stat; /* Stat record for input file. */
+ struct stat out_file_stat; /* Stat record for output file. */
+ int in_file_des; /* Input file descriptor. */
+ int out_file_des; /* Output file descriptor. */
+ int existing_dir; /* True if file is a dir & already exists. */
+#ifdef HPUX_CDF
+ int cdf_flag;
+ int cdf_char;
+#endif
+
+ newdir_umask = umask (0); /* Reset umask to preserve modes of
+ created files */
+
+ /* Initialize the copy pass. */
+ dirname_len = strlen (directory_name);
+ ds_init (&input_name, 128);
+ ds_init (&output_name, dirname_len + 2);
+ strcpy (output_name.ds_string, directory_name);
+ output_name.ds_string[dirname_len] = '/';
+ output_is_seekable = true;
+
+ /* Copy files with names read from stdin. */
+ while (ds_fgetstr (stdin, &input_name, name_end) != NULL)
+ {
+ int link_res = -1;
+
+ /* Check for blank line and ignore it if found. */
+ if (input_name.ds_string[0] == '\0')
+ {
+ error (0, 0, _("blank line ignored"));
+ continue;
+ }
+
+ /* Check for current directory and ignore it if found. */
+ if (input_name.ds_string[0] == '.'
+ && (input_name.ds_string[1] == '\0'
+ || (input_name.ds_string[1] == '/'
+ && input_name.ds_string[2] == '\0')))
+ continue;
+
+ if ((*xstat) (input_name.ds_string, &in_file_stat) < 0)
+ {
+ stat_error (input_name.ds_string);
+ continue;
+ }
+
+ /* Make the name of the new file. */
+ for (slash = input_name.ds_string; *slash == '/'; ++slash)
+ ;
+#ifdef HPUX_CDF
+ /* For CDF's we add a 2nd `/' after all "hidden" directories.
+ This kind of a kludge, but it's what we do when creating
+ archives, and it's easier to do this than to separately
+ keep track of which directories in a path are "hidden". */
+ slash = add_cdf_double_slashes (slash);
+#endif
+ ds_resize (&output_name, dirname_len + strlen (slash) + 2);
+ strcpy (output_name.ds_string + dirname_len + 1, slash);
+
+ existing_dir = false;
+ if (lstat (output_name.ds_string, &out_file_stat) == 0)
+ {
+ if (S_ISDIR (out_file_stat.st_mode)
+ && S_ISDIR (in_file_stat.st_mode))
+ {
+ /* If there is already a directory there that
+ we are trying to create, don't complain about it. */
+ existing_dir = true;
+ }
+ else if (!unconditional_flag
+ && in_file_stat.st_mtime <= out_file_stat.st_mtime)
+ {
+ error (0, 0, _("%s not created: newer or same age version exists"),
+ output_name.ds_string);
+ continue; /* Go to the next file. */
+ }
+ else if (S_ISDIR (out_file_stat.st_mode)
+ ? rmdir (output_name.ds_string)
+ : unlink (output_name.ds_string))
+ {
+ error (0, errno, _("cannot remove current %s"),
+ output_name.ds_string);
+ continue; /* Go to the next file. */
+ }
+ }
+
+ /* Do the real copy or link. */
+ if (S_ISREG (in_file_stat.st_mode))
+ {
+ /* Can the current file be linked to a another file?
+ Set link_name to the original file name. */
+ if (link_flag)
+ /* User said to link it if possible. Try and link to
+ the original copy. If that fails we'll still try
+ and link to a copy we've already made. */
+ link_res = link_to_name (output_name.ds_string,
+ input_name.ds_string);
+ if ( (link_res < 0) && (in_file_stat.st_nlink > 1) )
+ link_res = link_to_maj_min_ino (output_name.ds_string,
+ major (in_file_stat.st_dev),
+ minor (in_file_stat.st_dev),
+ in_file_stat.st_ino);
+
+ /* If the file was not linked, copy contents of file. */
+ if (link_res < 0)
+ {
+ in_file_des = open (input_name.ds_string,
+ O_RDONLY | O_BINARY, 0);
+ if (in_file_des < 0)
+ {
+ open_error (input_name.ds_string);
+ continue;
+ }
+ out_file_des = open (output_name.ds_string,
+ O_CREAT | O_WRONLY | O_BINARY, 0600);
+ if (out_file_des < 0 && create_dir_flag)
+ {
+ create_all_directories (output_name.ds_string);
+ out_file_des = open (output_name.ds_string,
+ O_CREAT | O_WRONLY | O_BINARY, 0600);
+ }
+ if (out_file_des < 0)
+ {
+ open_error (output_name.ds_string);
+ close (in_file_des);
+ continue;
+ }
+
+ copy_files_disk_to_disk (in_file_des, out_file_des, in_file_stat.st_size, input_name.ds_string);
+ disk_empty_output_buffer (out_file_des);
+ /* Debian hack to fix a bug in the --sparse option.
+ This bug has been reported to
+ "bug-gnu-utils@prep.ai.mit.edu". (96/7/10) -BEM */
+ if (delayed_seek_count > 0)
+ {
+ lseek (out_file_des, delayed_seek_count-1, SEEK_CUR);
+ write (out_file_des, "", 1);
+ delayed_seek_count = 0;
+ }
+
+ set_copypass_perms (out_file_des,
+ output_name.ds_string, &in_file_stat);
+
+ if (reset_time_flag)
+ {
+ set_file_times (in_file_des,
+ input_name.ds_string,
+ in_file_stat.st_atime,
+ in_file_stat.st_mtime);
+ set_file_times (out_file_des,
+ output_name.ds_string,
+ in_file_stat.st_atime,
+ in_file_stat.st_mtime);
+ }
+
+ if (close (in_file_des) < 0)
+ close_error (input_name.ds_string);
+
+ if (close (out_file_des) < 0)
+ close_error (output_name.ds_string);
+
+ warn_if_file_changed(input_name.ds_string, in_file_stat.st_size,
+ in_file_stat.st_mtime);
+ }
+ }
+ else if (S_ISDIR (in_file_stat.st_mode))
+ {
+ struct cpio_file_stat file_stat;
+
+ stat_to_cpio (&file_stat, &in_file_stat);
+ file_stat.c_name = output_name.ds_string;
+ cpio_create_dir (&file_stat, existing_dir);
+ }
+ else if (S_ISCHR (in_file_stat.st_mode) ||
+ S_ISBLK (in_file_stat.st_mode) ||
+#ifdef S_ISFIFO
+ S_ISFIFO (in_file_stat.st_mode) ||
+#endif
+#ifdef S_ISSOCK
+ S_ISSOCK (in_file_stat.st_mode) ||
+#endif
+ 0)
+ {
+ /* Can the current file be linked to a another file?
+ Set link_name to the original file name. */
+ if (link_flag)
+ /* User said to link it if possible. */
+ link_res = link_to_name (output_name.ds_string,
+ input_name.ds_string);
+ if ( (link_res < 0) && (in_file_stat.st_nlink > 1) )
+ link_res = link_to_maj_min_ino (output_name.ds_string,
+ major (in_file_stat.st_dev),
+ minor (in_file_stat.st_dev),
+ in_file_stat.st_ino);
+
+ if (link_res < 0)
+ {
+ res = mknod (output_name.ds_string, in_file_stat.st_mode,
+ in_file_stat.st_rdev);
+ if (res < 0 && create_dir_flag)
+ {
+ create_all_directories (output_name.ds_string);
+ res = mknod (output_name.ds_string, in_file_stat.st_mode,
+ in_file_stat.st_rdev);
+ }
+ if (res < 0)
+ {
+ mknod_error (output_name.ds_string);
+ continue;
+ }
+ set_copypass_perms (-1, output_name.ds_string, &in_file_stat);
+ }
+ }
+
+#ifdef S_ISLNK
+ else if (S_ISLNK (in_file_stat.st_mode))
+ {
+ char *link_name;
+ int link_size;
+ link_name = (char *) xmalloc ((unsigned int) in_file_stat.st_size + 1);
+
+ link_size = readlink (input_name.ds_string, link_name,
+ in_file_stat.st_size);
+ if (link_size < 0)
+ {
+ readlink_error (input_name.ds_string);
+ free (link_name);
+ continue;
+ }
+ link_name[link_size] = '\0';
+
+ res = UMASKED_SYMLINK (link_name, output_name.ds_string,
+ in_file_stat.st_mode);
+ if (res < 0 && create_dir_flag)
+ {
+ create_all_directories (output_name.ds_string);
+ res = UMASKED_SYMLINK (link_name, output_name.ds_string,
+ in_file_stat.st_mode);
+ }
+ if (res < 0)
+ {
+ symlink_error (output_name.ds_string, link_name);
+ free (link_name);
+ continue;
+ }
+
+ /* Set the attributes of the new link. */
+ if (!no_chown_flag)
+ {
+ uid_t uid = set_owner_flag ? set_owner : in_file_stat.st_uid;
+ gid_t gid = set_group_flag ? set_group : in_file_stat.st_gid;
+ if ((lchown (output_name.ds_string, uid, gid) < 0)
+ && errno != EPERM)
+ chown_error_details (output_name.ds_string, uid, gid);
+ }
+ free (link_name);
+ }
+#endif
+ else
+ {
+ error (0, 0, _("%s: unknown file type"), input_name.ds_string);
+ }
+
+ if (verbose_flag)
+ fprintf (stderr, "%s\n", output_name.ds_string);
+ if (dot_flag)
+ fputc ('.', stderr);
+ }
+
+ if (dot_flag)
+ fputc ('\n', stderr);
+
+ apply_delayed_set_stat ();
+
+ if (!quiet_flag)
+ {
+ size_t blocks = (output_bytes + io_block_size - 1) / io_block_size;
+ fprintf (stderr,
+ ngettext ("%lu block\n", "%lu blocks\n",
+ (unsigned long) blocks),
+ (unsigned long) blocks);
+ }
+}
+
+/* Try and create a hard link from FILE_NAME to another file
+ with the given major/minor device number and inode. If no other
+ file with the same major/minor/inode numbers is known, add this file
+ to the list of known files and associated major/minor/inode numbers
+ and return -1. If another file with the same major/minor/inode
+ numbers is found, try and create another link to it using
+ link_to_name, and return 0 for success and -1 for failure. */
+
+int
+link_to_maj_min_ino (char *file_name, int st_dev_maj, int st_dev_min,
+ ino_t st_ino)
+{
+ int link_res;
+ char *link_name;
+ link_res = -1;
+ /* Is the file a link to a previously copied file? */
+ link_name = find_inode_file (st_ino,
+ st_dev_maj,
+ st_dev_min);
+ if (link_name == NULL)
+ add_inode (st_ino, file_name,
+ st_dev_maj,
+ st_dev_min);
+ else
+ link_res = link_to_name (file_name, link_name);
+ return link_res;
+}
+
+/* Try and create a hard link from LINK_NAME to LINK_TARGET. If
+ `create_dir_flag' is set, any non-existent (parent) directories
+ needed by LINK_NAME will be created. If the link is successfully
+ created and `verbose_flag' is set, print "LINK_TARGET linked to LINK_NAME\n".
+ If the link can not be created and `link_flag' is set, print
+ "cannot link LINK_TARGET to LINK_NAME\n". Return 0 if the link
+ is created, -1 otherwise. */
+
+int
+link_to_name (char *link_name, char *link_target)
+{
+ int res = link (link_target, link_name);
+ if (res < 0 && create_dir_flag)
+ {
+ create_all_directories (link_name);
+ res = link (link_target, link_name);
+ }
+ if (res == 0)
+ {
+ if (verbose_flag)
+ error (0, 0, _("%s linked to %s"),
+ link_target, link_name);
+ }
+ else if (link_flag)
+ {
+ error (0, errno, _("cannot link %s to %s"),
+ link_target, link_name);
+ }
+ return res;
+}
diff --git a/src/cpio.h b/src/cpio.h
new file mode 100644
index 0000000..b2aec61
--- /dev/null
+++ b/src/cpio.h
@@ -0,0 +1,72 @@
+/* Extended cpio format from POSIX.1.
+ Copyright (C) 1992, 2005, 2007, 2010 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 3, 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA. */
+
+#ifndef _CPIO_H
+
+#define _CPIO_H 1
+
+/* A cpio archive consists of a sequence of files.
+ Each file has a 76 byte header,
+ a variable length, NUL terminated filename,
+ and variable length file data.
+ A header for a filename "TRAILER!!!" indicates the end of the archive. */
+
+#define CPIO_TRAILER_NAME "TRAILER!!!"
+
+/* All the fields in the header are ISO 646 (approximately ASCII) strings
+ of octal numbers, left padded, not NUL terminated.
+
+ Field Name Length in Bytes Notes
+ c_magic 6 must be "070707"
+ c_dev 6
+ c_ino 6
+ c_mode 6 see below for value
+ c_uid 6
+ c_gid 6
+ c_nlink 6
+ c_rdev 6 only valid for chr and blk special files
+ c_mtime 11
+ c_namesize 6 count includes terminating NUL in pathname
+ c_filesize 11 must be 0 for FIFOs and directories */
+
+/* Values for c_mode, OR'd together: */
+
+#define C_IRUSR 000400
+#define C_IWUSR 000200
+#define C_IXUSR 000100
+#define C_IRGRP 000040
+#define C_IWGRP 000020
+#define C_IXGRP 000010
+#define C_IROTH 000004
+#define C_IWOTH 000002
+#define C_IXOTH 000001
+
+#define C_ISUID 004000
+#define C_ISGID 002000
+#define C_ISVTX 001000
+
+#define C_ISBLK 060000
+#define C_ISCHR 020000
+#define C_ISDIR 040000
+#define C_ISFIFO 010000
+#define C_ISSOCK 0140000
+#define C_ISLNK 0120000
+#define C_ISCTG 0110000
+#define C_ISREG 0100000
+
+#endif /* cpio.h */
diff --git a/src/cpiohdr.h b/src/cpiohdr.h
new file mode 100644
index 0000000..bb1ad6b
--- /dev/null
+++ b/src/cpiohdr.h
@@ -0,0 +1,132 @@
+/* Extended cpio header from POSIX.1.
+ Copyright (C) 1992, 2006, 2007, 2010 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 3, 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA. */
+
+#ifndef _CPIOHDR_H
+
+#define _CPIOHDR_H 1
+
+#include <cpio.h>
+
+#ifdef HAVE_ATTRIB_PACKED
+#define ATTRIB_PACKED __attribute__((packed))
+#endif
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(1)
+#endif
+
+#ifdef HAVE_PRAGMA_PACK_HPPA
+#pragma pack 1
+#endif
+
+struct old_cpio_header
+{
+ unsigned short c_magic;
+ unsigned short c_dev;
+ unsigned short c_ino;
+ unsigned short c_mode;
+ unsigned short c_uid;
+ unsigned short c_gid;
+ unsigned short c_nlink;
+ unsigned short c_rdev;
+ unsigned short c_mtimes[2];
+ unsigned short c_namesize;
+ unsigned short c_filesizes[2];
+} ATTRIB_PACKED;
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(1)
+#endif
+
+#ifdef HAVE_PRAGMA_PACK_HPPA
+#pragma pack 1
+#endif
+struct old_ascii_header
+{
+ char c_magic[6];
+ char c_dev[6];
+ char c_ino[6];
+ char c_mode[6];
+ char c_uid[6];
+ char c_gid[6];
+ char c_nlink[6];
+ char c_rdev[6];
+ char c_mtime[11];
+ char c_namesize[6];
+ char c_filesize[11];
+} ATTRIB_PACKED;
+
+/* "New" portable format and CRC format:
+
+ Each file has a 110 byte header,
+ a variable length, NUL terminated filename,
+ and variable length file data.
+ A header for a filename "TRAILER!!!" indicates the end of the archive. */
+
+/* All the fields in the header are ISO 646 (approximately ASCII) strings
+ of hexadecimal numbers, left padded, not NUL terminated: */
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(1)
+#endif
+
+#ifdef HAVE_PRAGMA_PACK_HPPA
+#pragma pack 1
+#endif
+struct new_ascii_header
+{
+ char c_magic[6]; /* "070701" for "new" portable format
+ "070702" for CRC format */
+ char c_ino[8];
+ char c_mode[8];
+ char c_uid[8];
+ char c_gid[8];
+ char c_nlink[8];
+ char c_mtime[8];
+ char c_filesize[8]; /* must be 0 for FIFOs and directories */
+ char c_dev_maj[8];
+ char c_dev_min[8];
+ char c_rdev_maj[8]; /* only valid for chr and blk special files */
+ char c_rdev_min[8]; /* only valid for chr and blk special files */
+ char c_namesize[8]; /* count includes terminating NUL in pathname */
+ char c_chksum[8]; /* 0 for "new" portable format; for CRC format
+ the sum of all the bytes in the file */
+} ATTRIB_PACKED;
+
+struct cpio_file_stat /* Internal representation of a CPIO header */
+{
+ unsigned short c_magic;
+ ino_t c_ino;
+ mode_t c_mode;
+ uid_t c_uid;
+ gid_t c_gid;
+ size_t c_nlink;
+ time_t c_mtime;
+ off_t c_filesize;
+ long c_dev_maj;
+ long c_dev_min;
+ long c_rdev_maj;
+ long c_rdev_min;
+ size_t c_namesize;
+ unsigned long c_chksum;
+ char *c_name;
+ char *c_tar_linkname;
+};
+
+
+#endif /* cpiohdr.h */
diff --git a/src/defer.c b/src/defer.c
new file mode 100644
index 0000000..a213f81
--- /dev/null
+++ b/src/defer.c
@@ -0,0 +1,44 @@
+/* defer.c - handle "defered" links in newc and crc archives
+ Copyright (C) 1993, 2003, 2004, 2006, 2007, 2010 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 3, 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA. */
+
+#include <system.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include "cpiohdr.h"
+#include "extern.h"
+#include "defer.h"
+
+struct deferment *
+create_deferment (struct cpio_file_stat *file_hdr)
+{
+ struct deferment *d;
+ d = (struct deferment *) xmalloc (sizeof (struct deferment) );
+ d->header = *file_hdr;
+ d->header.c_name = (char *) xmalloc (strlen (file_hdr->c_name) + 1);
+ strcpy (d->header.c_name, file_hdr->c_name);
+ return d;
+}
+
+void
+free_deferment (struct deferment *d)
+{
+ free (d->header.c_name);
+ free (d);
+}
diff --git a/src/defer.h b/src/defer.h
new file mode 100644
index 0000000..3262649
--- /dev/null
+++ b/src/defer.h
@@ -0,0 +1,27 @@
+/* defer.h
+ Copyright (C) 1993, 2001, 2004, 2006, 2007, 2010 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 3, 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA. */
+
+struct deferment
+ {
+ struct deferment *next;
+ struct cpio_file_stat header;
+ };
+
+struct deferment *create_deferment (struct cpio_file_stat *file_hdr);
+void free_deferment (struct deferment *d);
diff --git a/src/dstring.c b/src/dstring.c
new file mode 100644
index 0000000..6ff75bf
--- /dev/null
+++ b/src/dstring.c
@@ -0,0 +1,104 @@
+/* dstring.c - The dynamic string handling routines used by cpio.
+ Copyright (C) 1990, 1991, 1992, 2004, 2007, 2010 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 3, 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA. */
+
+#if defined(HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include "dstring.h"
+
+char *xmalloc (unsigned n);
+char *xrealloc (char *p, unsigned n);
+
+/* Initialiaze dynamic string STRING with space for SIZE characters. */
+
+void
+ds_init (dynamic_string *string, int size)
+{
+ string->ds_length = size;
+ string->ds_string = (char *) xmalloc (size);
+}
+
+/* Expand dynamic string STRING, if necessary, to hold SIZE characters. */
+
+void
+ds_resize (dynamic_string *string, int size)
+{
+ if (size > string->ds_length)
+ {
+ string->ds_length = size;
+ string->ds_string = (char *) xrealloc ((char *) string->ds_string, size);
+ }
+}
+
+/* Dynamic string S gets a string terminated by the EOS character
+ (which is removed) from file F. S will increase
+ in size during the function if the string from F is longer than
+ the current size of S.
+ Return NULL if end of file is detected. Otherwise,
+ Return a pointer to the null-terminated string in S. */
+
+char *
+ds_fgetstr (FILE *f, dynamic_string *s, char eos)
+{
+ int insize; /* Amount needed for line. */
+ int strsize; /* Amount allocated for S. */
+ int next_ch;
+
+ /* Initialize. */
+ insize = 0;
+ strsize = s->ds_length;
+
+ /* Read the input string. */
+ next_ch = getc (f);
+ while (next_ch != eos && next_ch != EOF)
+ {
+ if (insize >= strsize - 1)
+ {
+ ds_resize (s, strsize * 2 + 2);
+ strsize = s->ds_length;
+ }
+ s->ds_string[insize++] = next_ch;
+ next_ch = getc (f);
+ }
+ s->ds_string[insize++] = '\0';
+
+ if (insize == 1 && next_ch == EOF)
+ return NULL;
+ else
+ return s->ds_string;
+}
+
+char *
+ds_fgets (FILE *f, dynamic_string *s)
+{
+ return ds_fgetstr (f, s, '\n');
+}
+
+char *
+ds_fgetname (FILE *f, dynamic_string *s)
+{
+ return ds_fgetstr (f, s, '\0');
+}
diff --git a/src/dstring.h b/src/dstring.h
new file mode 100644
index 0000000..39d63f0
--- /dev/null
+++ b/src/dstring.h
@@ -0,0 +1,51 @@
+/* dstring.h - Dynamic string handling include file. Requires strings.h.
+ Copyright (C) 1990, 1991, 1992, 2004, 2007, 2010 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 3, 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA. */
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* A dynamic string consists of record that records the size of an
+ allocated string and the pointer to that string. The actual string
+ is a normal zero byte terminated string that can be used with the
+ usual string functions. The major difference is that the
+ dynamic_string routines know how to get more space if it is needed
+ by allocating new space and copying the current string. */
+
+typedef struct
+{
+ int ds_length; /* Actual amount of storage allocated. */
+ char *ds_string; /* String. */
+} dynamic_string;
+
+
+/* Macros that look similar to the original string functions.
+ WARNING: These macros work only on pointers to dynamic string records.
+ If used with a real record, an "&" must be used to get the pointer. */
+#define ds_strlen(s) strlen ((s)->ds_string)
+#define ds_strcmp(s1, s2) strcmp ((s1)->ds_string, (s2)->ds_string)
+#define ds_strncmp(s1, s2, n) strncmp ((s1)->ds_string, (s2)->ds_string, n)
+#define ds_index(s, c) index ((s)->ds_string, c)
+#define ds_rindex(s, c) rindex ((s)->ds_string, c)
+
+void ds_init (dynamic_string *string, int size);
+void ds_resize (dynamic_string *string, int size);
+char *ds_fgetname (FILE *f, dynamic_string *s);
+char *ds_fgets (FILE *f, dynamic_string *s);
+char *ds_fgetstr (FILE *f, dynamic_string *s, char eos);
diff --git a/src/extern.h b/src/extern.h
new file mode 100644
index 0000000..4f94d40
--- /dev/null
+++ b/src/extern.h
@@ -0,0 +1,219 @@
+/* extern.h - External declarations for cpio. Requires system.h.
+ Copyright (C) 1990, 1991, 1992, 2001, 2006, 2007, 2009, 2010 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 3, 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA. */
+
+#include "paxlib.h"
+#include "quotearg.h"
+#include "quote.h"
+
+enum archive_format
+{
+ arf_unknown, arf_binary, arf_oldascii, arf_newascii, arf_crcascii,
+ arf_tar, arf_ustar, arf_hpoldascii, arf_hpbinary
+};
+
+extern enum archive_format archive_format;
+extern int reset_time_flag;
+extern int io_block_size;
+extern int create_dir_flag;
+extern int rename_flag;
+extern char *rename_batch_file;
+extern int table_flag;
+extern int unconditional_flag;
+extern int verbose_flag;
+extern int dot_flag;
+extern int link_flag;
+extern int retain_time_flag;
+extern int crc_i_flag;
+extern int append_flag;
+extern int swap_bytes_flag;
+extern int swap_halfwords_flag;
+extern int swapping_bytes;
+extern int swapping_halfwords;
+extern int set_owner_flag;
+extern uid_t set_owner;
+extern int set_group_flag;
+extern gid_t set_group;
+extern int no_chown_flag;
+extern int sparse_flag;
+extern int quiet_flag;
+extern int only_verify_crc_flag;
+extern int no_abs_paths_flag;
+extern unsigned int warn_option;
+extern mode_t newdir_umask;
+
+/* Values for warn_option */
+#define CPIO_WARN_NONE 0
+#define CPIO_WARN_TRUNCATE 0x01
+#define CPIO_WARN_INTERDIR 0x02
+#define CPIO_WARN_ALL (unsigned int)-1
+
+extern bool to_stdout_option;
+
+extern int last_header_start;
+extern int copy_matching_files;
+extern int numeric_uid;
+extern char *pattern_file_name;
+extern char *new_media_message;
+extern char *new_media_message_with_number;
+extern char *new_media_message_after_number;
+extern int archive_des;
+extern char *archive_name;
+extern char *rsh_command_option;
+extern unsigned long crc;
+extern int delayed_seek_count;
+#ifdef DEBUG_CPIO
+extern int debug_flag;
+#endif
+
+extern char *input_buffer, *output_buffer;
+extern char *in_buff, *out_buff;
+extern size_t input_buffer_size;
+extern size_t input_size, output_size;
+extern off_t input_bytes, output_bytes;
+
+extern char *directory_name;
+extern char **save_patterns;
+extern int num_patterns;
+extern char name_end;
+extern char input_is_special;
+extern char output_is_special;
+extern char input_is_seekable;
+extern char output_is_seekable;
+extern int (*xstat) ();
+extern void (*copy_function) ();
+
+
+/* copyin.c */
+void warn_junk_bytes (long bytes_skipped);
+/* FIXME: make read_* static in copyin.c */
+void read_in_header (struct cpio_file_stat *file_hdr, int in_des);
+void read_in_old_ascii (struct cpio_file_stat *file_hdr, int in_des);
+void read_in_new_ascii (struct cpio_file_stat *file_hdr, int in_des);
+void read_in_binary (struct cpio_file_stat *file_hdr,
+ struct old_cpio_header *short_hdr, int in_des);
+void swab_array (char *arg, int count);
+void process_copy_in (void);
+void long_format (struct cpio_file_stat *file_hdr, char *link_name);
+void print_name_with_quoting (char *p);
+
+/* copyout.c */
+int write_out_header (struct cpio_file_stat *file_hdr, int out_des);
+void process_copy_out (void);
+
+/* copypass.c */
+void process_copy_pass (void);
+int link_to_maj_min_ino (char *file_name, int st_dev_maj,
+ int st_dev_min, ino_t st_ino);
+int link_to_name (char *link_name, char *link_target);
+
+/* dirname.c */
+char *dirname (char *path);
+
+/* filemode.c */
+void mode_string (unsigned int mode, char *str);
+
+/* idcache.c */
+char *getgroup (gid_t gid);
+char *getuser (uid_t uid);
+uid_t *getuidbyname (char *user);
+gid_t *getgidbyname (char *group);
+
+/* main.c */
+void process_args (int argc, char *argv[]);
+void initialize_buffers (void);
+
+/* makepath.c */
+int make_path (char *argpath, uid_t owner, gid_t group,
+ const char *verbose_fmt_string);
+
+/* tar.c */
+void write_out_tar_header (struct cpio_file_stat *file_hdr, int out_des);
+int null_block (long *block, int size);
+void read_in_tar_header (struct cpio_file_stat *file_hdr, int in_des);
+int otoa (char *s, unsigned long *n);
+int is_tar_header (char *buf);
+int is_tar_filename_too_long (char *name);
+
+/* userspec.c */
+char *parse_user_spec (char *name, uid_t *uid, gid_t *gid,
+ char **username, char **groupname);
+
+/* util.c */
+void tape_empty_output_buffer (int out_des);
+void disk_empty_output_buffer (int out_des);
+void swahw_array (char *ptr, int count);
+void tape_buffered_write (char *in_buf, int out_des, off_t num_bytes);
+void tape_buffered_read (char *in_buf, int in_des, off_t num_bytes);
+int tape_buffered_peek (char *peek_buf, int in_des, int num_bytes);
+void tape_toss_input (int in_des, off_t num_bytes);
+void copy_files_tape_to_disk (int in_des, int out_des, off_t num_bytes);
+void copy_files_disk_to_tape (int in_des, int out_des, off_t num_bytes, char *filename);
+void copy_files_disk_to_disk (int in_des, int out_des, off_t num_bytes, char *filename);
+void warn_if_file_changed (char *file_name, off_t old_file_size,
+ time_t old_file_mtime);
+void create_all_directories (char *name);
+void prepare_append (int out_file_des);
+char *find_inode_file (ino_t node_num,
+ unsigned long major_num, unsigned long minor_num);
+void add_inode (ino_t node_num, char *file_name,
+ unsigned long major_num, unsigned long minor_num);
+int open_archive (char *file);
+void tape_offline (int tape_des);
+void get_next_reel (int tape_des);
+void set_new_media_message (char *message);
+#ifdef HPUX_CDF
+char *add_cdf_double_slashes (char *filename);
+#endif
+void write_nuls_to_file (off_t num_bytes, int out_des,
+ void (*writer) (char *in_buf,
+ int out_des, off_t num_bytes));
+#define DISK_IO_BLOCK_SIZE 512
+
+/* FIXME: Move to system.h? */
+#ifndef SYMLINK_USES_UMASK
+# define UMASKED_SYMLINK(name1,name2,mode) symlink(name1,name2)
+#else
+# define UMASKED_SYMLINK(name1,name2,mode) umasked_symlink(name1,name2,mode)
+#endif /* SYMLINK_USES_UMASK */
+
+void set_perms (int fd, struct cpio_file_stat *header);
+void set_file_times (int fd, const char *name, unsigned long atime,
+ unsigned long mtime);
+void stat_to_cpio (struct cpio_file_stat *hdr, struct stat *st);
+void cpio_to_stat (struct stat *st, struct cpio_file_stat *hdr);
+void cpio_safer_name_suffix (char *name, bool link_target,
+ bool absolute_names, bool strip_leading_dots);
+int cpio_create_dir (struct cpio_file_stat *file_hdr, int existing_dir);
+
+/* FIXME: These two defines should be defined in paxutils */
+#define LG_8 3
+#define LG_16 4
+
+uintmax_t from_ascii (char const *where, size_t digs, unsigned logbase);
+
+#define FROM_OCTAL(f) from_ascii (f, sizeof f, LG_8)
+#define FROM_HEX(f) from_ascii (f, sizeof f, LG_16)
+
+void delay_cpio_set_stat (struct cpio_file_stat *file_stat,
+ mode_t invert_permissions);
+void delay_set_stat (char const *file_name, struct stat *st,
+ mode_t invert_permissions);
+int repair_delayed_set_stat (struct cpio_file_stat *file_hdr);
+void apply_delayed_set_stat (void);
+
diff --git a/src/fatal.c b/src/fatal.c
new file mode 100644
index 0000000..16413cd
--- /dev/null
+++ b/src/fatal.c
@@ -0,0 +1,27 @@
+/* This file is part of GNU cpio.
+ Copyright (C) 2005, 2007, 2010 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 3, 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA. */
+
+#include <system.h>
+#include <paxlib.h>
+
+void
+fatal_exit ()
+{
+ exit (PAXEXIT_FAILURE);
+}
+
diff --git a/src/filemode.c b/src/filemode.c
new file mode 100644
index 0000000..9c816ea
--- /dev/null
+++ b/src/filemode.c
@@ -0,0 +1,244 @@
+/* filemode.c -- make a string describing file modes
+ Copyright (C) 1985, 1990, 1993, 2004, 2007, 2010 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 3, 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if !S_IRUSR
+# if S_IREAD
+# define S_IRUSR S_IREAD
+# else
+# define S_IRUSR 00400
+# endif
+#endif
+
+#if !S_IWUSR
+# if S_IWRITE
+# define S_IWUSR S_IWRITE
+# else
+# define S_IWUSR 00200
+# endif
+#endif
+
+#if !S_IXUSR
+# if S_IEXEC
+# define S_IXUSR S_IEXEC
+# else
+# define S_IXUSR 00100
+# endif
+#endif
+
+#ifdef STAT_MACROS_BROKEN
+#undef S_ISBLK
+#undef S_ISCHR
+#undef S_ISDIR
+#undef S_ISFIFO
+#undef S_ISLNK
+#undef S_ISMPB
+#undef S_ISMPC
+#undef S_ISNWK
+#undef S_ISREG
+#undef S_ISSOCK
+#endif /* STAT_MACROS_BROKEN. */
+
+#if !defined(S_ISBLK) && defined(S_IFBLK)
+#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
+#endif
+#if !defined(S_ISCHR) && defined(S_IFCHR)
+#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+#endif
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+#if !defined(S_ISREG) && defined(S_IFREG)
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+#if !defined(S_ISFIFO) && defined(S_IFIFO)
+#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+#endif
+#if !defined(S_ISLNK) && defined(S_IFLNK)
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+#if !defined(S_ISSOCK) && defined(S_IFSOCK)
+#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+#endif
+#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */
+#define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
+#define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
+#endif
+#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */
+#define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
+#endif
+
+/* Return a character indicating the type of file described by
+ file mode BITS:
+ 'd' for directories
+ 'b' for block special files
+ 'c' for character special files
+ 'm' for multiplexor files
+ 'l' for symbolic links
+ 's' for sockets
+ 'p' for fifos
+ '-' for regular files
+ '?' for any other file type. */
+
+static char
+ftypelet (long bits)
+{
+#ifdef S_ISBLK
+ if (S_ISBLK (bits))
+ return 'b';
+#endif
+ if (S_ISCHR (bits))
+ return 'c';
+ if (S_ISDIR (bits))
+ return 'd';
+ if (S_ISREG (bits))
+ return '-';
+#ifdef S_ISFIFO
+ if (S_ISFIFO (bits))
+ return 'p';
+#endif
+#ifdef S_ISLNK
+ if (S_ISLNK (bits))
+ return 'l';
+#endif
+#ifdef S_ISSOCK
+ if (S_ISSOCK (bits))
+ return 's';
+#endif
+#ifdef S_ISMPC
+ if (S_ISMPC (bits))
+ return 'm';
+#endif
+#ifdef S_ISNWK
+ if (S_ISNWK (bits))
+ return 'n';
+#endif
+ return '?';
+}
+
+/* Look at read, write, and execute bits in BITS and set
+ flags in CHARS accordingly. */
+
+static void
+rwx (unsigned short bits, char *chars)
+{
+ chars[0] = (bits & S_IRUSR) ? 'r' : '-';
+ chars[1] = (bits & S_IWUSR) ? 'w' : '-';
+ chars[2] = (bits & S_IXUSR) ? 'x' : '-';
+}
+
+/* Set the 's' and 't' flags in file attributes string CHARS,
+ according to the file mode BITS. */
+
+static void
+setst (unsigned short bits, char *chars)
+{
+#ifdef S_ISUID
+ if (bits & S_ISUID)
+ {
+ if (chars[3] != 'x')
+ /* Set-uid, but not executable by owner. */
+ chars[3] = 'S';
+ else
+ chars[3] = 's';
+ }
+#endif
+#ifdef S_ISGID
+ if (bits & S_ISGID)
+ {
+ if (chars[6] != 'x')
+ /* Set-gid, but not executable by group. */
+ chars[6] = 'S';
+ else
+ chars[6] = 's';
+ }
+#endif
+#ifdef S_ISVTX
+ if (bits & S_ISVTX)
+ {
+ if (chars[9] != 'x')
+ /* Sticky, but not executable by others. */
+ chars[9] = 'T';
+ else
+ chars[9] = 't';
+ }
+#endif
+}
+
+/* Like filemodestring (see below), but only the relevant part of the
+ `struct stat' is given as an argument. */
+
+void
+mode_string (unsigned short mode, char *str)
+{
+ str[0] = ftypelet ((long) mode);
+ rwx ((mode & 0700) << 0, &str[1]);
+ rwx ((mode & 0070) << 3, &str[4]);
+ rwx ((mode & 0007) << 6, &str[7]);
+ setst (mode, str);
+}
+
+/* filemodestring - fill in string STR with an ls-style ASCII
+ representation of the st_mode field of file stats block STATP.
+ 10 characters are stored in STR; no terminating null is added.
+ The characters stored in STR are:
+
+ 0 File type. 'd' for directory, 'c' for character
+ special, 'b' for block special, 'm' for multiplex,
+ 'l' for symbolic link, 's' for socket, 'p' for fifo,
+ '-' for regular, '?' for any other file type
+
+ 1 'r' if the owner may read, '-' otherwise.
+
+ 2 'w' if the owner may write, '-' otherwise.
+
+ 3 'x' if the owner may execute, 's' if the file is
+ set-user-id, '-' otherwise.
+ 'S' if the file is set-user-id, but the execute
+ bit isn't set.
+
+ 4 'r' if group members may read, '-' otherwise.
+
+ 5 'w' if group members may write, '-' otherwise.
+
+ 6 'x' if group members may execute, 's' if the file is
+ set-group-id, '-' otherwise.
+ 'S' if it is set-group-id but not executable.
+
+ 7 'r' if any user may read, '-' otherwise.
+
+ 8 'w' if any user may write, '-' otherwise.
+
+ 9 'x' if any user may execute, 't' if the file is "sticky"
+ (will be retained in swap space after execution), '-'
+ otherwise.
+ 'T' if the file is sticky but not executable. */
+
+void
+filemodestring (struct stat *statp, char *str)
+{
+ mode_string (statp->st_mode, str);
+}
+
diff --git a/src/filetypes.h b/src/filetypes.h
new file mode 100644
index 0000000..f80faab
--- /dev/null
+++ b/src/filetypes.h
@@ -0,0 +1,85 @@
+/* filetypes.h - deal with POSIX annoyances
+ Copyright (C) 1991, 2007, 2010 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 3, 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA. */
+
+/* Include sys/types.h and sys/stat.h before this file. */
+
+#ifndef S_ISREG /* Doesn't have POSIX.1 stat stuff. */
+#define mode_t unsigned short
+#endif
+
+/* Define the POSIX macros for systems that lack them. */
+#if !defined(S_ISBLK) && defined(S_IFBLK)
+#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
+#endif
+#if !defined(S_ISCHR) && defined(S_IFCHR)
+#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+#endif
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+#if !defined(S_ISREG) && defined(S_IFREG)
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+#if !defined(S_ISFIFO) && defined(S_IFIFO)
+#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+#endif
+#if !defined(S_ISLNK) && defined(S_IFLNK)
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+#if !defined(S_ISSOCK) && defined(S_IFSOCK)
+#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+#endif
+#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX network special */
+#define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
+#endif
+
+/* Define the file type bits used in cpio archives.
+ They have the same values as the S_IF bits in traditional Unix. */
+
+#define CP_IFMT 0170000 /* Mask for all file type bits. */
+
+#if defined(S_ISBLK)
+#define CP_IFBLK 0060000
+#endif
+#if defined(S_ISCHR)
+#define CP_IFCHR 0020000
+#endif
+#if defined(S_ISDIR)
+#define CP_IFDIR 0040000
+#endif
+#if defined(S_ISREG)
+#define CP_IFREG 0100000
+#endif
+#if defined(S_ISFIFO)
+#define CP_IFIFO 0010000
+#endif
+#if defined(S_ISLNK)
+#define CP_IFLNK 0120000
+#endif
+#if defined(S_ISSOCK)
+#define CP_IFSOCK 0140000
+#endif
+#if defined(S_ISNWK)
+#define CP_IFNWK 0110000
+#endif
+
+#ifndef S_ISLNK
+#define lstat stat
+#endif
+int lstat ();
+int stat ();
diff --git a/src/global.c b/src/global.c
new file mode 100644
index 0000000..cff9720
--- /dev/null
+++ b/src/global.c
@@ -0,0 +1,195 @@
+/* global.c - global variables and initial values for cpio.
+ Copyright (C) 1990, 1991, 1992, 2001, 2006, 2007, 2009, 2010 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 3, 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA. */
+
+#include <system.h>
+
+#include <sys/types.h>
+#include "cpiohdr.h"
+#include "dstring.h"
+#include "extern.h"
+
+/* If true, reset access times after reading files (-a). */
+int reset_time_flag = false;
+
+/* Block size value, initially 512. -B sets to 5120. */
+int io_block_size = 512;
+
+/* The header format to recognize and produce. */
+enum archive_format archive_format = arf_unknown;
+
+/* If true, create directories as needed. (-d with -i or -p) */
+int create_dir_flag = false;
+
+/* If true, interactively rename files. (-r) */
+int rename_flag = false;
+
+/* If non-NULL, the name of a file that will be read to
+ rename all of the files in the archive. --rename-batch-file. */
+char *rename_batch_file = NULL;
+
+/* If true, print a table of contents of input. (-t) */
+int table_flag = false;
+
+/* If true, copy unconditionally (older replaces newer). (-u) */
+int unconditional_flag = false;
+
+/* If true, list the files processed, or ls -l style output with -t. (-v) */
+int verbose_flag = false;
+
+/* If true, print a . for each file processed. (-V) */
+int dot_flag = false;
+
+/* If true, link files whenever possible. Used with -p option. (-l) */
+int link_flag = false;
+
+/* If true, retain previous file modification time. (-m) */
+int retain_time_flag = false;
+
+/* Set true if crc_flag is true and we are doing a cpio -i. Used
+ by copy_files so it knows whether to compute the crc. */
+int crc_i_flag = false;
+
+/* If true, append to end of archive. (-A) */
+int append_flag = false;
+
+/* If true, swap bytes of each file during cpio -i. */
+int swap_bytes_flag = false;
+
+/* If true, swap halfwords of each file during cpio -i. */
+int swap_halfwords_flag = false;
+
+/* If true, we are swapping halfwords on the current file. */
+int swapping_halfwords = false;
+
+/* If true, we are swapping bytes on the current file. */
+int swapping_bytes = false;
+
+/* Umask for creating new directories */
+mode_t newdir_umask;
+
+/* If true, set ownership of all files to UID `set_owner'. */
+int set_owner_flag = false;
+uid_t set_owner;
+
+/* If true, set group ownership of all files to GID `set_group'. */
+int set_group_flag = false;
+gid_t set_group;
+
+/* If true, do not chown the files. */
+int no_chown_flag = false;
+
+/* If true, try to write sparse ("holey") files. */
+int sparse_flag = false;
+
+/* If true, don't report number of blocks copied. */
+int quiet_flag = false;
+
+/* If true, only read the archive and verify the files' CRC's, don't
+ actually extract the files. */
+int only_verify_crc_flag = false;
+
+/* If true, don't use any absolute paths, prefix them by `./'. */
+int no_abs_paths_flag = false;
+
+#ifdef DEBUG_CPIO
+/* If true, print debugging information. */
+int debug_flag = false;
+#endif
+
+/* File position of last header read. Only used during -A to determine
+ where the old TRAILER!!! record started. */
+int last_header_start = 0;
+
+/* With -i; if true, copy only files that match any of the given patterns;
+ if false, copy only files that do not match any of the patterns. (-f) */
+int copy_matching_files = true;
+
+/* With -itv; if true, list numeric uid and gid instead of translating them
+ into names. */
+int numeric_uid = false;
+
+/* Name of file containing additional patterns (-E). */
+char *pattern_file_name = NULL;
+
+/* Message to print when end of medium is reached (-M). */
+char *new_media_message = NULL;
+
+/* With -M with %d, message to print when end of medium is reached. */
+char *new_media_message_with_number = NULL;
+char *new_media_message_after_number = NULL;
+
+/* File descriptor containing the archive. */
+int archive_des;
+
+/* Name of file containing the archive, if known; NULL if stdin/out. */
+char *archive_name = NULL;
+
+/* Name of the remote shell command, if known; NULL otherwise. */
+char *rsh_command_option = NULL;
+
+/* CRC checksum. */
+unsigned long crc;
+
+/* Input and output buffers. */
+char *input_buffer, *output_buffer;
+
+/* The size of the input buffer. */
+size_t input_buffer_size;
+
+/* Current locations in `input_buffer' and `output_buffer'. */
+char *in_buff, *out_buff;
+
+/* Current number of bytes stored at `input_buff' and `output_buff'. */
+size_t input_size, output_size;
+
+off_t input_bytes, output_bytes;
+
+/* Saving of argument values for later reference. */
+char *directory_name = NULL;
+char **save_patterns;
+int num_patterns;
+
+/* Character that terminates file names read from stdin. */
+char name_end = '\n';
+
+/* true if input (cpio -i) or output (cpio -o) is a device node. */
+char input_is_special = false;
+char output_is_special = false;
+
+/* true if lseek works on the input. */
+char input_is_seekable = false;
+
+/* true if lseek works on the output. */
+char output_is_seekable = false;
+
+/* Print extra warning messages */
+unsigned int warn_option = 0;
+
+/* Extract to standard output? */
+bool to_stdout_option = false;
+
+/* The name this program was run with. */
+char *program_name;
+
+/* A pointer to either lstat or stat, depending on whether
+ dereferencing of symlinks is done for input files. */
+int (*xstat) ();
+
+/* Which copy operation to perform. (-i, -o, -p) */
+void (*copy_function) () = 0;
diff --git a/src/idcache.c b/src/idcache.c
new file mode 100644
index 0000000..4bcf79d
--- /dev/null
+++ b/src/idcache.c
@@ -0,0 +1,198 @@
+/* idcache.c -- map user and group IDs, cached for speed
+ Copyright (C) 1985, 1988, 1989, 1990, 2004, 2007, 2010 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 3, 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <xalloc.h>
+
+#include <system.h>
+
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#include <unistd.h>
+
+struct userid
+{
+ union
+ {
+ uid_t u;
+ gid_t g;
+ } id;
+ char *name;
+ struct userid *next;
+};
+
+static struct userid *user_alist;
+
+/* The members of this list have names not in the local passwd file. */
+static struct userid *nouser_alist;
+
+/* Translate UID to a login name or a stringified number,
+ with cache. */
+
+char *
+getuser (uid_t uid)
+{
+ register struct userid *tail;
+ struct passwd *pwent;
+ char usernum_string[20];
+
+ for (tail = user_alist; tail; tail = tail->next)
+ if (tail->id.u == uid)
+ return tail->name;
+
+ pwent = getpwuid (uid);
+ tail = (struct userid *) xmalloc (sizeof (struct userid));
+ tail->id.u = uid;
+ if (pwent == 0)
+ {
+ sprintf (usernum_string, "%u", (unsigned) uid);
+ tail->name = xstrdup (usernum_string);
+ }
+ else
+ tail->name = xstrdup (pwent->pw_name);
+
+ /* Add to the head of the list, so most recently used is first. */
+ tail->next = user_alist;
+ user_alist = tail;
+ return tail->name;
+}
+
+/* Translate USER to a UID, with cache.
+ Return NULL if there is no such user.
+ (We also cache which user names have no passwd entry,
+ so we don't keep looking them up.) */
+
+uid_t *
+getuidbyname (char *user)
+{
+ register struct userid *tail;
+ struct passwd *pwent;
+
+ for (tail = user_alist; tail; tail = tail->next)
+ /* Avoid a function call for the most common case. */
+ if (*tail->name == *user && !strcmp (tail->name, user))
+ return &tail->id.u;
+
+ for (tail = nouser_alist; tail; tail = tail->next)
+ /* Avoid a function call for the most common case. */
+ if (*tail->name == *user && !strcmp (tail->name, user))
+ return 0;
+
+ pwent = getpwnam (user);
+
+ tail = (struct userid *) xmalloc (sizeof (struct userid));
+ tail->name = xstrdup (user);
+
+ /* Add to the head of the list, so most recently used is first. */
+ if (pwent)
+ {
+ tail->id.u = pwent->pw_uid;
+ tail->next = user_alist;
+ user_alist = tail;
+ return &tail->id.u;
+ }
+
+ tail->next = nouser_alist;
+ nouser_alist = tail;
+ return 0;
+}
+
+/* Use the same struct as for userids. */
+static struct userid *group_alist;
+static struct userid *nogroup_alist;
+
+/* Translate GID to a group name or a stringified number,
+ with cache. */
+
+char *
+getgroup (gid_t gid)
+{
+ register struct userid *tail;
+ struct group *grent;
+ char groupnum_string[20];
+
+ for (tail = group_alist; tail; tail = tail->next)
+ if (tail->id.g == gid)
+ return tail->name;
+
+ grent = getgrgid (gid);
+ tail = (struct userid *) xmalloc (sizeof (struct userid));
+ tail->id.g = gid;
+ if (grent == 0)
+ {
+ sprintf (groupnum_string, "%u", (unsigned int) gid);
+ tail->name = xstrdup (groupnum_string);
+ }
+ else
+ tail->name = xstrdup (grent->gr_name);
+
+ /* Add to the head of the list, so most recently used is first. */
+ tail->next = group_alist;
+ group_alist = tail;
+ return tail->name;
+}
+
+/* Translate GROUP to a UID, with cache.
+ Return NULL if there is no such group.
+ (We also cache which group names have no group entry,
+ so we don't keep looking them up.) */
+
+gid_t *
+getgidbyname (char *group)
+{
+ register struct userid *tail;
+ struct group *grent;
+
+ for (tail = group_alist; tail; tail = tail->next)
+ /* Avoid a function call for the most common case. */
+ if (*tail->name == *group && !strcmp (tail->name, group))
+ return &tail->id.g;
+
+ for (tail = nogroup_alist; tail; tail = tail->next)
+ /* Avoid a function call for the most common case. */
+ if (*tail->name == *group && !strcmp (tail->name, group))
+ return 0;
+
+ grent = getgrnam (group);
+
+ tail = (struct userid *) xmalloc (sizeof (struct userid));
+ tail->name = xstrdup (group);
+
+ /* Add to the head of the list, so most recently used is first. */
+ if (grent)
+ {
+ tail->id.g = grent->gr_gid;
+ tail->next = group_alist;
+ group_alist = tail;
+ return &tail->id.g;
+ }
+
+ tail->next = nogroup_alist;
+ nogroup_alist = tail;
+ return 0;
+}
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..ba1b969
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,743 @@
+/* main.c - main program and argument processing for cpio.
+ Copyright (C) 1990, 1991, 1992, 2001, 2003, 2004, 2005, 2006, 2007,
+ 2009, 2010 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 3, 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA. */
+
+/* Written by Phil Nelson <phil@cs.wwu.edu>,
+ David MacKenzie <djm@gnu.ai.mit.edu>,
+ John Oleynick <juo@klinzhai.rutgers.edu>,
+ and Sergey Poznyakoff <gray@gnu.org> */
+
+#include <system.h>
+#include <paxlib.h>
+
+#include <stdio.h>
+#include <argp.h>
+#include <argp-version-etc.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#endif
+
+#include <progname.h>
+
+#include "filetypes.h"
+#include "cpiohdr.h"
+#include "dstring.h"
+#include "extern.h"
+#include <rmt.h>
+#include <rmt-command.h>
+#include "configmake.h"
+
+enum cpio_options {
+ NO_ABSOLUTE_FILENAMES_OPTION=256,
+ ABSOLUTE_FILENAMES_OPTION,
+ NO_PRESERVE_OWNER_OPTION,
+ ONLY_VERIFY_CRC_OPTION,
+ RENAME_BATCH_FILE_OPTION,
+ RSH_COMMAND_OPTION,
+ QUIET_OPTION,
+ SPARSE_OPTION,
+ FORCE_LOCAL_OPTION,
+ DEBUG_OPTION,
+ BLOCK_SIZE_OPTION,
+ TO_STDOUT_OPTION
+};
+
+const char *program_authors[] =
+ {
+ "Phil Nelson",
+ "David MacKenzie",
+ "John Oleynick",
+ "Sergey Poznyakoff",
+ NULL
+ };
+
+const char *argp_program_bug_address = "<" PACKAGE_BUGREPORT ">";
+static char doc[] = N_("GNU `cpio' copies files to and from archives\n\
+\n\
+Examples:\n\
+ # Copy files named in name-list to the archive\n\
+ cpio -o < name-list [> archive]\n\
+ # Extract files from the archive\n\
+ cpio -i [< archive]\n\
+ # Copy files named in name-list to destination-directory\n\
+ cpio -p destination-directory < name-list\n");
+
+/* Print usage error message and exit with error. */
+
+#define CHECK_USAGE(cond, opt, mode_opt) \
+ if (cond) \
+ ERROR((PAXEXIT_FAILURE, 0, _("%s is meaningless with %s"), opt, mode_opt));
+
+static struct argp_option options[] = {
+ /* ********** */
+#define GRID 10
+ {NULL, 0, NULL, 0,
+ N_("Main operation mode:"), GRID },
+ {"create", 'o', 0, 0,
+ N_("Create the archive (run in copy-out mode)"), GRID },
+ {"extract", 'i', 0, 0,
+ N_("Extract files from an archive (run in copy-in mode)"), GRID },
+ {"pass-through", 'p', 0, 0,
+ N_("Run in copy-pass mode"), GRID },
+ {"list", 't', 0, 0,
+ N_("Print a table of contents of the input"), GRID },
+#undef GRID
+
+ /* ********** */
+#define GRID 100
+ {NULL, 0, NULL, 0,
+ N_("Operation modifiers valid in any mode:"), GRID },
+
+ {"file", 'F', N_("[[USER@]HOST:]FILE-NAME"), 0,
+ N_("Use this FILE-NAME instead of standard input or output. Optional USER and HOST specify the user and host names in case of a remote archive"), GRID+1 },
+ {"force-local", FORCE_LOCAL_OPTION, 0, 0,
+ N_("Archive file is local, even if its name contains colons"), GRID+1 },
+ {"format", 'H', N_("FORMAT"), 0,
+ N_("Use given archive FORMAT"), GRID+1 },
+ {NULL, 'B', NULL, 0,
+ N_("Set the I/O block size to 5120 bytes"), GRID+1 },
+ {"block-size", BLOCK_SIZE_OPTION, N_("BLOCK-SIZE"), 0,
+ N_("Set the I/O block size to BLOCK-SIZE * 512 bytes"), GRID+1 },
+ {NULL, 'c', NULL, 0,
+ N_("Use the old portable (ASCII) archive format"), GRID+1 },
+ {"dot", 'V', NULL, 0,
+ N_("Print a \".\" for each file processed"), GRID+1 },
+ {"io-size", 'C', N_("NUMBER"), 0,
+ N_("Set the I/O block size to the given NUMBER of bytes"), GRID+1 },
+ {"message", 'M', N_("STRING"), 0,
+ N_("Print STRING when the end of a volume of the backup media is reached"),
+ GRID+1 },
+ {"nonmatching", 'f', 0, 0,
+ N_("Only copy files that do not match any of the given patterns"), GRID+1 },
+ {"numeric-uid-gid", 'n', 0, 0,
+ N_("In the verbose table of contents listing, show numeric UID and GID"),
+ GRID+1 },
+ {"rsh-command", RSH_COMMAND_OPTION, N_("COMMAND"), 0,
+ N_("Use remote COMMAND instead of rsh"), GRID+1 },
+ {"quiet", QUIET_OPTION, NULL, 0,
+ N_("Do not print the number of blocks copied"), GRID+1 },
+ {"verbose", 'v', NULL, 0,
+ N_("Verbosely list the files processed"), GRID+1 },
+#ifdef DEBUG_CPIO
+ {"debug", DEBUG_OPTION, NULL, 0,
+ N_("Enable debugging info"), GRID+1 },
+#endif
+ {"warning", 'W', N_("FLAG"), 0,
+ N_("Control warning display. Currently FLAG is one of 'none', 'truncate', 'all'. Multiple options accumulate."), GRID+1 },
+#undef GRID
+
+ /* ********** */
+#define GRID 200
+ {NULL, 0, NULL, 0,
+ N_("Operation modifiers valid only in copy-in mode:"), GRID },
+ {"pattern-file", 'E', N_("FILE"), 0,
+ N_("Read additional patterns specifying filenames to extract or list from FILE"), 210},
+ {"only-verify-crc", ONLY_VERIFY_CRC_OPTION, 0, 0,
+ N_("When reading a CRC format archive, only verify the CRC's of each file in the archive, don't actually extract the files"), 210},
+ {"rename", 'r', 0, 0,
+ N_("Interactively rename files"), GRID+1 },
+ {"rename-batch-file", RENAME_BATCH_FILE_OPTION, N_("FILE"), OPTION_HIDDEN,
+ "", GRID+1 },
+ {"swap", 'b', NULL, 0,
+ N_("Swap both halfwords of words and bytes of halfwords in the data. Equivalent to -sS"), GRID+1 },
+ {"swap-bytes", 's', NULL, 0,
+ N_("Swap the bytes of each halfword in the files"), GRID+1 },
+ {"swap-halfwords", 'S', NULL, 0,
+ N_("Swap the halfwords of each word (4 bytes) in the files"),
+ GRID+1 },
+ {"to-stdout", TO_STDOUT_OPTION, NULL, 0,
+ N_("Extract files to standard output"), GRID+1 },
+#undef GRID
+
+ /* ********** */
+#define GRID 300
+ {NULL, 0, NULL, 0,
+ N_("Operation modifiers valid only in copy-out mode:"), GRID },
+ {"append", 'A', 0, 0,
+ N_("Append to an existing archive."), GRID+1 },
+ {NULL, 'O', N_("[[USER@]HOST:]FILE-NAME"), 0,
+ N_("Archive filename to use instead of standard output. Optional USER and HOST specify the user and host names in case of a remote archive"), GRID+1 },
+#undef GRID
+
+ /* ********** */
+#define GRID 400
+ {NULL, 0, NULL, 0,
+ N_("Operation modifiers valid only in copy-pass mode:"), GRID},
+ {"link", 'l', 0, 0,
+ N_("Link files instead of copying them, when possible"), GRID+1 },
+
+#undef GRID
+
+ /* ********** */
+#define GRID 500
+ {NULL, 0, NULL, 0,
+ N_("Operation modifiers valid in copy-in and copy-out modes:"), GRID },
+ {"absolute-filenames", ABSOLUTE_FILENAMES_OPTION, 0, 0,
+ N_("Do not strip file system prefix components from the file names"),
+ GRID+1 },
+ {"no-absolute-filenames", NO_ABSOLUTE_FILENAMES_OPTION, 0, 0,
+ N_("Create all files relative to the current directory"), GRID+1 },
+#undef GRID
+ /* ********** */
+#define GRID 600
+ {NULL, 0, NULL, 0,
+ N_("Operation modifiers valid in copy-out and copy-pass modes:"), GRID },
+ {"null", '0', 0, 0,
+ N_("A list of filenames is terminated by a null character instead of a newline"), GRID+1 },
+ {NULL, 'I', N_("[[USER@]HOST:]FILE-NAME"), 0,
+ N_("Archive filename to use instead of standard input. Optional USER and HOST specify the user and host names in case of a remote archive"), GRID+1 },
+ {"dereference", 'L', 0, 0,
+ N_("Dereference symbolic links (copy the files that they point to instead of copying the links)."), GRID+1 },
+ {"owner", 'R', N_("[USER][:.][GROUP]"), 0,
+ N_("Set the ownership of all files created to the specified USER and/or GROUP"), GRID+1 },
+ {"reset-access-time", 'a', NULL, 0,
+ N_("Reset the access times of files after reading them"), GRID+1 },
+
+#undef GRID
+ /* ********** */
+#define GRID 700
+ {NULL, 0, NULL, 0,
+ N_("Operation modifiers valid in copy-in and copy-pass modes:"), GRID },
+ {"preserve-modification-time", 'm', 0, 0,
+ N_("Retain previous file modification times when creating files"), GRID+1 },
+ {"make-directories", 'd', 0, 0,
+ N_("Create leading directories where needed"), GRID+1 },
+ {"no-preserve-owner", NO_PRESERVE_OWNER_OPTION, 0, 0,
+ N_("Do not change the ownership of the files"), GRID+1 },
+ {"unconditional", 'u', NULL, 0,
+ N_("Replace all files unconditionally"), GRID+1 },
+ {"sparse", SPARSE_OPTION, NULL, 0,
+ N_("Write files with large blocks of zeros as sparse files"), GRID+1 },
+#undef GRID
+
+ {0, 0, 0, 0}
+};
+
+static char *input_archive_name = 0;
+static char *output_archive_name = 0;
+
+static int
+warn_control (char *arg)
+{
+ static struct warn_tab {
+ char *name;
+ int flag;
+ } warn_tab[] = {
+ { "none", CPIO_WARN_ALL },
+ { "truncate", CPIO_WARN_TRUNCATE },
+ { "all", CPIO_WARN_ALL },
+ { "interdir", CPIO_WARN_INTERDIR },
+ { NULL }
+ };
+ struct warn_tab *wt;
+ int offset = 0;
+
+ if (strcmp (arg, "none") == 0)
+ {
+ warn_option = 0;
+ return 0;
+ }
+
+ if (strlen (arg) > 2 && memcmp (arg, "no-", 3) == 0)
+ offset = 3;
+
+ for (wt = warn_tab; wt->name; wt++)
+ if (strcmp (arg + offset, wt->name) == 0)
+ {
+ if (offset)
+ warn_option &= ~wt->flag;
+ else
+ warn_option |= wt->flag;
+ return 0;
+ }
+
+ return 1;
+}
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ switch (key)
+ {
+ case '0': /* Read null-terminated filenames. */
+ name_end = '\0';
+ break;
+
+ case 'a': /* Reset access times. */
+ reset_time_flag = true;
+ break;
+
+ case 'A': /* Append to the archive. */
+ append_flag = true;
+ break;
+
+ case 'b': /* Swap bytes and halfwords. */
+ swap_bytes_flag = true;
+ swap_halfwords_flag = true;
+ break;
+
+ case 'B': /* Set block size to 5120. */
+ io_block_size = 5120;
+ break;
+
+ case BLOCK_SIZE_OPTION: /* --block-size */
+ io_block_size = atoi (arg);
+ if (io_block_size < 1)
+ error (2, 0, _("invalid block size"));
+ io_block_size *= 512;
+ break;
+
+ case 'c': /* Use the old portable ASCII format. */
+ if (archive_format != arf_unknown)
+ error (0, EXIT_FAILURE, _("Archive format multiply defined"));
+#ifdef SVR4_COMPAT
+ archive_format = arf_newascii; /* -H newc. */
+#else
+ archive_format = arf_oldascii; /* -H odc. */
+#endif
+ break;
+
+ case 'C': /* Block size. */
+ io_block_size = atoi (arg);
+ if (io_block_size < 1)
+ error (2, 0, _("invalid block size"));
+ break;
+
+ case 'd': /* Create directories where needed. */
+ create_dir_flag = true;
+ break;
+
+ case 'f': /* Only copy files not matching patterns. */
+ copy_matching_files = false;
+ break;
+
+ case 'E': /* Pattern file name. */
+ pattern_file_name = arg;
+ break;
+
+ case 'F': /* Archive file name. */
+ archive_name = arg;
+ break;
+
+ case 'H': /* Header format name. */
+ if (archive_format != arf_unknown)
+ error (PAXEXIT_FAILURE, 0, _("Archive format multiply defined"));
+ if (!strcasecmp (arg, "crc"))
+ archive_format = arf_crcascii;
+ else if (!strcasecmp (arg, "newc"))
+ archive_format = arf_newascii;
+ else if (!strcasecmp (arg, "odc"))
+ archive_format = arf_oldascii;
+ else if (!strcasecmp (arg, "bin"))
+ archive_format = arf_binary;
+ else if (!strcasecmp (arg, "ustar"))
+ archive_format = arf_ustar;
+ else if (!strcasecmp (arg, "tar"))
+ archive_format = arf_tar;
+ else if (!strcasecmp (arg, "hpodc"))
+ archive_format = arf_hpoldascii;
+ else if (!strcasecmp (arg, "hpbin"))
+ archive_format = arf_hpbinary;
+ else
+ error (2, 0, _("\
+invalid archive format `%s'; valid formats are:\n\
+crc newc odc bin ustar tar (all-caps also recognized)"), arg);
+ break;
+
+ case 'i': /* Copy-in mode. */
+ if (copy_function != 0)
+ error (PAXEXIT_FAILURE, 0, _("Mode already defined"));
+ copy_function = process_copy_in;
+ break;
+
+ case 'I': /* Input archive file name. */
+ input_archive_name = arg;
+ break;
+
+ case 'k': /* Handle corrupted archives. We always handle
+ corrupted archives, but recognize this
+ option for compatability. */
+ break;
+
+ case 'l': /* Link files when possible. */
+ link_flag = true;
+ break;
+
+ case 'L': /* Dereference symbolic links. */
+ xstat = stat;
+ break;
+
+ case 'm': /* Retain previous file modify times. */
+ retain_time_flag = true;
+ break;
+
+ case 'M': /* New media message. */
+ set_new_media_message (arg);
+ break;
+
+ case 'n': /* Long list owner and group as numbers. */
+ numeric_uid = true;
+ break;
+
+ case NO_ABSOLUTE_FILENAMES_OPTION: /* --no-absolute-filenames */
+ no_abs_paths_flag = true;
+ break;
+
+ case ABSOLUTE_FILENAMES_OPTION: /* --absolute-filenames */
+ no_abs_paths_flag = false;
+ break;
+
+ case NO_PRESERVE_OWNER_OPTION: /* --no-preserve-owner */
+ if (set_owner_flag || set_group_flag)
+ error (PAXEXIT_FAILURE, 0,
+ _("--no-preserve-owner cannot be used with --owner"));
+ no_chown_flag = true;
+ break;
+
+ case 'o': /* Copy-out mode. */
+ if (copy_function != 0)
+ error (PAXEXIT_FAILURE, 0, _("Mode already defined"));
+ copy_function = process_copy_out;
+ break;
+
+ case 'O': /* Output archive file name. */
+ output_archive_name = arg;
+ break;
+
+ case ONLY_VERIFY_CRC_OPTION:
+ only_verify_crc_flag = true;
+ break;
+
+ case 'p': /* Copy-pass mode. */
+ if (copy_function != 0)
+ error (PAXEXIT_FAILURE, 0, _("Mode already defined"));
+ copy_function = process_copy_pass;
+ break;
+
+ case RSH_COMMAND_OPTION:
+ rsh_command_option = arg;
+ break;
+
+ case 'r': /* Interactively rename. */
+ rename_flag = true;
+ break;
+
+ case RENAME_BATCH_FILE_OPTION:
+ rename_batch_file = arg;
+ break;
+
+ case QUIET_OPTION:
+ quiet_flag = true;
+ break;
+
+ case 'R': /* Set the owner. */
+ if (no_chown_flag)
+ error (PAXEXIT_FAILURE, 0,
+ _("--owner cannot be used with --no-preserve-owner"));
+ else
+ {
+ char *e, *u, *g;
+
+ e = parse_user_spec (arg, &set_owner, &set_group, &u, &g);
+ if (e)
+ error (PAXEXIT_FAILURE, 0, "%s: %s", arg, e);
+ if (u)
+ {
+ free (u);
+ set_owner_flag = true;
+ }
+ if (g)
+ {
+ free (g);
+ set_group_flag = true;
+ }
+ }
+ break;
+
+ case 's': /* Swap bytes. */
+ swap_bytes_flag = true;
+ break;
+
+ case 'S': /* Swap halfwords. */
+ swap_halfwords_flag = true;
+ break;
+
+ case 't': /* Only print a list. */
+ table_flag = true;
+ break;
+
+ case 'u': /* Replace all! Unconditionally! */
+ unconditional_flag = true;
+ break;
+
+ case 'v': /* Verbose! */
+ verbose_flag = true;
+ break;
+
+ case 'V': /* Print `.' for each file. */
+ dot_flag = true;
+ break;
+
+ case 'W':
+ if (warn_control (arg))
+ argp_error (state, _("Invalid value for --warning option: %s"), arg);
+ break;
+
+ case SPARSE_OPTION:
+ sparse_flag = true;
+ break;
+
+ case FORCE_LOCAL_OPTION:
+ force_local_option = 1;
+ break;
+
+#ifdef DEBUG_CPIO
+ case DEBUG_OPTION:
+ debug_flag = true;
+ break;
+#endif
+
+ case TO_STDOUT_OPTION:
+ to_stdout_option = true;
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static struct argp argp = {
+ options,
+ parse_opt,
+ N_("[destination-directory]"),
+ doc,
+ NULL,
+ NULL,
+ NULL
+};
+
+/* Process the arguments. Set all options and set up the copy pass
+ directory or the copy in patterns. */
+
+void
+process_args (int argc, char *argv[])
+{
+ void (*copy_in) (); /* Work around for pcc bug. */
+ void (*copy_out) ();
+ int index;
+
+ xstat = lstat;
+
+ if (argp_parse (&argp, argc, argv, ARGP_IN_ORDER, &index, NULL))
+ exit (PAXEXIT_FAILURE);
+
+ /* Do error checking and look at other args. */
+
+ if (copy_function == 0)
+ {
+ if (table_flag)
+ copy_function = process_copy_in;
+ else
+ error (PAXEXIT_FAILURE, 0,
+ _("You must specify one of -oipt options.\nTry `%s --help' or `%s --usage' for more information.\n"),
+ program_name, program_name);
+ }
+
+ /* Work around for pcc bug. */
+ copy_in = process_copy_in;
+ copy_out = process_copy_out;
+
+ if (copy_function == copy_in)
+ {
+ archive_des = 0;
+ CHECK_USAGE(link_flag, "--link", "--extract");
+ CHECK_USAGE(reset_time_flag, "--reset", "--extract");
+ CHECK_USAGE(xstat != lstat, "--dereference", "--extract");
+ CHECK_USAGE(append_flag, "--append", "--extract");
+ CHECK_USAGE(output_archive_name, "-O", "--extract");
+ if (to_stdout_option)
+ {
+ CHECK_USAGE(create_dir_flag, "--make-directories", "--to-stdout");
+ CHECK_USAGE(rename_flag, "--rename", "--to-stdout");
+ CHECK_USAGE(no_chown_flag, "--no-preserve-owner", "--to-stdout");
+ CHECK_USAGE(set_owner_flag||set_group_flag, "--owner", "--to-stdout");
+ CHECK_USAGE(retain_time_flag, "--preserve-modification-time",
+ "--to-stdout");
+ }
+
+ if (archive_name && input_archive_name)
+ error (PAXEXIT_FAILURE, 0,
+ _("Both -I and -F are used in copy-in mode"));
+
+ if (archive_format == arf_crcascii)
+ crc_i_flag = true;
+ num_patterns = argc - index;
+ save_patterns = &argv[index];
+ if (input_archive_name)
+ archive_name = input_archive_name;
+ }
+ else if (copy_function == copy_out)
+ {
+ if (index != argc)
+ error (PAXEXIT_FAILURE, 0, _("Too many arguments"));
+
+ archive_des = 1;
+ CHECK_USAGE(create_dir_flag, "--make-directories", "--create");
+ CHECK_USAGE(rename_flag, "--rename", "--create");
+ CHECK_USAGE(table_flag, "--list", "--create");
+ CHECK_USAGE(unconditional_flag, "--unconditional", "--create");
+ CHECK_USAGE(link_flag, "--link", "--create");
+ CHECK_USAGE(sparse_flag, "--sparse", "--create");
+ CHECK_USAGE(retain_time_flag, "--preserve-modification-time",
+ "--create");
+ CHECK_USAGE(no_chown_flag, "--no-preserve-owner", "--create");
+ CHECK_USAGE(swap_bytes_flag, "--swap-bytes (--swap)", "--create");
+ CHECK_USAGE(swap_halfwords_flag, "--swap-halfwords (--swap)",
+ "--create");
+ CHECK_USAGE(to_stdout_option, "--to-stdout", "--create");
+
+ if (append_flag && !(archive_name || output_archive_name))
+ error (PAXEXIT_FAILURE, 0,
+ _("--append is used but no archive file name is given (use -F or -O options)"));
+
+ CHECK_USAGE(rename_batch_file, "--rename-batch-file", "--create");
+ CHECK_USAGE(input_archive_name, "-I", "--create");
+ if (archive_name && output_archive_name)
+ error (PAXEXIT_FAILURE, 0,
+ _("Both -O and -F are used in copy-out mode"));
+
+ if (archive_format == arf_unknown)
+ archive_format = arf_binary;
+ if (output_archive_name)
+ archive_name = output_archive_name;
+ }
+ else
+ {
+ /* Copy pass. */
+ if (index < argc - 1)
+ error (PAXEXIT_FAILURE, 0, _("Too many arguments"));
+ else if (index > argc - 1)
+ error (PAXEXIT_FAILURE, 0, _("Not enough arguments"));
+
+ if (archive_format != arf_unknown)
+ error (PAXEXIT_FAILURE, 0,
+ _("Archive format is not specified in copy-pass mode (use --format option)"));
+
+ CHECK_USAGE(swap_bytes_flag, "--swap-bytes (--swap)", "--pass-through");
+ CHECK_USAGE(swap_halfwords_flag, "--swap-halfwords (--swap)",
+ "--pass-through");
+ CHECK_USAGE(table_flag, "--list", "--pass-through");
+ CHECK_USAGE(rename_flag, "--rename", "--pass-through");
+ CHECK_USAGE(append_flag, "--append", "--pass-through");
+ CHECK_USAGE(rename_batch_file, "--rename-batch-file", "--pass-through");
+ CHECK_USAGE(no_abs_paths_flag, "--no-absolute-pathnames",
+ "--pass-through");
+ CHECK_USAGE(no_abs_paths_flag, "--absolute-pathnames",
+ "--pass-through");
+ CHECK_USAGE(to_stdout_option, "--to-stdout", "--pass-through");
+
+ directory_name = argv[index];
+ }
+
+ if (archive_name)
+ {
+ if (copy_function != copy_in && copy_function != copy_out)
+ error (PAXEXIT_FAILURE, 0,
+ _("-F can be used only with --create or --extract"));
+ archive_des = open_archive (archive_name);
+ if (archive_des < 0)
+ error (PAXEXIT_FAILURE, errno, _("Cannot open %s"),
+ quotearg_colon (archive_name));
+ }
+
+ /* Prevent SysV non-root users from giving away files inadvertantly.
+ This happens automatically on BSD, where only root can give
+ away files. */
+ if (set_owner_flag == false && set_group_flag == false && geteuid ())
+ no_chown_flag = true;
+}
+
+/* Initialize the input and output buffers to their proper size and
+ initialize all variables associated with the input and output
+ buffers. */
+
+void
+initialize_buffers ()
+{
+ int in_buf_size, out_buf_size;
+
+ if (copy_function == process_copy_in)
+ {
+ /* Make sure the input buffer can always hold 2 blocks and that it
+ is big enough to hold 1 tar record (512 bytes) even if it
+ is not aligned on a block boundary. The extra buffer space
+ is needed by process_copyin and peek_in_buf to automatically
+ figure out what kind of archive it is reading. */
+ if (io_block_size >= 512)
+ in_buf_size = 2 * io_block_size;
+ else
+ in_buf_size = 1024;
+ out_buf_size = DISK_IO_BLOCK_SIZE;
+ }
+ else if (copy_function == process_copy_out)
+ {
+ in_buf_size = DISK_IO_BLOCK_SIZE;
+ out_buf_size = io_block_size;
+ }
+ else
+ {
+ in_buf_size = DISK_IO_BLOCK_SIZE;
+ out_buf_size = DISK_IO_BLOCK_SIZE;
+ }
+
+ input_buffer = (char *) xmalloc (in_buf_size);
+ in_buff = input_buffer;
+ input_buffer_size = in_buf_size;
+ input_size = 0;
+ input_bytes = 0;
+
+ output_buffer = (char *) xmalloc (out_buf_size);
+ out_buff = output_buffer;
+ output_size = 0;
+ output_bytes = 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ set_program_name (argv[0]);
+ argp_version_setup ("cpio", program_authors);
+ process_args (argc, argv);
+
+ initialize_buffers ();
+
+ (*copy_function) ();
+
+ if (archive_des >= 0 && rmtclose (archive_des) == -1)
+ error (PAXEXIT_FAILURE, errno, _("error closing archive"));
+
+ pax_exit ();
+}
diff --git a/src/makepath.c b/src/makepath.c
new file mode 100644
index 0000000..7631772
--- /dev/null
+++ b/src/makepath.c
@@ -0,0 +1,188 @@
+/* makepath.c -- Ensure that a directory path exists.
+ Copyright (C) 1990, 2006, 2007, 2010 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 3, 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA. */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu> and
+ Jim Meyering <meyering@cs.utexas.edu>. */
+
+/* This copy of makepath is almost like the fileutils one, but has
+ changes for HPUX CDF's. Maybe the 2 versions of makepath can
+ come together again in the future. */
+
+#include <system.h>
+#include <paxlib.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "cpiohdr.h"
+#include "dstring.h"
+#include "extern.h"
+
+/* Ensure that the directory ARGPATH exists.
+ Remove any trailing slashes from ARGPATH before calling this function.
+
+ Make all directory components that don't already exist with
+ permissions 700.
+ If OWNER and GROUP are non-negative, make them the UID and GID of
+ created directories.
+ If VERBOSE_FMT_STRING is nonzero, use it as a printf format
+ string for printing a message after successfully making a directory,
+ with the name of the directory that was just made as an argument.
+
+ Return 0 if ARGPATH exists as a directory with the proper
+ ownership and permissions when done, otherwise 1. */
+
+int
+make_path (char *argpath,
+ uid_t owner,
+ gid_t group,
+ const char *verbose_fmt_string)
+{
+ char *dirpath; /* A copy we can scribble NULs on. */
+ struct stat stats;
+ int retval = 0;
+ mode_t tmpmode;
+ mode_t invert_permissions;
+ int we_are_root = getuid () == 0;
+ dirpath = alloca (strlen (argpath) + 1);
+
+ strcpy (dirpath, argpath);
+
+ if (stat (dirpath, &stats))
+ {
+ tmpmode = MODE_RWX & ~ newdir_umask;
+ invert_permissions = we_are_root ? 0 : MODE_WXUSR & ~ tmpmode;
+
+ char *slash = dirpath;
+ while (*slash == '/')
+ slash++;
+ while ((slash = strchr (slash, '/')))
+ {
+#ifdef HPUX_CDF
+ int iscdf;
+ iscdf = 0;
+#endif
+ *slash = '\0';
+ if (stat (dirpath, &stats))
+ {
+#ifdef HPUX_CDF
+ /* If this component of the pathname ends in `+' and is
+ followed by 2 `/'s, then this is a CDF. We remove the
+ `+' from the name and create the directory. Later
+ we will "hide" the directory. */
+ if ( (*(slash +1) == '/') && (*(slash -1) == '+') )
+ {
+ iscdf = 1;
+ *(slash -1) = '\0';
+ }
+#endif
+ if (mkdir (dirpath, tmpmode ^ invert_permissions))
+ {
+ error (0, errno, _("cannot make directory `%s'"), dirpath);
+ return 1;
+ }
+ else
+ {
+ if (verbose_fmt_string != NULL)
+ error (0, 0, verbose_fmt_string, dirpath);
+
+ if (stat (dirpath, &stats))
+ stat_error (dirpath);
+ else
+ {
+ if (owner != -1)
+ stats.st_uid = owner;
+ if (group != -1)
+ stats.st_gid = group;
+
+ delay_set_stat (dirpath, &stats, invert_permissions);
+ }
+
+#ifdef HPUX_CDF
+ if (iscdf)
+ {
+ /* If this is a CDF, "hide" the directory by setting
+ its hidden/setuid bit. Also add the `+' back to
+ its name (since once it's "hidden" we must refer
+ to as `name+' instead of `name'). */
+ chmod (dirpath, 04700);
+ *(slash - 1) = '+';
+ }
+#endif
+ }
+ }
+ else if (!S_ISDIR (stats.st_mode))
+ {
+ error (0, 0, _("`%s' exists but is not a directory"), dirpath);
+ return 1;
+ }
+
+ *slash++ = '/';
+
+ /* Avoid unnecessary calls to `stat' when given
+ pathnames containing multiple adjacent slashes. */
+ while (*slash == '/')
+ slash++;
+ }
+
+ /* We're done making leading directories.
+ Make the final component of the path. */
+
+ if (mkdir (dirpath, tmpmode ^ invert_permissions))
+ {
+ /* In some cases, if the final component in dirpath was `.' then we
+ just got an EEXIST error from that last mkdir(). If that's
+ the case, ignore it. */
+ if ( (errno != EEXIST) ||
+ (stat (dirpath, &stats) != 0) ||
+ (!S_ISDIR (stats.st_mode) ) )
+ {
+ error (0, errno, _("cannot make directory `%s'"), dirpath);
+ return 1;
+ }
+ }
+ else if (stat (dirpath, &stats))
+ stat_error (dirpath);
+ else
+ {
+ if (owner != -1)
+ stats.st_uid = owner;
+ if (group != -1)
+ stats.st_gid = group;
+
+ delay_set_stat (dirpath, &stats, invert_permissions);
+ }
+
+ if (verbose_fmt_string != NULL)
+ error (0, 0, verbose_fmt_string, dirpath);
+
+ }
+ else
+ {
+ /* We get here if the entire path already exists. */
+
+ if (!S_ISDIR (stats.st_mode))
+ {
+ error (0, 0, _("`%s' exists but is not a directory"), dirpath);
+ return 1;
+ }
+
+ }
+
+ return retval;
+}
diff --git a/src/mt.c b/src/mt.c
new file mode 100644
index 0000000..a25e1bb
--- /dev/null
+++ b/src/mt.c
@@ -0,0 +1,361 @@
+/* mt -- control magnetic tape drive operation
+ Copyright (C) 1991, 1992, 1995, 2001, 2007, 2010 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 3, 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA
+*/
+
+
+/* If -f is not given, the environment variable TAPE is used;
+ if that is not set, a default device defined in sys/mtio.h is used.
+ The device must be either a character special file or a remote
+ tape drive with the form "[user@]system:path".
+ The default count is 1. Some operations ignore it.
+
+ Exit status:
+ 0 success
+ 1 invalid operation or device name
+ 2 operation failed
+
+ Operations (unique abbreviations are accepted):
+ eof, weof Write COUNT EOF marks at current position on tape.
+ fsf Forward space COUNT files.
+ Tape is positioned on the first block of the file.
+ bsf Backward space COUNT files.
+ Tape is positioned on the first block of the file.
+ fsr Forward space COUNT records.
+ bsr Backward space COUNT records.
+ bsfm Backward space COUNT file marks.
+ Tape is positioned on the beginning-of-the-tape side of
+ the file mark.
+ asf Absolute space to file number COUNT.
+ Equivalent to rewind followed by fsf COUNT.
+ eom Space to the end of the recorded media on the tape
+ (for appending files onto tapes).
+ rewind Rewind the tape.
+ offline, rewoffl
+ Rewind the tape and, if applicable, unload the tape.
+ status Print status information about the tape unit.
+ retension Rewind the tape, then wind it to the end of the reel,
+ then rewind it again.
+ erase Erase the tape.
+
+ David MacKenzie <djm@gnu.ai.mit.edu> */
+
+#include <system.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_MTIO_H
+# ifdef HAVE_SYS_IO_TRIOCTL_H
+# include <sys/io/trioctl.h>
+# endif
+# include <sys/mtio.h>
+#endif
+#include <sys/file.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <argp.h>
+#include <argp-version-etc.h>
+#include <progname.h>
+
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#endif
+#include <rmt-command.h>
+
+#include <rmt.h>
+
+#include <argmatch.h>
+#include <paxlib.h>
+#include "configmake.h"
+
+#define MT_EXIT_SUCCESS 0
+#define MT_EXIT_INVOP 1
+#define MT_EXIT_FAILURE 2
+
+char const * const opnames[] =
+{
+ "eof",
+ "weof",
+ "fsf",
+ "bsf",
+ "fsr",
+ "bsr",
+ "rewind",
+ "offline",
+ "rewoffl",
+ "eject",
+ "status",
+#ifdef MTBSFM
+ "bsfm",
+#endif
+#ifdef MTEOM
+ "eom",
+#endif
+#ifdef MTRETEN
+ "retension",
+#endif
+#ifdef MTERASE
+ "erase",
+#endif
+ "asf",
+#ifdef MTFSFM
+ "fsfm",
+#endif
+#ifdef MTSEEK
+ "seek",
+#endif
+ NULL
+};
+
+#define MTASF 600 /* Random unused number. */
+short operations[] =
+{
+ MTWEOF,
+ MTWEOF,
+ MTFSF,
+ MTBSF,
+ MTFSR,
+ MTBSR,
+ MTREW,
+ MTOFFL,
+ MTOFFL,
+ MTOFFL,
+ MTNOP,
+#ifdef MTBSFM
+ MTBSFM,
+#endif
+#ifdef MTEOM
+ MTEOM,
+#endif
+#ifdef MTRETEN
+ MTRETEN,
+#endif
+#ifdef MTERASE
+ MTERASE,
+#endif
+ MTASF,
+#ifdef MTFSFM
+ MTFSFM,
+#endif
+#ifdef MTSEEK
+ MTSEEK,
+#endif
+};
+
+ARGMATCH_VERIFY (opnames, operations);
+
+const char *argp_program_bug_address = "<" PACKAGE_BUGREPORT ">";
+static char doc[] = N_("control magnetic tape drive operation");
+const char *program_authors[] =
+ {
+ "David MacKenzie",
+ "Sergey Poznyakoff",
+ NULL
+ };
+
+enum
+ {
+ RSH_COMMAND_OPTION = 256
+ };
+
+static struct argp_option options[] = {
+ { "file", 'f', N_("DEVICE"), 0,
+ N_("use device as the file name of the tape drive to operate on") },
+ { "rsh-command", RSH_COMMAND_OPTION, N_("COMMAND"), 0,
+ N_("use remote COMMAND instead of rsh") },
+ { NULL }
+};
+
+char *tapedev; /* tape device */
+char *rsh_command_option = NULL; /* rsh command */
+short operation; /* operation code */
+int count = 1; /* count */
+
+int argcnt = 0; /* number of command line arguments
+ processed so far */
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ switch (key)
+ {
+ case ARGP_KEY_ARG:
+ switch (argcnt++)
+ {
+ case 0:
+ operation = XARGMATCH (N_("operation"), arg, opnames, operations);
+ break;
+
+ case 1:
+ {
+ char *p;
+ long val = strtol (arg, &p, 0);
+ if (*p || (count = val) != count)
+ error (MT_EXIT_INVOP, 0, _("invalid count value"));
+ }
+ break;
+
+ default:
+ argp_usage (state);
+ }
+ break;
+
+ case ARGP_KEY_FINI:
+ if (argcnt == 0)
+ argp_usage (state);
+ if (tapedev == NULL)
+ {
+ tapedev = getenv ("TAPE");
+ if (tapedev == NULL)
+#ifdef DEFTAPE /* From sys/mtio.h. */
+ tapedev = DEFTAPE;
+#else
+ error (MT_EXIT_INVOP, 0, _("no tape device specified"));
+#endif
+ }
+ break;
+
+ case 'f':
+ case 't':
+ tapedev = arg;
+ break;
+
+ case RSH_COMMAND_OPTION:
+ rsh_command_option = arg;
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static struct argp argp = {
+ options,
+ parse_opt,
+ N_("operation [count]"),
+ doc,
+ NULL,
+ NULL,
+ NULL
+};
+
+void
+check_type (char *dev, int desc)
+{
+ struct stat stats;
+
+ if (_isrmt (desc))
+ return;
+ if (fstat (desc, &stats) == -1)
+ stat_error (dev);
+ if ((stats.st_mode & S_IFMT) != S_IFCHR)
+ error (MT_EXIT_INVOP, 0, _("%s is not a character special file"), dev);
+}
+
+void
+perform_operation (char *dev, int desc, short op, int count)
+{
+ struct mtop control;
+
+ control.mt_op = op;
+ control.mt_count = count;
+ if (rmtioctl (desc, MTIOCTOP, (char*)&control) == -1)
+ error (MT_EXIT_FAILURE, errno, _("%s: rmtioctl failed"), dev);
+}
+
+void
+print_status (char *dev, int desc)
+{
+ struct mtget status;
+
+ if (rmtioctl (desc, MTIOCGET, (char*)&status) == -1)
+ error (MT_EXIT_FAILURE, errno, _("%s: rmtioctl failed"), dev);
+
+ printf ("drive type = %d\n", (int) status.mt_type);
+#if defined(hpux) || defined(__hpux)
+ printf ("drive status (high) = %d\n", (int) status.mt_dsreg1);
+ printf ("drive status (low) = %d\n", (int) status.mt_dsreg2);
+#else
+ printf ("drive status = %d\n", (int) status.mt_dsreg);
+#endif
+ printf ("sense key error = %d\n", (int) status.mt_erreg);
+ printf ("residue count = %d\n", (int) status.mt_resid);
+#if !defined(ultrix) && !defined(__ultrix__) && !defined(hpux) && !defined(__hpux) && !defined(__osf__)
+ printf ("file number = %d\n", (int) status.mt_fileno);
+ printf ("block number = %d\n", (int) status.mt_blkno);
+#endif
+}
+
+void
+fatal_exit ()
+{
+ exit (MT_EXIT_INVOP);
+}
+
+int
+main (int argc, char **argv)
+{
+ int tapedesc;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ set_program_name (argv[0]);
+ argp_version_setup ("mt", program_authors);
+ argmatch_die = fatal_exit;
+ argp_err_exit_status = MT_EXIT_INVOP;
+ if (argp_parse (&argp, argc, argv, ARGP_IN_ORDER, NULL, NULL))
+ exit (MT_EXIT_INVOP);
+
+ switch (operation)
+ {
+ case MTWEOF:
+#ifdef MTERASE
+ case MTERASE:
+#endif
+ tapedesc = rmtopen (tapedev, O_WRONLY, 0, rsh_command_option);
+ break;
+
+ default:
+ tapedesc = rmtopen (tapedev, O_RDONLY, 0, rsh_command_option);
+ }
+
+ if (tapedesc == -1)
+ error (MT_EXIT_INVOP, errno, _("%s: rmtopen failed"), tapedev);
+ check_type (tapedev, tapedesc);
+
+ if (operation == MTASF)
+ {
+ perform_operation (tapedev, tapedesc, MTREW, 1);
+ operation = MTFSF;
+ }
+ perform_operation (tapedev, tapedesc, operation, count);
+ if (operation == MTNOP)
+ print_status (tapedev, tapedesc);
+
+ if (rmtclose (tapedesc) == -1)
+ error (MT_EXIT_FAILURE, errno, _("%s: rmtclose failed"), tapedev);
+
+ exit (MT_EXIT_SUCCESS);
+}
+
diff --git a/src/safe-stat.h b/src/safe-stat.h
new file mode 100644
index 0000000..3a37970
--- /dev/null
+++ b/src/safe-stat.h
@@ -0,0 +1 @@
+#define SAFE_STAT(path,pbuf) stat(path,pbuf)
diff --git a/src/tar.c b/src/tar.c
new file mode 100644
index 0000000..04d1e32
--- /dev/null
+++ b/src/tar.c
@@ -0,0 +1,480 @@
+/* tar.c - read in write tar headers for cpio
+ Copyright (C) 1992, 2001, 2004, 2006, 2007, 2010 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 3, 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA. */
+
+#include <system.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "filetypes.h"
+#include "cpiohdr.h"
+#include "dstring.h"
+#include "extern.h"
+#include <rmt.h>
+#include "tarhdr.h"
+
+/* Stash the tar linkname in static storage. */
+
+static char *
+stash_tar_linkname (char *linkname)
+{
+ static char hold_tar_linkname[TARLINKNAMESIZE + 1];
+
+ strncpy (hold_tar_linkname, linkname, TARLINKNAMESIZE);
+ hold_tar_linkname[TARLINKNAMESIZE] = '\0';
+ return hold_tar_linkname;
+}
+
+/* Try to split a long file name into prefix and suffix parts separated
+ by a slash. Return the length of the prefix (not counting the slash). */
+
+static size_t
+split_long_name (const char *name, size_t length)
+{
+ size_t i;
+
+ if (length > TARPREFIXSIZE)
+ length = TARPREFIXSIZE+2;
+ for (i = length - 1; i > 0; i--)
+ if (name[i] == '/')
+ break;
+ return i;
+}
+
+/* Stash the tar filename and optional prefix in static storage. */
+
+static char *
+stash_tar_filename (char *prefix, char *filename)
+{
+ static char hold_tar_filename[TARNAMESIZE + TARPREFIXSIZE + 2];
+ if (prefix == NULL || *prefix == '\0')
+ {
+ strncpy (hold_tar_filename, filename, TARNAMESIZE);
+ hold_tar_filename[TARNAMESIZE] = '\0';
+ }
+ else
+ {
+ strncpy (hold_tar_filename, prefix, TARPREFIXSIZE);
+ hold_tar_filename[TARPREFIXSIZE] = '\0';
+ strcat (hold_tar_filename, "/");
+ strncat (hold_tar_filename, filename, TARNAMESIZE);
+ hold_tar_filename[TARPREFIXSIZE + TARNAMESIZE] = '\0';
+ }
+ return hold_tar_filename;
+}
+
+/* Convert a number into a string of octal digits.
+ Convert long VALUE into a DIGITS-digit field at WHERE,
+ including a trailing space and room for a NUL. DIGITS==3 means
+ 1 digit, a space, and room for a NUL.
+
+ We assume the trailing NUL is already there and don't fill it in.
+ This fact is used by start_header and finish_header, so don't change it!
+
+ This is be equivalent to:
+ sprintf (where, "%*lo ", digits - 2, value);
+ except that sprintf fills in the trailing NUL and we don't. */
+
+static void
+to_oct (register long value, register int digits, register char *where)
+{
+ --digits; /* Leave the trailing NUL slot alone. */
+
+ /* Produce the digits -- at least one. */
+ do
+ {
+ where[--digits] = '0' + (char) (value & 7); /* One octal digit. */
+ value >>= 3;
+ }
+ while (digits > 0 && value != 0);
+
+ /* Add leading zeroes, if necessary. */
+ while (digits > 0)
+ where[--digits] = '0';
+}
+
+
+
+/* Compute and return a checksum for TAR_HDR,
+ counting the checksum bytes as if they were spaces. */
+
+unsigned int
+tar_checksum (struct tar_header *tar_hdr)
+{
+ unsigned int sum = 0;
+ char *p = (char *) tar_hdr;
+ char *q = p + TARRECORDSIZE;
+ int i;
+
+ while (p < tar_hdr->chksum)
+ sum += *p++ & 0xff;
+ for (i = 0; i < 8; ++i)
+ {
+ sum += ' ';
+ ++p;
+ }
+ while (p < q)
+ sum += *p++ & 0xff;
+ return sum;
+}
+
+/* Write out header FILE_HDR, including the file name, to file
+ descriptor OUT_DES. */
+
+void
+write_out_tar_header (struct cpio_file_stat *file_hdr, int out_des)
+{
+ int name_len;
+ union tar_record tar_rec;
+ struct tar_header *tar_hdr = (struct tar_header *) &tar_rec;
+
+ memset (&tar_rec, 0, sizeof tar_rec);
+
+ /* process_copy_out must ensure that file_hdr->c_name is short enough,
+ or we will lose here. */
+
+ name_len = strlen (file_hdr->c_name);
+ if (name_len <= TARNAMESIZE)
+ {
+ strncpy (tar_hdr->name, file_hdr->c_name, name_len);
+ }
+ else
+ {
+ /* Fit as much as we can into `name', the rest into `prefix'. */
+ int prefix_len = split_long_name (file_hdr->c_name, name_len);
+
+ strncpy (tar_hdr->prefix, file_hdr->c_name, prefix_len);
+ strncpy (tar_hdr->name, file_hdr->c_name + prefix_len + 1,
+ name_len - prefix_len - 1);
+ }
+
+ /* Ustar standard (POSIX.1-1988) requires the mode to contain only 3 octal
+ digits */
+ to_oct (file_hdr->c_mode & MODE_ALL, 8, tar_hdr->mode);
+ to_oct (file_hdr->c_uid, 8, tar_hdr->uid);
+ to_oct (file_hdr->c_gid, 8, tar_hdr->gid);
+ to_oct (file_hdr->c_filesize, 12, tar_hdr->size);
+ to_oct (file_hdr->c_mtime, 12, tar_hdr->mtime);
+
+ switch (file_hdr->c_mode & CP_IFMT)
+ {
+ case CP_IFREG:
+ if (file_hdr->c_tar_linkname)
+ {
+ /* process_copy_out makes sure that c_tar_linkname is shorter
+ than TARLINKNAMESIZE. */
+ strncpy (tar_hdr->linkname, file_hdr->c_tar_linkname,
+ TARLINKNAMESIZE);
+ tar_hdr->typeflag = LNKTYPE;
+ to_oct (0, 12, tar_hdr->size);
+ }
+ else
+ tar_hdr->typeflag = REGTYPE;
+ break;
+ case CP_IFDIR:
+ tar_hdr->typeflag = DIRTYPE;
+ break;
+ case CP_IFCHR:
+ tar_hdr->typeflag = CHRTYPE;
+ break;
+ case CP_IFBLK:
+ tar_hdr->typeflag = BLKTYPE;
+ break;
+#ifdef CP_IFIFO
+ case CP_IFIFO:
+ tar_hdr->typeflag = FIFOTYPE;
+ break;
+#endif /* CP_IFIFO */
+#ifdef CP_IFLNK
+ case CP_IFLNK:
+ tar_hdr->typeflag = SYMTYPE;
+ /* process_copy_out makes sure that c_tar_linkname is shorter
+ than TARLINKNAMESIZE. */
+ strncpy (tar_hdr->linkname, file_hdr->c_tar_linkname,
+ TARLINKNAMESIZE);
+ to_oct (0, 12, tar_hdr->size);
+ break;
+#endif /* CP_IFLNK */
+ }
+
+ if (archive_format == arf_ustar)
+ {
+ char *name;
+
+ strncpy (tar_hdr->magic, TMAGIC, TMAGLEN);
+ strncpy (tar_hdr->version, TVERSION, TVERSLEN);
+
+ name = getuser (file_hdr->c_uid);
+ if (name)
+ strcpy (tar_hdr->uname, name);
+ name = getgroup (file_hdr->c_gid);
+ if (name)
+ strcpy (tar_hdr->gname, name);
+
+ to_oct (file_hdr->c_rdev_maj, 8, tar_hdr->devmajor);
+ to_oct (file_hdr->c_rdev_min, 8, tar_hdr->devminor);
+ }
+
+ to_oct (tar_checksum (tar_hdr), 8, tar_hdr->chksum);
+
+ tape_buffered_write ((char *) &tar_rec, out_des, TARRECORDSIZE);
+}
+
+/* Return nonzero iff all the bytes in BLOCK are NUL.
+ SIZE is the number of bytes to check in BLOCK; it must be a
+ multiple of sizeof (long). */
+
+int
+null_block (long *block, int size)
+{
+ register long *p = block;
+ register int i = size / sizeof (long);
+
+ while (i--)
+ if (*p++)
+ return 0;
+ return 1;
+}
+
+/* Read a tar header, including the file name, from file descriptor IN_DES
+ into FILE_HDR. */
+
+void
+read_in_tar_header (struct cpio_file_stat *file_hdr, int in_des)
+{
+ long bytes_skipped = 0;
+ int warned = false;
+ union tar_record tar_rec;
+ struct tar_header *tar_hdr = (struct tar_header *) &tar_rec;
+ uid_t *uidp;
+ gid_t *gidp;
+
+ tape_buffered_read ((char *) &tar_rec, in_des, TARRECORDSIZE);
+
+ /* Check for a block of 0's. */
+ if (null_block ((long *) &tar_rec, TARRECORDSIZE))
+ {
+#if 0
+ /* Found one block of 512 0's. If the next block is also all 0's
+ then this is the end of the archive. If not, assume the
+ previous block was all corruption and continue reading
+ the archive. */
+ /* Commented out because GNU tar sometimes creates archives with
+ only one block of 0's at the end. This happened for the
+ cpio 2.0 distribution! */
+ tape_buffered_read ((char *) &tar_rec, in_des, TARRECORDSIZE);
+ if (null_block ((long *) &tar_rec, TARRECORDSIZE))
+#endif
+ {
+ file_hdr->c_name = CPIO_TRAILER_NAME;
+ return;
+ }
+#if 0
+ bytes_skipped = TARRECORDSIZE;
+#endif
+ }
+
+ while (1)
+ {
+ file_hdr->c_chksum = FROM_OCTAL (tar_hdr->chksum);
+
+ if (file_hdr->c_chksum != tar_checksum (tar_hdr))
+ {
+ /* If the checksum is bad, skip 1 byte and try again. When
+ we try again we do not look for an EOF record (all zeros),
+ because when we start skipping bytes in a corrupted archive
+ the chances are pretty good that we might stumble across
+ 2 blocks of 512 zeros (that probably is not really the last
+ record) and it is better to miss the EOF and give the user
+ a "premature EOF" error than to give up too soon on a corrupted
+ archive. */
+ if (!warned)
+ {
+ error (0, 0, _("invalid header: checksum error"));
+ warned = true;
+ }
+ memmove (&tar_rec, ((char *) &tar_rec) + 1, TARRECORDSIZE - 1);
+ tape_buffered_read (((char *) &tar_rec) + (TARRECORDSIZE - 1), in_des, 1);
+ ++bytes_skipped;
+ continue;
+ }
+
+ if (archive_format != arf_ustar)
+ file_hdr->c_name = stash_tar_filename (NULL, tar_hdr->name);
+ else
+ file_hdr->c_name = stash_tar_filename (tar_hdr->prefix, tar_hdr->name);
+ file_hdr->c_nlink = 1;
+ file_hdr->c_mode = FROM_OCTAL (tar_hdr->mode);
+ file_hdr->c_mode = file_hdr->c_mode & 07777;
+ /* Debian hack: This version of cpio uses the -n flag also to extract
+ tar archives using the numeric UID/GID instead of the user/group
+ names in /etc/passwd and /etc/groups. (98/10/15) -BEM */
+ if (archive_format == arf_ustar && !numeric_uid
+ && (uidp = getuidbyname (tar_hdr->uname)))
+ file_hdr->c_uid = *uidp;
+ else
+ file_hdr->c_uid = FROM_OCTAL (tar_hdr->uid);
+
+ if (archive_format == arf_ustar && !numeric_uid
+ && (gidp = getgidbyname (tar_hdr->gname)))
+ file_hdr->c_gid = *gidp;
+ else
+ file_hdr->c_gid = FROM_OCTAL (tar_hdr->gid);
+ file_hdr->c_filesize = FROM_OCTAL (tar_hdr->size);
+ file_hdr->c_mtime = FROM_OCTAL (tar_hdr->mtime);
+ file_hdr->c_rdev_maj = FROM_OCTAL (tar_hdr->devmajor);
+ file_hdr->c_rdev_min = FROM_OCTAL (tar_hdr->devminor);
+ file_hdr->c_tar_linkname = NULL;
+
+ switch (tar_hdr->typeflag)
+ {
+ case REGTYPE:
+ case CONTTYPE: /* For now, punt. */
+ default:
+ file_hdr->c_mode |= CP_IFREG;
+ break;
+ case DIRTYPE:
+ file_hdr->c_mode |= CP_IFDIR;
+ break;
+ case CHRTYPE:
+ file_hdr->c_mode |= CP_IFCHR;
+ /* If a POSIX tar header has a valid linkname it's always supposed
+ to set typeflag to be LNKTYPE. System V.4 tar seems to
+ be broken, and for device files with multiple links it
+ puts the name of the link into linkname, but leaves typeflag
+ as CHRTYPE, BLKTYPE, FIFOTYPE, etc. */
+ file_hdr->c_tar_linkname = stash_tar_linkname (tar_hdr->linkname);
+
+ /* Does POSIX say that the filesize must be 0 for devices? We
+ assume so, but HPUX's POSIX tar sets it to be 1 which causes
+ us problems (when reading an archive we assume we can always
+ skip to the next file by skipping filesize bytes). For
+ now at least, it's easier to clear filesize for devices,
+ rather than check everywhere we skip in copyin.c. */
+ file_hdr->c_filesize = 0;
+ break;
+ case BLKTYPE:
+ file_hdr->c_mode |= CP_IFBLK;
+ file_hdr->c_tar_linkname = stash_tar_linkname (tar_hdr->linkname);
+ file_hdr->c_filesize = 0;
+ break;
+#ifdef CP_IFIFO
+ case FIFOTYPE:
+ file_hdr->c_mode |= CP_IFIFO;
+ file_hdr->c_tar_linkname = stash_tar_linkname (tar_hdr->linkname);
+ file_hdr->c_filesize = 0;
+ break;
+#endif
+ case SYMTYPE:
+#ifdef CP_IFLNK
+ file_hdr->c_mode |= CP_IFLNK;
+ file_hdr->c_tar_linkname = stash_tar_linkname (tar_hdr->linkname);
+ file_hdr->c_filesize = 0;
+ break;
+ /* Else fall through. */
+#endif
+ case LNKTYPE:
+ file_hdr->c_mode |= CP_IFREG;
+ file_hdr->c_tar_linkname = stash_tar_linkname (tar_hdr->linkname);
+ file_hdr->c_filesize = 0;
+ break;
+
+ case AREGTYPE:
+ /* Old tar format; if the last char in filename is '/' then it is
+ a directory, otherwise it's a regular file. */
+ if (file_hdr->c_name[strlen (file_hdr->c_name) - 1] == '/')
+ file_hdr->c_mode |= CP_IFDIR;
+ else
+ file_hdr->c_mode |= CP_IFREG;
+ break;
+ }
+ break;
+ }
+ if (bytes_skipped > 0)
+ warn_junk_bytes (bytes_skipped);
+}
+
+/* Return
+ 2 if BUF is a valid POSIX tar header (the checksum is correct
+ and it has the "ustar" magic string),
+ 1 if BUF is a valid old tar header (the checksum is correct),
+ 0 otherwise. */
+
+int
+is_tar_header (char *buf)
+{
+ struct tar_header *tar_hdr = (struct tar_header *) buf;
+ unsigned long chksum;
+
+ chksum = FROM_OCTAL (tar_hdr->chksum);
+
+ if (chksum != tar_checksum (tar_hdr))
+ return 0;
+
+ /* GNU tar 1.10 and previous set the magic field to be "ustar " instead
+ of "ustar\0". Only look at the first 5 characters of the magic
+ field so we can recognize old GNU tar ustar archives. */
+ if (!strncmp (tar_hdr->magic, TMAGIC, TMAGLEN - 1))
+ return 2;
+ return 1;
+}
+
+/* Return true if the filename is too long to fit in a tar header.
+ For old tar headers, if the filename's length is less than or equal
+ to 100 then it will fit, otherwise it will not. For POSIX tar headers,
+ if the filename's length is less than or equal to 100 then it
+ will definitely fit, and if it is greater than 256 then it
+ will definitely not fit. If the length is between 100 and 256,
+ then the filename will fit only if it is possible to break it
+ into a 155 character "prefix" and 100 character "name". There
+ must be a slash between the "prefix" and the "name", although
+ the slash is not stored or counted in either the "prefix" or
+ the "name", and there must be at least one character in both
+ the "prefix" and the "name". If it is not possible to break down
+ the filename like this then it will not fit. */
+
+int
+is_tar_filename_too_long (char *name)
+{
+ int whole_name_len;
+ int prefix_name_len;
+
+ whole_name_len = strlen (name);
+ if (whole_name_len <= TARNAMESIZE)
+ return false;
+
+ if (archive_format != arf_ustar)
+ return true;
+
+ if (whole_name_len > TARNAMESIZE + TARPREFIXSIZE + 1)
+ return true;
+
+ /* See whether we can split up the name into acceptably-sized
+ `prefix' and `name' (`p') pieces. */
+ prefix_name_len = split_long_name (name, whole_name_len);
+
+ /* Interestingly, a name consisting of a slash followed by
+ TARNAMESIZE characters can't be stored, because the prefix
+ would be empty, and thus ignored. */
+ if (prefix_name_len == 0
+ || whole_name_len - prefix_name_len - 1 > TARNAMESIZE)
+ return true;
+
+ return false;
+}
diff --git a/src/tar.h b/src/tar.h
new file mode 100644
index 0000000..0047d6c
--- /dev/null
+++ b/src/tar.h
@@ -0,0 +1,112 @@
+/* Extended tar format from POSIX.1.
+ Copyright (C) 1992, 2007, 2010 Free Software Foundation, Inc.
+ Written by David J. MacKenzie.
+
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 3 of the
+License, or (at your option) any later version.
+
+The GNU C Library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General
+Public License along with this library; see the file COPYING.LIB.
+If not, write to the Free Software Foundation, Inc., 51 Franklin
+Street, Fifth Floor, Boston, MA 02110-1301 USA. */
+
+#ifndef _TAR_H
+
+#define _TAR_H 1
+
+
+/* A tar archive consists of 512-byte blocks.
+ Each file in the archive has a header block followed by 0+ data blocks.
+ Two blocks of NUL bytes indicate the end of the archive. */
+
+/* The fields of header blocks:
+ All strings are stored as ISO 646 (approximately ASCII) strings.
+
+ Fields are numeric unless otherwise noted below; numbers are ISO 646
+ representations of octal numbers, with leading zeros as needed.
+
+ linkname is only valid when typeflag==LNKTYPE. It doesn't use prefix;
+ files that are links to pathnames >100 chars long can not be stored
+ in a tar archive.
+
+ If typeflag=={LNKTYPE,SYMTYPE,DIRTYPE} then size must be 0.
+
+ devmajor and devminor are only valid for typeflag=={BLKTYPE,CHRTYPE}.
+
+ chksum contains the sum of all 512 bytes in the header block,
+ treating each byte as an 8-bit unsigned value and treating the
+ 8 bytes of chksum as blank characters.
+
+ uname and gname are used in preference to uid and gid, if those
+ names exist locally.
+
+ Field Name Byte Offset Length in Bytes Field Type
+ name 0 100 NUL-terminated if NUL fits
+ mode 100 8
+ uid 108 8
+ gid 116 8
+ size 124 12
+ mtime 136 12
+ chksum 148 8
+ typeflag 156 1 see below
+ linkname 157 100 NUL-terminated if NUL fits
+ magic 257 6 must be TMAGIC (NUL term.)
+ version 263 2 must be TVERSION
+ uname 265 32 NUL-terminated
+ gname 297 32 NUL-terminated
+ devmajor 329 8
+ devminor 337 8
+ prefix 345 155 NUL-terminated if NUL fits
+
+ If the first character of prefix is '\0', the file name is name;
+ otherwise, it is prefix/name. Files whose pathnames don't fit in that
+ length can not be stored in a tar archive. */
+
+/* The bits in mode: */
+#define TSUID 04000
+#define TSGID 02000
+#define TSVTX 01000
+#define TUREAD 00400
+#define TUWRITE 00200
+#define TUEXEC 00100
+#define TGREAD 00040
+#define TGWRITE 00020
+#define TGEXEC 00010
+#define TOREAD 00004
+#define TOWRITE 00002
+#define TOEXEC 00001
+
+/* The values for typeflag:
+ Values 'A'-'Z' are reserved for custom implementations.
+ All other values are reserved for future POSIX.1 revisions. */
+
+#define REGTYPE '0' /* Regular file (preferred code). */
+#define AREGTYPE '\0' /* Regular file (alternate code). */
+#define LNKTYPE '1' /* Hard link. */
+#define SYMTYPE '2' /* Symbolic link (hard if not supported). */
+#define CHRTYPE '3' /* Character special. */
+#define BLKTYPE '4' /* Block special. */
+#define DIRTYPE '5' /* Directory. */
+#define FIFOTYPE '6' /* Named pipe. */
+#define CONTTYPE '7' /* Contiguous file */
+ /* (regular file if not supported). */
+
+/* Contents of magic field and its length. */
+#define TMAGIC "ustar"
+#define TMAGLEN 6
+
+/* Contents of the version field and its length. */
+#define TVERSION "00"
+#define TVERSLEN 2
+
+
+#endif /* tar.h */
diff --git a/src/tarhdr.h b/src/tarhdr.h
new file mode 100644
index 0000000..59d0060
--- /dev/null
+++ b/src/tarhdr.h
@@ -0,0 +1,63 @@
+/* Extended tar header from POSIX.1.
+ Copyright (C) 1992, 2007, 2010 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 3, 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA. */
+
+#ifndef _TARHDR_H
+
+#define _TARHDR_H 1
+
+#include <tar.h>
+
+/* Size of `name' field. */
+#define TARNAMESIZE 100
+
+/* Size of `linkname' field. */
+#define TARLINKNAMESIZE 100
+
+/* Size of `prefix' field. */
+#define TARPREFIXSIZE 155
+
+/* Size of entire tar header. */
+#define TARRECORDSIZE 512
+
+struct tar_header
+{
+ char name[TARNAMESIZE];
+ char mode[8];
+ char uid[8];
+ char gid[8];
+ char size[12];
+ char mtime[12];
+ char chksum[8];
+ char typeflag;
+ char linkname[TARLINKNAMESIZE];
+ char magic[6];
+ char version[2];
+ char uname[32];
+ char gname[32];
+ char devmajor[8];
+ char devminor[8];
+ char prefix[TARPREFIXSIZE];
+};
+
+union tar_record
+{
+ struct tar_header header;
+ char buffer[TARRECORDSIZE];
+};
+
+#endif /* tarhdr.h */
diff --git a/src/userspec.c b/src/userspec.c
new file mode 100644
index 0000000..8cffd65
--- /dev/null
+++ b/src/userspec.c
@@ -0,0 +1,233 @@
+/* userspec.c -- Parse a user and group string.
+ Copyright (C) 1989, 1990, 1991, 1992, 2001, 2004, 2005, 2007, 2010
+ 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 3, 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA. */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
+
+#include <system.h>
+#include <alloca.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+
+#ifndef HAVE_ENDPWENT
+# define endpwent()
+#endif
+#ifndef HAVE_ENDGRENT
+# define endgrent()
+#endif
+
+/* Perform the equivalent of the statement `dest = strdup (src);',
+ but obtaining storage via alloca instead of from the heap. */
+
+#define V_STRDUP(dest, src) \
+ do \
+ { \
+ int _len = strlen ((src)); \
+ (dest) = (char *) alloca (_len + 1); \
+ strcpy (dest, src); \
+ } \
+ while (0)
+
+/* Return nonzero if STR represents an unsigned decimal integer,
+ otherwise return 0. */
+
+static int
+isnumber_p (const char *str)
+{
+ for (; *str; str++)
+ if (!isdigit (*str))
+ return 0;
+ return 1;
+}
+
+/* Extract from NAME, which has the form "[user][:.][group]",
+ a USERNAME, UID U, GROUPNAME, and GID G.
+ Either user or group, or both, must be present.
+ If the group is omitted but the ":" or "." separator is given,
+ use the given user's login group.
+
+ USERNAME and GROUPNAME will be in newly malloc'd memory.
+ Either one might be NULL instead, indicating that it was not
+ given and the corresponding numeric ID was left unchanged.
+
+ Return NULL if successful, a static error message string if not. */
+
+const char *
+parse_user_spec (const char *spec_arg, uid_t *uid, gid_t *gid,
+ char **username_arg, char **groupname_arg)
+{
+ static const char *tired = "virtual memory exhausted";
+ const char *error_msg;
+ char *spec; /* A copy we can write on. */
+ struct passwd *pwd;
+ struct group *grp;
+ char *g, *u, *separator;
+ char *groupname;
+
+ error_msg = NULL;
+ *username_arg = *groupname_arg = NULL;
+ groupname = NULL;
+
+ V_STRDUP (spec, spec_arg);
+
+ /* Find the separator if there is one. */
+ separator = strchr (spec, ':');
+ if (separator == NULL)
+ separator = strchr (spec, '.');
+
+ /* Replace separator with a NUL. */
+ if (separator != NULL)
+ *separator = '\0';
+
+ /* Set U and G to non-zero length strings corresponding to user and
+ group specifiers or to NULL. */
+ u = (*spec == '\0' ? NULL : spec);
+
+ g = (separator == NULL || *(separator + 1) == '\0'
+ ? NULL
+ : separator + 1);
+
+ if (u == NULL && g == NULL)
+ return "can not omit both user and group";
+
+ if (u != NULL)
+ {
+ pwd = getpwnam (u);
+ if (pwd == NULL)
+ {
+
+ if (!isnumber_p (u))
+ error_msg = _("invalid user");
+ else
+ {
+ int use_login_group;
+ use_login_group = (separator != NULL && g == NULL);
+ if (use_login_group)
+ error_msg = _("cannot get the login group of a numeric UID");
+ else
+ *uid = atoi (u);
+ }
+ }
+ else
+ {
+ *uid = pwd->pw_uid;
+ if (g == NULL && separator != NULL)
+ {
+ /* A separator was given, but a group was not specified,
+ so get the login group. */
+ *gid = pwd->pw_gid;
+ grp = getgrgid (pwd->pw_gid);
+ if (grp == NULL)
+ {
+ /* This is enough room to hold the unsigned decimal
+ representation of any 32-bit quantity and the trailing
+ zero byte. */
+ char uint_buf[21];
+ sprintf (uint_buf, "%u", (unsigned) (pwd->pw_gid));
+ V_STRDUP (groupname, uint_buf);
+ }
+ else
+ {
+ V_STRDUP (groupname, grp->gr_name);
+ }
+ endgrent ();
+ }
+ }
+ endpwent ();
+ }
+
+ if (g != NULL && error_msg == NULL)
+ {
+ /* Explicit group. */
+ grp = getgrnam (g);
+ if (grp == NULL)
+ {
+ if (!isnumber_p (g))
+ error_msg = _("invalid group");
+ else
+ *gid = atoi (g);
+ }
+ else
+ *gid = grp->gr_gid;
+ endgrent (); /* Save a file descriptor. */
+
+ if (error_msg == NULL)
+ V_STRDUP (groupname, g);
+ }
+
+ if (error_msg == NULL)
+ {
+ if (u != NULL)
+ {
+ *username_arg = strdup (u);
+ if (*username_arg == NULL)
+ error_msg = tired;
+ }
+
+ if (groupname != NULL && error_msg == NULL)
+ {
+ *groupname_arg = strdup (groupname);
+ if (*groupname_arg == NULL)
+ {
+ if (*username_arg != NULL)
+ {
+ free (*username_arg);
+ *username_arg = NULL;
+ }
+ error_msg = tired;
+ }
+ }
+ }
+
+ return error_msg;
+}
+
+#ifdef TEST
+
+#define NULL_CHECK(s) ((s) == NULL ? "(null)" : (s))
+
+int
+main (int argc, char **argv)
+{
+ int i;
+
+ for (i = 1; i < argc; i++)
+ {
+ const char *e;
+ char *username, *groupname;
+ uid_t uid;
+ gid_t gid;
+ char *tmp;
+
+ tmp = strdup (argv[i]);
+ e = parse_user_spec (tmp, &uid, &gid, &username, &groupname);
+ free (tmp);
+ printf ("%s: %u %u %s %s %s\n",
+ argv[i],
+ (unsigned int) uid,
+ (unsigned int) gid,
+ NULL_CHECK (username),
+ NULL_CHECK (groupname),
+ NULL_CHECK (e));
+ }
+
+ exit (0);
+}
+
+#endif
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..00953d5
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,1620 @@
+/* util.c - Several utility routines for cpio.
+ Copyright (C) 1990, 1991, 1992, 2001, 2004, 2006, 2007, 2010 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 3, 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA. */
+
+#include <system.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "cpiohdr.h"
+#include "dstring.h"
+#include "extern.h"
+#include <paxlib.h>
+#include "filetypes.h"
+#include <safe-read.h>
+#include <full-write.h>
+#include <rmt.h>
+#include <hash.h>
+#include <utimens.h>
+
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_MTIO_H
+# ifdef HAVE_SYS_IO_TRIOCTL_H
+# include <sys/io/trioctl.h>
+# endif
+# include <sys/mtio.h>
+#endif
+
+#if !HAVE_DECL_ERRNO
+extern int errno;
+#endif
+
+/* Write `output_size' bytes of `output_buffer' to file
+ descriptor OUT_DES and reset `output_size' and `out_buff'. */
+
+void
+tape_empty_output_buffer (int out_des)
+{
+ int bytes_written;
+
+#ifdef BROKEN_LONG_TAPE_DRIVER
+ static long output_bytes_before_lseek = 0;
+
+ /* Some tape drivers seem to have a signed internal seek pointer and
+ they lose if it overflows and becomes negative (e.g. when writing
+ tapes > 2Gb). Doing an lseek (des, 0, SEEK_SET) seems to reset the
+ seek pointer and prevent it from overflowing. */
+ if (output_is_special
+ && ( (output_bytes_before_lseek += output_size) >= 1073741824L) )
+ {
+ lseek(out_des, 0L, SEEK_SET);
+ output_bytes_before_lseek = 0;
+ }
+#endif
+
+ bytes_written = rmtwrite (out_des, output_buffer, output_size);
+ if (bytes_written != output_size)
+ {
+ int rest_bytes_written;
+ int rest_output_size;
+
+ if (output_is_special
+ && (bytes_written >= 0
+ || (bytes_written < 0
+ && (errno == ENOSPC || errno == EIO || errno == ENXIO))))
+ {
+ get_next_reel (out_des);
+ if (bytes_written > 0)
+ rest_output_size = output_size - bytes_written;
+ else
+ rest_output_size = output_size;
+ rest_bytes_written = rmtwrite (out_des, output_buffer,
+ rest_output_size);
+ if (rest_bytes_written != rest_output_size)
+ error (1, errno, _("write error"));
+ }
+ else
+ error (1, errno, _("write error"));
+ }
+ output_bytes += output_size;
+ out_buff = output_buffer;
+ output_size = 0;
+}
+
+static int sparse_write (int fildes, char *buf, unsigned int nbyte);
+
+/* Write `output_size' bytes of `output_buffer' to file
+ descriptor OUT_DES and reset `output_size' and `out_buff'.
+ If `swapping_halfwords' or `swapping_bytes' is set,
+ do the appropriate swapping first. Our callers have
+ to make sure to only set these flags if `output_size'
+ is appropriate (a multiple of 4 for `swapping_halfwords',
+ 2 for `swapping_bytes'). The fact that DISK_IO_BLOCK_SIZE
+ must always be a multiple of 4 helps us (and our callers)
+ insure this. */
+
+void
+disk_empty_output_buffer (int out_des)
+{
+ int bytes_written;
+
+ if (swapping_halfwords || swapping_bytes)
+ {
+ if (swapping_halfwords)
+ {
+ int complete_words;
+ complete_words = output_size / 4;
+ swahw_array (output_buffer, complete_words);
+ if (swapping_bytes)
+ swab_array (output_buffer, 2 * complete_words);
+ }
+ else
+ {
+ int complete_halfwords;
+ complete_halfwords = output_size /2;
+ swab_array (output_buffer, complete_halfwords);
+ }
+ }
+
+ if (sparse_flag)
+ bytes_written = sparse_write (out_des, output_buffer, output_size);
+ else
+ bytes_written = write (out_des, output_buffer, output_size);
+
+ if (bytes_written != output_size)
+ {
+ error (1, errno, _("write error"));
+ }
+ output_bytes += output_size;
+ out_buff = output_buffer;
+ output_size = 0;
+}
+
+/* Exchange the halfwords of each element of the array of COUNT longs
+ starting at PTR. PTR does not have to be aligned at a word
+ boundary. */
+
+void
+swahw_array (char *ptr, int count)
+{
+ char tmp;
+
+ for (; count > 0; --count)
+ {
+ tmp = *ptr;
+ *ptr = *(ptr + 2);
+ *(ptr + 2) = tmp;
+ ++ptr;
+ tmp = *ptr;
+ *ptr = *(ptr + 2);
+ *(ptr + 2) = tmp;
+ ptr += 3;
+ }
+}
+
+/* Read at most NUM_BYTES or `io_block_size' bytes, whichever is smaller,
+ into the start of `input_buffer' from file descriptor IN_DES.
+ Set `input_size' to the number of bytes read and reset `in_buff'.
+ Exit with an error if end of file is reached. */
+
+#ifdef BROKEN_LONG_TAPE_DRIVER
+static long input_bytes_before_lseek = 0;
+#endif
+
+static void
+tape_fill_input_buffer (int in_des, int num_bytes)
+{
+#ifdef BROKEN_LONG_TAPE_DRIVER
+ /* Some tape drivers seem to have a signed internal seek pointer and
+ they lose if it overflows and becomes negative (e.g. when writing
+ tapes > 4Gb). Doing an lseek (des, 0, SEEK_SET) seems to reset the
+ seek pointer and prevent it from overflowing. */
+ if (input_is_special
+ && ( (input_bytes_before_lseek += num_bytes) >= 1073741824L) )
+ {
+ lseek(in_des, 0L, SEEK_SET);
+ input_bytes_before_lseek = 0;
+ }
+#endif
+ in_buff = input_buffer;
+ num_bytes = (num_bytes < io_block_size) ? num_bytes : io_block_size;
+ input_size = rmtread (in_des, input_buffer, num_bytes);
+ if (input_size == 0 && input_is_special)
+ {
+ get_next_reel (in_des);
+ input_size = rmtread (in_des, input_buffer, num_bytes);
+ }
+ if (input_size < 0)
+ error (1, errno, _("read error"));
+ if (input_size == 0)
+ {
+ error (0, 0, _("premature end of file"));
+ exit (1);
+ }
+ input_bytes += input_size;
+}
+
+/* Read at most NUM_BYTES or `DISK_IO_BLOCK_SIZE' bytes, whichever is smaller,
+ into the start of `input_buffer' from file descriptor IN_DES.
+ Set `input_size' to the number of bytes read and reset `in_buff'.
+ Exit with an error if end of file is reached. */
+
+static int
+disk_fill_input_buffer (int in_des, off_t num_bytes)
+{
+ in_buff = input_buffer;
+ num_bytes = (num_bytes < DISK_IO_BLOCK_SIZE) ? num_bytes : DISK_IO_BLOCK_SIZE;
+ input_size = read (in_des, input_buffer, num_bytes);
+ if (input_size < 0)
+ {
+ input_size = 0;
+ return (-1);
+ }
+ else if (input_size == 0)
+ return (1);
+ input_bytes += input_size;
+ return (0);
+}
+
+/* Copy NUM_BYTES of buffer IN_BUF to `out_buff', which may be partly full.
+ When `out_buff' fills up, flush it to file descriptor OUT_DES. */
+
+void
+tape_buffered_write (char *in_buf, int out_des, off_t num_bytes)
+{
+ off_t bytes_left = num_bytes; /* Bytes needing to be copied. */
+ off_t space_left; /* Room left in output buffer. */
+
+ while (bytes_left > 0)
+ {
+ space_left = io_block_size - output_size;
+ if (space_left == 0)
+ tape_empty_output_buffer (out_des);
+ else
+ {
+ if (bytes_left < space_left)
+ space_left = bytes_left;
+ memcpy (out_buff, in_buf, (unsigned) space_left);
+ out_buff += space_left;
+ output_size += space_left;
+ in_buf += space_left;
+ bytes_left -= space_left;
+ }
+ }
+}
+
+/* Copy NUM_BYTES of buffer IN_BUF to `out_buff', which may be partly full.
+ When `out_buff' fills up, flush it to file descriptor OUT_DES. */
+
+void
+disk_buffered_write (char *in_buf, int out_des, off_t num_bytes)
+{
+ off_t bytes_left = num_bytes; /* Bytes needing to be copied. */
+ off_t space_left; /* Room left in output buffer. */
+
+ while (bytes_left > 0)
+ {
+ space_left = DISK_IO_BLOCK_SIZE - output_size;
+ if (space_left == 0)
+ disk_empty_output_buffer (out_des);
+ else
+ {
+ if (bytes_left < space_left)
+ space_left = bytes_left;
+ memcpy (out_buff, in_buf, (unsigned) space_left);
+ out_buff += space_left;
+ output_size += space_left;
+ in_buf += space_left;
+ bytes_left -= space_left;
+ }
+ }
+}
+
+/* Copy NUM_BYTES of buffer `in_buff' into IN_BUF.
+ `in_buff' may be partly full.
+ When `in_buff' is exhausted, refill it from file descriptor IN_DES. */
+
+void
+tape_buffered_read (char *in_buf, int in_des, off_t num_bytes)
+{
+ off_t bytes_left = num_bytes; /* Bytes needing to be copied. */
+ off_t space_left; /* Bytes to copy from input buffer. */
+
+ while (bytes_left > 0)
+ {
+ if (input_size == 0)
+ tape_fill_input_buffer (in_des, io_block_size);
+ if (bytes_left < input_size)
+ space_left = bytes_left;
+ else
+ space_left = input_size;
+ memcpy (in_buf, in_buff, (unsigned) space_left);
+ in_buff += space_left;
+ in_buf += space_left;
+ input_size -= space_left;
+ bytes_left -= space_left;
+ }
+}
+
+/* Copy the the next NUM_BYTES bytes of `input_buffer' into PEEK_BUF.
+ If NUM_BYTES bytes are not available, read the next `io_block_size' bytes
+ into the end of `input_buffer' and update `input_size'.
+
+ Return the number of bytes copied into PEEK_BUF.
+ If the number of bytes returned is less than NUM_BYTES,
+ then EOF has been reached. */
+
+int
+tape_buffered_peek (char *peek_buf, int in_des, int num_bytes)
+{
+ long tmp_input_size;
+ long got_bytes;
+ char *append_buf;
+
+#ifdef BROKEN_LONG_TAPE_DRIVER
+ /* Some tape drivers seem to have a signed internal seek pointer and
+ they lose if it overflows and becomes negative (e.g. when writing
+ tapes > 4Gb). Doing an lseek (des, 0, SEEK_SET) seems to reset the
+ seek pointer and prevent it from overflowing. */
+ if (input_is_special
+ && ( (input_bytes_before_lseek += num_bytes) >= 1073741824L) )
+ {
+ lseek(in_des, 0L, SEEK_SET);
+ input_bytes_before_lseek = 0;
+ }
+#endif
+
+ while (input_size < num_bytes)
+ {
+ append_buf = in_buff + input_size;
+ if ( (append_buf - input_buffer) >= input_buffer_size)
+ {
+ /* We can keep up to 2 "blocks" (either the physical block size
+ or 512 bytes(the size of a tar record), which ever is
+ larger) in the input buffer when we are peeking. We
+ assume that our caller will never be interested in peeking
+ ahead at more than 512 bytes, so we know that by the time
+ we need a 3rd "block" in the buffer we can throw away the
+ first block to make room. */
+ int half;
+ half = input_buffer_size / 2;
+ memmove (input_buffer, input_buffer + half, half);
+ in_buff = in_buff - half;
+ append_buf = append_buf - half;
+ }
+ tmp_input_size = rmtread (in_des, append_buf, io_block_size);
+ if (tmp_input_size == 0)
+ {
+ if (input_is_special)
+ {
+ get_next_reel (in_des);
+ tmp_input_size = rmtread (in_des, append_buf, io_block_size);
+ }
+ else
+ break;
+ }
+ if (tmp_input_size < 0)
+ error (1, errno, _("read error"));
+ input_bytes += tmp_input_size;
+ input_size += tmp_input_size;
+ }
+ if (num_bytes <= input_size)
+ got_bytes = num_bytes;
+ else
+ got_bytes = input_size;
+ memcpy (peek_buf, in_buff, (unsigned) got_bytes);
+ return got_bytes;
+}
+
+/* Skip the next NUM_BYTES bytes of file descriptor IN_DES. */
+
+void
+tape_toss_input (int in_des, off_t num_bytes)
+{
+ off_t bytes_left = num_bytes; /* Bytes needing to be copied. */
+ off_t space_left; /* Bytes to copy from input buffer. */
+
+ while (bytes_left > 0)
+ {
+ if (input_size == 0)
+ tape_fill_input_buffer (in_des, io_block_size);
+ if (bytes_left < input_size)
+ space_left = bytes_left;
+ else
+ space_left = input_size;
+
+ if (crc_i_flag && only_verify_crc_flag)
+ {
+ int k;
+ for (k = 0; k < space_left; ++k)
+ crc += in_buff[k] & 0xff;
+ }
+
+ in_buff += space_left;
+ input_size -= space_left;
+ bytes_left -= space_left;
+ }
+}
+
+void
+write_nuls_to_file (off_t num_bytes, int out_des,
+ void (*writer) (char *in_buf, int out_des, off_t num_bytes))
+{
+ off_t blocks;
+ off_t extra_bytes;
+ off_t i;
+ static char zeros_512[512];
+
+ blocks = num_bytes / sizeof zeros_512;
+ extra_bytes = num_bytes % sizeof zeros_512;
+ for (i = 0; i < blocks; ++i)
+ writer (zeros_512, out_des, sizeof zeros_512);
+ if (extra_bytes)
+ writer (zeros_512, out_des, extra_bytes);
+}
+
+/* Copy a file using the input and output buffers, which may start out
+ partly full. After the copy, the files are not closed nor the last
+ block flushed to output, and the input buffer may still be partly
+ full. If `crc_i_flag' is set, add each byte to `crc'.
+ IN_DES is the file descriptor for input;
+ OUT_DES is the file descriptor for output;
+ NUM_BYTES is the number of bytes to copy. */
+
+void
+copy_files_tape_to_disk (int in_des, int out_des, off_t num_bytes)
+{
+ off_t size;
+ off_t k;
+
+ while (num_bytes > 0)
+ {
+ if (input_size == 0)
+ tape_fill_input_buffer (in_des, io_block_size);
+ size = (input_size < num_bytes) ? input_size : num_bytes;
+ if (crc_i_flag)
+ {
+ for (k = 0; k < size; ++k)
+ crc += in_buff[k] & 0xff;
+ }
+ disk_buffered_write (in_buff, out_des, size);
+ num_bytes -= size;
+ input_size -= size;
+ in_buff += size;
+ }
+}
+/* Copy a file using the input and output buffers, which may start out
+ partly full. After the copy, the files are not closed nor the last
+ block flushed to output, and the input buffer may still be partly
+ full. If `crc_i_flag' is set, add each byte to `crc'.
+ IN_DES is the file descriptor for input;
+ OUT_DES is the file descriptor for output;
+ NUM_BYTES is the number of bytes to copy. */
+
+void
+copy_files_disk_to_tape (int in_des, int out_des, off_t num_bytes,
+ char *filename)
+{
+ off_t size;
+ off_t k;
+ int rc;
+ off_t original_num_bytes;
+
+ original_num_bytes = num_bytes;
+
+ while (num_bytes > 0)
+ {
+ if (input_size == 0)
+ if (rc = disk_fill_input_buffer (in_des,
+ num_bytes < DISK_IO_BLOCK_SIZE ?
+ num_bytes : DISK_IO_BLOCK_SIZE))
+ {
+ if (rc > 0)
+ {
+ char buf[UINTMAX_STRSIZE_BOUND];
+ error (0, 0,
+ ngettext ("File %s shrunk by %s byte, padding with zeros",
+ "File %s shrunk by %s bytes, padding with zeros",
+ num_bytes),
+ filename, STRINGIFY_BIGINT (num_bytes, buf));
+ }
+ else
+ error (0, 0, _("Read error at byte %lld in file %s, padding with zeros"),
+ original_num_bytes - num_bytes, filename);
+ write_nuls_to_file (num_bytes, out_des, tape_buffered_write);
+ break;
+ }
+ size = (input_size < num_bytes) ? input_size : num_bytes;
+ if (crc_i_flag)
+ {
+ for (k = 0; k < size; ++k)
+ crc += in_buff[k] & 0xff;
+ }
+ tape_buffered_write (in_buff, out_des, size);
+ num_bytes -= size;
+ input_size -= size;
+ in_buff += size;
+ }
+}
+/* Copy a file using the input and output buffers, which may start out
+ partly full. After the copy, the files are not closed nor the last
+ block flushed to output, and the input buffer may still be partly
+ full. If `crc_i_flag' is set, add each byte to `crc'.
+ IN_DES is the file descriptor for input;
+ OUT_DES is the file descriptor for output;
+ NUM_BYTES is the number of bytes to copy. */
+
+void
+copy_files_disk_to_disk (int in_des, int out_des, off_t num_bytes,
+ char *filename)
+{
+ off_t size;
+ off_t k;
+ off_t original_num_bytes;
+ int rc;
+
+ original_num_bytes = num_bytes;
+ while (num_bytes > 0)
+ {
+ if (input_size == 0)
+ if (rc = disk_fill_input_buffer (in_des, num_bytes))
+ {
+ if (rc > 0)
+ {
+ char buf[UINTMAX_STRSIZE_BOUND];
+ error (0, 0,
+ ngettext ("File %s shrunk by %s byte, padding with zeros",
+ "File %s shrunk by %s bytes, padding with zeros",
+ num_bytes),
+ filename, STRINGIFY_BIGINT (num_bytes, buf));
+ }
+ else
+ error (0, 0, _("Read error at byte %lld in file %s, padding with zeros"),
+ original_num_bytes - num_bytes, filename);
+ write_nuls_to_file (num_bytes, out_des, disk_buffered_write);
+ break;
+ }
+ size = (input_size < num_bytes) ? input_size : num_bytes;
+ if (crc_i_flag)
+ {
+ for (k = 0; k < size; ++k)
+ crc += in_buff[k] & 0xff;
+ }
+ disk_buffered_write (in_buff, out_des, size);
+ num_bytes -= size;
+ input_size -= size;
+ in_buff += size;
+ }
+}
+
+/* Warn if file changed while it was being copied. */
+
+void
+warn_if_file_changed (char *file_name, off_t old_file_size,
+ time_t old_file_mtime)
+{
+ struct stat new_file_stat;
+ if ((*xstat) (file_name, &new_file_stat) < 0)
+ {
+ stat_error (file_name);
+ return;
+ }
+
+ /* Only check growth, shrinkage detected in copy_files_disk_to_{disk,tape}()
+ */
+ if (new_file_stat.st_size > old_file_size)
+ error (0, 0,
+ ngettext ("File %s grew, %"PRIuMAX" new byte not copied",
+ "File %s grew, %"PRIuMAX" new bytes not copied",
+ (long)(new_file_stat.st_size - old_file_size)),
+ file_name, (uintmax_t) (new_file_stat.st_size - old_file_size));
+
+ else if (new_file_stat.st_mtime != old_file_mtime)
+ error (0, 0, _("File %s was modified while being copied"), file_name);
+}
+
+/* Create all directories up to but not including the last part of NAME.
+ Do not destroy any nondirectories while creating directories. */
+
+void
+create_all_directories (char *name)
+{
+ char *dir;
+ int mode;
+#ifdef HPUX_CDF
+ int cdf;
+#endif
+
+ dir = dir_name (name);
+ mode = 0700;
+#ifdef HPUX_CDF
+ cdf = islastparentcdf (name);
+ if (cdf)
+ {
+ dir [strlen (dir) - 1] = '\0'; /* remove final + */
+ mode = 04700;
+ }
+
+#endif
+
+ if (dir == NULL)
+ error (2, 0, _("virtual memory exhausted"));
+
+ if (dir[0] != '.' || dir[1] != '\0')
+ {
+ const char *fmt;
+ if (warn_option & CPIO_WARN_INTERDIR)
+ fmt = _("Creating intermediate directory `%s'");
+ else
+ fmt = NULL;
+ make_path (dir, -1, -1, fmt);
+ }
+
+ free (dir);
+}
+
+/* Prepare to append to an archive. We have been in
+ process_copy_in, keeping track of the position where
+ the last header started in `last_header_start'. Now we
+ have the starting position of the last header (the TRAILER!!!
+ header, or blank record for tar archives) and we want to start
+ writing (appending) over the last header. The last header may
+ be in the middle of a block, so to keep the buffering in sync
+ we lseek back to the start of the block, read everything up
+ to but not including the last header, lseek back to the start
+ of the block, and then do a copy_buf_out of what we read.
+ Actually, we probably don't have to worry so much about keeping the
+ buffering perfect since you can only append to archives that
+ are disk files. */
+
+void
+prepare_append (int out_file_des)
+{
+ int start_of_header;
+ int start_of_block;
+ int useful_bytes_in_block;
+ char *tmp_buf;
+
+ start_of_header = last_header_start;
+ /* Figure out how many bytes we will rewrite, and where they start. */
+ useful_bytes_in_block = start_of_header % io_block_size;
+ start_of_block = start_of_header - useful_bytes_in_block;
+
+ if (lseek (out_file_des, start_of_block, SEEK_SET) < 0)
+ error (1, errno, _("cannot seek on output"));
+ if (useful_bytes_in_block > 0)
+ {
+ tmp_buf = (char *) xmalloc (useful_bytes_in_block);
+ read (out_file_des, tmp_buf, useful_bytes_in_block);
+ if (lseek (out_file_des, start_of_block, SEEK_SET) < 0)
+ error (1, errno, _("cannot seek on output"));
+ /* fix juo -- is this copy_tape_buf_out? or copy_disk? */
+ tape_buffered_write (tmp_buf, out_file_des, useful_bytes_in_block);
+ free (tmp_buf);
+ }
+
+ /* We are done reading the archive, so clear these since they
+ will now be used for reading in files that we are appending
+ to the archive. */
+ input_size = 0;
+ input_bytes = 0;
+ in_buff = input_buffer;
+}
+
+/* Support for remembering inodes with multiple links. Used in the
+ "copy in" and "copy pass" modes for making links instead of copying
+ the file. */
+
+struct inode_val
+{
+ ino_t inode;
+ unsigned long major_num;
+ unsigned long minor_num;
+ char *file_name;
+};
+
+/* Inode hash table. Allocated by first call to add_inode. */
+static Hash_table *hash_table = NULL;
+
+static size_t
+inode_val_hasher (const void *val, size_t n_buckets)
+{
+ const struct inode_val *ival = val;
+ return ival->inode % n_buckets;
+}
+
+static bool
+inode_val_compare (const void *val1, const void *val2)
+{
+ const struct inode_val *ival1 = val1;
+ const struct inode_val *ival2 = val2;
+ return ival1->inode == ival2->inode
+ && ival1->major_num == ival2->major_num
+ && ival1->minor_num == ival2->minor_num;
+}
+
+char *
+find_inode_file (ino_t node_num, unsigned long major_num,
+ unsigned long minor_num)
+{
+ struct inode_val sample;
+ struct inode_val *ival;
+
+ if (!hash_table)
+ return NULL;
+
+ sample.inode = node_num;
+ sample.major_num = major_num;
+ sample.minor_num = minor_num;
+ ival = hash_lookup (hash_table, &sample);
+ return ival ? ival->file_name : NULL;
+}
+
+/* Associate FILE_NAME with the inode NODE_NUM. (Insert into hash table.) */
+
+void
+add_inode (ino_t node_num, char *file_name, unsigned long major_num,
+ unsigned long minor_num)
+{
+ struct inode_val *temp;
+ struct inode_val *e;
+
+ /* Create new inode record. */
+ temp = (struct inode_val *) xmalloc (sizeof (struct inode_val));
+ temp->inode = node_num;
+ temp->major_num = major_num;
+ temp->minor_num = minor_num;
+ temp->file_name = xstrdup (file_name);
+
+ if (!((hash_table
+ || (hash_table = hash_initialize (0, 0, inode_val_hasher,
+ inode_val_compare, 0)))
+ && (e = hash_insert (hash_table, temp))))
+ xalloc_die ();
+ /* FIXME: e is not used */
+}
+
+
+/* Open FILE in the mode specified by the command line options
+ and return an open file descriptor for it,
+ or -1 if it can't be opened. */
+
+int
+open_archive (char *file)
+{
+ int fd;
+ void (*copy_in) (); /* Workaround for pcc bug. */
+
+ copy_in = process_copy_in;
+
+ if (copy_function == copy_in)
+ fd = rmtopen (file, O_RDONLY | O_BINARY, MODE_RW, rsh_command_option);
+ else
+ {
+ if (!append_flag)
+ fd = rmtopen (file, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, MODE_RW,
+ rsh_command_option);
+ else
+ fd = rmtopen (file, O_RDWR | O_BINARY, MODE_RW, rsh_command_option);
+ }
+
+ return fd;
+}
+
+/* Attempt to rewind the tape drive on file descriptor TAPE_DES
+ and take it offline. */
+
+void
+tape_offline (int tape_des)
+{
+#if defined(MTIOCTOP) && defined(MTOFFL)
+ struct mtop control;
+
+ control.mt_op = MTOFFL;
+ control.mt_count = 1;
+ rmtioctl (tape_des, MTIOCTOP, (char*) &control); /* Don't care if it fails. */
+#endif
+}
+
+/* The file on file descriptor TAPE_DES is assumed to be magnetic tape
+ (or floppy disk or other device) and the end of the medium
+ has been reached. Ask the user for to mount a new "tape" to continue
+ the processing. If the user specified the device name on the
+ command line (with the -I, -O, -F or --file options), then we can
+ automatically re-open the same device to use the next medium. If the
+ user did not specify the device name, then we have to ask them which
+ device to use. */
+
+void
+get_next_reel (int tape_des)
+{
+ static int reel_number = 1;
+ FILE *tty_in; /* File for interacting with user. */
+ FILE *tty_out; /* File for interacting with user. */
+ int old_tape_des;
+ char *next_archive_name;
+ dynamic_string new_name;
+ char *str_res;
+
+ ds_init (&new_name, 128);
+
+ /* Open files for interactive communication. */
+ tty_in = fopen (TTY_NAME, "r");
+ if (tty_in == NULL)
+ error (2, errno, TTY_NAME);
+ tty_out = fopen (TTY_NAME, "w");
+ if (tty_out == NULL)
+ error (2, errno, TTY_NAME);
+
+ old_tape_des = tape_des;
+ tape_offline (tape_des);
+ rmtclose (tape_des);
+
+ /* Give message and wait for carrage return. User should hit carrage return
+ only after loading the next tape. */
+ ++reel_number;
+ if (new_media_message)
+ fprintf (tty_out, "%s", new_media_message);
+ else if (new_media_message_with_number)
+ fprintf (tty_out, "%s%d%s", new_media_message_with_number, reel_number,
+ new_media_message_after_number);
+ else if (archive_name)
+ fprintf (tty_out, _("Found end of tape. Load next tape and press RETURN. "));
+ else
+ fprintf (tty_out, _("Found end of tape. To continue, type device/file name when ready.\n"));
+
+ fflush (tty_out);
+
+ if (archive_name)
+ {
+ int c;
+
+ do
+ c = getc (tty_in);
+ while (c != EOF && c != '\n');
+
+ tape_des = open_archive (archive_name);
+ if (tape_des == -1)
+ open_error (archive_name);
+ }
+ else
+ {
+ do
+ {
+ if (tape_des < 0)
+ {
+ fprintf (tty_out,
+ _("To continue, type device/file name when ready.\n"));
+ fflush (tty_out);
+ }
+
+ str_res = ds_fgets (tty_in, &new_name);
+ if (str_res == NULL || str_res[0] == '\0')
+ exit (1);
+ next_archive_name = str_res;
+
+ tape_des = open_archive (next_archive_name);
+ if (tape_des == -1)
+ open_error (next_archive_name);
+ }
+ while (tape_des < 0);
+ }
+
+ /* We have to make sure that `tape_des' has not changed its value even
+ though we closed it and reopened it, since there are local
+ copies of it in other routines. This works fine on Unix (even with
+ rmtread and rmtwrite) since open will always return the lowest
+ available file descriptor and we haven't closed any files (e.g.,
+ stdin, stdout or stderr) that were opened before we originally opened
+ the archive. */
+
+ if (tape_des != old_tape_des)
+ error (1, 0, _("internal error: tape descriptor changed from %d to %d"),
+ old_tape_des, tape_des);
+
+ free (new_name.ds_string);
+ fclose (tty_in);
+ fclose (tty_out);
+}
+
+/* If MESSAGE does not contain the string "%d", make `new_media_message'
+ a copy of MESSAGE. If MESSAGES does contain the string "%d", make
+ `new_media_message_with_number' a copy of MESSAGE up to, but
+ not including, the string "%d", and make `new_media_message_after_number'
+ a copy of MESSAGE after the string "%d". */
+
+void
+set_new_media_message (char *message)
+{
+ char *p;
+ int prev_was_percent;
+
+ p = message;
+ prev_was_percent = 0;
+ while (*p != '\0')
+ {
+ if (*p == 'd' && prev_was_percent)
+ break;
+ prev_was_percent = (*p == '%');
+ ++p;
+ }
+ if (*p == '\0')
+ {
+ new_media_message = xstrdup (message);
+ }
+ else
+ {
+ int length = p - message - 1;
+
+ new_media_message_with_number = xmalloc (length + 1);
+ strncpy (new_media_message_with_number, message, length);
+ new_media_message_with_number[length] = '\0';
+ length = strlen (p + 1);
+ new_media_message_after_number = xmalloc (length + 1);
+ strcpy (new_media_message_after_number, p + 1);
+ }
+}
+
+#ifdef SYMLINK_USES_UMASK
+/* Most machines always create symlinks with rwxrwxrwx protection,
+ but some (HP/UX 8.07; maybe DEC's OSF on MIPS, too?) use the
+ umask when creating symlinks, so if your umask is 022 you end
+ up with rwxr-xr-x symlinks (although HP/UX seems to completely
+ ignore the protection). There doesn't seem to be any way to
+ manipulate the modes once the symlinks are created (e.g.
+ a hypothetical "lchmod"), so to create them with the right
+ modes we have to set the umask first. */
+
+int
+umasked_symlink (char *name1, char *name2, int mode)
+{
+ int old_umask;
+ int rc;
+ mode = ~(mode & 0777) & 0777;
+ old_umask = umask (mode);
+ rc = symlink (name1, name2);
+ umask (old_umask);
+ return rc;
+}
+#endif /* SYMLINK_USES_UMASK */
+
+#ifdef HPUX_CDF
+/* When we create a cpio archive we mark CDF's by putting an extra `/'
+ after their component name so we can distinguish the CDF's when we
+ extract the archive (in case the "hidden" directory's files appear
+ in the archive before the directory itself). E.g., in the path
+ "a/b+/c", if b+ is a CDF, we will write this path as "a/b+//c" in
+ the archive so when we extract the archive we will know that b+
+ is actually a CDF, and not an ordinary directory whose name happens
+ to end in `+'. We also do the same thing internally in copypass.c. */
+
+
+/* Take an input pathname and check it for CDF's. Insert an extra
+ `/' in the pathname after each "hidden" directory. If we add
+ any `/'s, return a malloced string instead of the original input
+ string.
+ FIXME: This creates a memory leak.
+*/
+
+char *
+add_cdf_double_slashes (char *input_name)
+{
+ static char *ret_name = NULL; /* re-usuable return buffer (malloc'ed) */
+ static int ret_size = -1; /* size of return buffer. */
+ char *p;
+ char *q;
+ int n;
+ struct stat dir_stat;
+
+ /* Search for a `/' preceeded by a `+'. */
+
+ for (p = input_name; *p != '\0'; ++p)
+ {
+ if ( (*p == '+') && (*(p + 1) == '/') )
+ break;
+ }
+
+ /* If we didn't find a `/' preceeded by a `+' then there are
+ no CDF's in this pathname. Return the original pathname. */
+
+ if (*p == '\0')
+ return input_name;
+
+ /* There was a `/' preceeded by a `+' in the pathname. If it is a CDF
+ then we will need to copy the input pathname to our return
+ buffer so we can insert the extra `/'s. Since we can't tell
+ yet whether or not it is a CDF we will just always copy the
+ string to the return buffer. First we have to make sure the
+ buffer is large enough to hold the string and any number of
+ extra `/'s we might add. */
+
+ n = 2 * (strlen (input_name) + 1);
+ if (n >= ret_size)
+ {
+ if (ret_size < 0)
+ ret_name = (char *) malloc (n);
+ else
+ ret_name = (char *)realloc (ret_name, n);
+ ret_size = n;
+ }
+
+ /* Clear the `/' after this component, so we can stat the pathname
+ up to and including this component. */
+ ++p;
+ *p = '\0';
+ if ((*xstat) (input_name, &dir_stat) < 0)
+ {
+ stat_error (input_name);
+ return input_name;
+ }
+
+ /* Now put back the `/' after this component and copy the pathname up to
+ and including this component and its trailing `/' to the return
+ buffer. */
+ *p++ = '/';
+ strncpy (ret_name, input_name, p - input_name);
+ q = ret_name + (p - input_name);
+
+ /* If it was a CDF, add another `/'. */
+ if (S_ISDIR (dir_stat.st_mode) && (dir_stat.st_mode & 04000) )
+ *q++ = '/';
+
+ /* Go through the rest of the input pathname, copying it to the
+ return buffer, and adding an extra `/' after each CDF. */
+ while (*p != '\0')
+ {
+ if ( (*p == '+') && (*(p + 1) == '/') )
+ {
+ *q++ = *p++;
+
+ *p = '\0';
+ if ((*xstat) (input_name, &dir_stat) < 0)
+ {
+ stat_error (input_name);
+ return input_name;
+ }
+ *p = '/';
+
+ if (S_ISDIR (dir_stat.st_mode) && (dir_stat.st_mode & 04000) )
+ *q++ = '/';
+ }
+ *q++ = *p++;
+ }
+ *q = '\0';
+
+ return ret_name;
+}
+
+/* Is the last parent directory (e.g., c in a/b/c/d) a CDF? If the
+ directory name ends in `+' and is followed by 2 `/'s instead of 1
+ then it is. This is only the case for cpio archives, but we don't
+ have to worry about tar because tar always has the directory before
+ its files (or else we lose). */
+int
+islastparentcdf (char *path)
+{
+ char *newpath;
+ char *slash;
+ int slash_count;
+ int length; /* Length of result, not including NUL. */
+
+ slash = strrchr (path, '/');
+ if (slash == 0)
+ return 0;
+ else
+ {
+ slash_count = 0;
+ while (slash > path && *slash == '/')
+ {
+ ++slash_count;
+ --slash;
+ }
+
+
+ if ( (*slash == '+') && (slash_count >= 2) )
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+#define DISKBLOCKSIZE (512)
+
+static int
+buf_all_zeros (char *buf, int bufsize)
+{
+ int i;
+ for (i = 0; i < bufsize; ++i)
+ {
+ if (*buf++ != '\0')
+ return 0;
+ }
+ return 1;
+}
+
+int delayed_seek_count = 0;
+
+/* Write NBYTE bytes from BUF to remote tape connection FILDES.
+ Return the number of bytes written on success, -1 on error. */
+
+static int
+sparse_write (int fildes, char *buf, unsigned int nbyte)
+{
+ int complete_block_count;
+ int leftover_bytes_count;
+ int seek_count;
+ int write_count;
+ char *cur_write_start;
+ int lseek_rc;
+ int write_rc;
+ int i;
+ enum { begin, in_zeros, not_in_zeros } state;
+
+ complete_block_count = nbyte / DISKBLOCKSIZE;
+ leftover_bytes_count = nbyte % DISKBLOCKSIZE;
+
+ if (delayed_seek_count != 0)
+ state = in_zeros;
+ else
+ state = begin;
+
+ seek_count = delayed_seek_count;
+
+ for (i = 0; i < complete_block_count; ++i)
+ {
+ switch (state)
+ {
+ case begin :
+ if (buf_all_zeros (buf, DISKBLOCKSIZE))
+ {
+ seek_count = DISKBLOCKSIZE;
+ state = in_zeros;
+ }
+ else
+ {
+ cur_write_start = buf;
+ write_count = DISKBLOCKSIZE;
+ state = not_in_zeros;
+ }
+ buf += DISKBLOCKSIZE;
+ break;
+
+ case in_zeros :
+ if (buf_all_zeros (buf, DISKBLOCKSIZE))
+ {
+ seek_count += DISKBLOCKSIZE;
+ }
+ else
+ {
+ lseek (fildes, seek_count, SEEK_CUR);
+ cur_write_start = buf;
+ write_count = DISKBLOCKSIZE;
+ state = not_in_zeros;
+ }
+ buf += DISKBLOCKSIZE;
+ break;
+
+ case not_in_zeros :
+ if (buf_all_zeros (buf, DISKBLOCKSIZE))
+ {
+ write_rc = write (fildes, cur_write_start, write_count);
+ seek_count = DISKBLOCKSIZE;
+ state = in_zeros;
+ }
+ else
+ {
+ write_count += DISKBLOCKSIZE;
+ }
+ buf += DISKBLOCKSIZE;
+ break;
+ }
+ }
+
+ switch (state)
+ {
+ case begin :
+ case in_zeros :
+ delayed_seek_count = seek_count;
+ break;
+
+ case not_in_zeros :
+ write_rc = write (fildes, cur_write_start, write_count);
+ delayed_seek_count = 0;
+ break;
+ }
+
+ if (leftover_bytes_count != 0)
+ {
+ if (delayed_seek_count != 0)
+ {
+ lseek_rc = lseek (fildes, delayed_seek_count, SEEK_CUR);
+ delayed_seek_count = 0;
+ }
+ write_rc = write (fildes, buf, leftover_bytes_count);
+ }
+ return nbyte;
+}
+
+#define CPIO_UID(uid) (set_owner_flag ? set_owner : (uid))
+#define CPIO_GID(gid) (set_group_flag ? set_group : (gid))
+
+void
+stat_to_cpio (struct cpio_file_stat *hdr, struct stat *st)
+{
+ hdr->c_dev_maj = major (st->st_dev);
+ hdr->c_dev_min = minor (st->st_dev);
+ hdr->c_ino = st->st_ino;
+ /* For POSIX systems that don't define the S_IF macros,
+ we can't assume that S_ISfoo means the standard Unix
+ S_IFfoo bit(s) are set. So do it manually, with a
+ different name. Bleah. */
+ hdr->c_mode = (st->st_mode & 07777);
+ if (S_ISREG (st->st_mode))
+ hdr->c_mode |= CP_IFREG;
+ else if (S_ISDIR (st->st_mode))
+ hdr->c_mode |= CP_IFDIR;
+#ifdef S_ISBLK
+ else if (S_ISBLK (st->st_mode))
+ hdr->c_mode |= CP_IFBLK;
+#endif
+#ifdef S_ISCHR
+ else if (S_ISCHR (st->st_mode))
+ hdr->c_mode |= CP_IFCHR;
+#endif
+#ifdef S_ISFIFO
+ else if (S_ISFIFO (st->st_mode))
+ hdr->c_mode |= CP_IFIFO;
+#endif
+#ifdef S_ISLNK
+ else if (S_ISLNK (st->st_mode))
+ hdr->c_mode |= CP_IFLNK;
+#endif
+#ifdef S_ISSOCK
+ else if (S_ISSOCK (st->st_mode))
+ hdr->c_mode |= CP_IFSOCK;
+#endif
+#ifdef S_ISNWK
+ else if (S_ISNWK (st->st_mode))
+ hdr->c_mode |= CP_IFNWK;
+#endif
+ hdr->c_nlink = st->st_nlink;
+ hdr->c_uid = CPIO_UID (st->st_uid);
+ hdr->c_gid = CPIO_GID (st->st_gid);
+ hdr->c_rdev_maj = major (st->st_rdev);
+ hdr->c_rdev_min = minor (st->st_rdev);
+ hdr->c_mtime = st->st_mtime;
+ hdr->c_filesize = st->st_size;
+ hdr->c_chksum = 0;
+ hdr->c_tar_linkname = NULL;
+}
+
+void
+cpio_to_stat (struct stat *st, struct cpio_file_stat *hdr)
+{
+ memset (st, 0, sizeof (*st));
+ st->st_dev = makedev (hdr->c_dev_maj, hdr->c_dev_min);
+ st->st_ino = hdr->c_ino;
+ st->st_mode = hdr->c_mode & 0777;
+ if (hdr->c_mode & CP_IFREG)
+ st->st_mode |= S_IFREG;
+ else if (hdr->c_mode & CP_IFDIR)
+ st->st_mode |= S_IFDIR;
+#ifdef S_IFBLK
+ else if (hdr->c_mode & CP_IFBLK)
+ st->st_mode |= S_IFBLK;
+#endif
+#ifdef S_IFCHR
+ else if (hdr->c_mode & CP_IFCHR)
+ st->st_mode |= S_IFCHR;
+#endif
+#ifdef S_IFFIFO
+ else if (hdr->c_mode & CP_IFIFO)
+ st->st_mode |= S_IFIFO;
+#endif
+#ifdef S_IFLNK
+ else if (hdr->c_mode & CP_IFLNK)
+ st->st_mode |= S_IFLNK;
+#endif
+#ifdef S_IFSOCK
+ else if (hdr->c_mode & CP_IFSOCK)
+ st->st_mode |= S_IFSOCK;
+#endif
+#ifdef S_IFNWK
+ else if (hdr->c_mode & CP_IFNWK)
+ st->st_mode |= S_IFNWK;
+#endif
+ st->st_nlink = hdr->c_nlink;
+ st->st_uid = CPIO_UID (hdr->c_uid);
+ st->st_gid = CPIO_GID (hdr->c_gid);
+ st->st_rdev = makedev (hdr->c_rdev_maj, hdr->c_rdev_min);
+ st->st_mtime = hdr->c_mtime;
+ st->st_size = hdr->c_filesize;
+}
+
+#ifndef HAVE_FCHOWN
+# define HAVE_FCHOWN 0
+#endif
+#ifndef HAVE_FCHMOD
+# define HAVE_FCHMOD 0
+#endif
+
+int
+fchown_or_chown (int fd, const char *name, uid_t uid, uid_t gid)
+{
+ if (HAVE_FCHOWN && fd != -1)
+ return fchown (fd, uid, gid);
+ else
+ return chown (name, uid, gid);
+}
+
+int
+fchmod_or_chmod (int fd, const char *name, mode_t mode)
+{
+ if (HAVE_FCHMOD && fd != -1)
+ return fchmod (fd, mode);
+ else
+ return chmod (name, mode);
+}
+
+void
+set_perms (int fd, struct cpio_file_stat *header)
+{
+ if (!no_chown_flag)
+ {
+ uid_t uid = CPIO_UID (header->c_uid);
+ gid_t gid = CPIO_GID (header->c_gid);
+ if ((fchown_or_chown (fd, header->c_name, uid, gid) < 0)
+ && errno != EPERM)
+ chown_error_details (header->c_name, uid, gid);
+ }
+ /* chown may have turned off some permissions we wanted. */
+ if (fchmod_or_chmod (fd, header->c_name, header->c_mode) < 0)
+ chmod_error_details (header->c_name, header->c_mode);
+#ifdef HPUX_CDF
+ if ((header->c_mode & CP_IFMT) && cdf_flag)
+ /* Once we "hide" the directory with the chmod(),
+ we have to refer to it using name+ instead of name. */
+ file_hdr->c_name [cdf_char] = '+';
+#endif
+ if (retain_time_flag)
+ set_file_times (fd, header->c_name, header->c_mtime, header->c_mtime);
+}
+
+void
+set_file_times (int fd,
+ const char *name, unsigned long atime, unsigned long mtime)
+{
+ struct timespec ts[2];
+
+ memset (&ts, 0, sizeof ts);
+
+ ts[0].tv_sec = atime;
+ ts[1].tv_sec = mtime;
+
+ /* Silently ignore EROFS because reading the file won't have upset its
+ timestamp if it's on a read-only filesystem. */
+ if (gl_futimens (fd, name, ts) < 0 && errno != EROFS)
+ utime_error (name);
+}
+
+/* Do we have to ignore absolute paths, and if so, does the filename
+ have an absolute path? */
+void
+cpio_safer_name_suffix (char *name, bool link_target, bool absolute_names,
+ bool strip_leading_dots)
+{
+ char *p = safer_name_suffix (name, link_target, absolute_names);
+ if (strip_leading_dots && strcmp (p, "./"))
+ /* strip leading `./' from the filename. */
+ while (*p == '.' && *(p + 1) == '/')
+ {
+ ++p;
+ while (*p == '/')
+ ++p;
+ }
+ if (p != name)
+ memmove (name, p, (size_t)(strlen (p) + 1));
+}
+
+
+/* This is a simplified form of delayed set_stat used by GNU tar.
+ With the time, both forms will merge and pass to paxutils
+
+ List of directories whose statuses we need to extract after we've
+ finished extracting their subsidiary files. If you consider each
+ contiguous subsequence of elements of the form [D]?[^D]*, where [D]
+ represents an element where AFTER_LINKS is nonzero and [^D]
+ represents an element where AFTER_LINKS is zero, then the head
+ of the subsequence has the longest name, and each non-head element
+ in the prefix is an ancestor (in the directory hierarchy) of the
+ preceding element. */
+
+struct delayed_set_stat
+ {
+ struct delayed_set_stat *next;
+ struct cpio_file_stat stat;
+ mode_t invert_permissions;
+ };
+
+static struct delayed_set_stat *delayed_set_stat_head;
+
+void
+delay_cpio_set_stat (struct cpio_file_stat *file_stat,
+ mode_t invert_permissions)
+{
+ size_t file_name_len = strlen (file_stat->c_name);
+ struct delayed_set_stat *data =
+ xmalloc (sizeof (struct delayed_set_stat) + file_name_len + 1);
+ data->next = delayed_set_stat_head;
+ memcpy (&data->stat, file_stat, sizeof data->stat);
+ data->stat.c_name = (char*) (data + 1);
+ strcpy (data->stat.c_name, file_stat->c_name);
+ data->invert_permissions = invert_permissions;
+ delayed_set_stat_head = data;
+}
+
+void
+delay_set_stat (char const *file_name, struct stat *st,
+ mode_t invert_permissions)
+{
+ struct cpio_file_stat fs;
+
+ stat_to_cpio (&fs, st);
+ fs.c_name = (char*) file_name;
+ delay_cpio_set_stat (&fs, invert_permissions);
+}
+
+/* Update the delayed_set_stat info for an intermediate directory
+ created within the file name of DIR. The intermediate directory turned
+ out to be the same as this directory, e.g. due to ".." or symbolic
+ links. *DIR_STAT_INFO is the status of the directory. */
+int
+repair_inter_delayed_set_stat (struct stat *dir_stat_info)
+{
+ struct delayed_set_stat *data;
+ for (data = delayed_set_stat_head; data; data = data->next)
+ {
+ struct stat st;
+ if (stat (data->stat.c_name, &st) != 0)
+ {
+ stat_error (data->stat.c_name);
+ return -1;
+ }
+
+ if (st.st_dev == dir_stat_info->st_dev
+ && st.st_ino == dir_stat_info->st_ino)
+ {
+ stat_to_cpio (&data->stat, dir_stat_info);
+ data->invert_permissions =
+ ((dir_stat_info->st_mode ^ st.st_mode)
+ & MODE_RWX & ~ newdir_umask);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* Update the delayed_set_stat info for a directory matching
+ FILE_HDR.
+
+ Return 0 if such info was found, 1 otherwise. */
+int
+repair_delayed_set_stat (struct cpio_file_stat *file_hdr)
+{
+ struct delayed_set_stat *data;
+ for (data = delayed_set_stat_head; data; data = data->next)
+ {
+ if (strcmp (file_hdr->c_name, data->stat.c_name) == 0)
+ {
+ data->invert_permissions = 0;
+ memcpy (&data->stat, file_hdr,
+ offsetof (struct cpio_file_stat, c_name));
+ return 0;
+ }
+ }
+ return 1;
+}
+
+void
+apply_delayed_set_stat ()
+{
+ while (delayed_set_stat_head)
+ {
+ struct delayed_set_stat *data = delayed_set_stat_head;
+ if (data->invert_permissions)
+ {
+ data->stat.c_mode ^= data->invert_permissions;
+ }
+ set_perms (-1, &data->stat);
+ delayed_set_stat_head = data->next;
+ free (data);
+ }
+}
+
+
+static int
+cpio_mkdir (struct cpio_file_stat *file_hdr, int *setstat_delayed)
+{
+ int rc;
+ mode_t mode = file_hdr->c_mode;
+
+ if (!(file_hdr->c_mode & S_IWUSR))
+ {
+ rc = mkdir (file_hdr->c_name, mode | S_IWUSR);
+ if (rc == 0)
+ {
+ delay_cpio_set_stat (file_hdr, 0);
+ *setstat_delayed = 1;
+ }
+ }
+ else
+ {
+ rc = mkdir (file_hdr->c_name, mode);
+ *setstat_delayed = 0;
+ }
+ return rc;
+}
+
+int
+cpio_create_dir (struct cpio_file_stat *file_hdr, int existing_dir)
+{
+ int res; /* Result of various function calls. */
+#ifdef HPUX_CDF
+ int cdf_flag; /* True if file is a CDF. */
+ int cdf_char; /* Index of `+' char indicating a CDF. */
+#endif
+ int setstat_delayed = 0;
+
+ if (to_stdout_option)
+ return 0;
+
+ /* Strip any trailing `/'s off the filename; tar puts
+ them on. We might as well do it here in case anybody
+ else does too, since they cause strange things to happen. */
+ strip_trailing_slashes (file_hdr->c_name);
+
+ /* Ignore the current directory. It must already exist,
+ and we don't want to change its permission, ownership
+ or time. */
+ if (file_hdr->c_name[0] == '.' && file_hdr->c_name[1] == '\0')
+ {
+ return 0;
+ }
+
+#ifdef HPUX_CDF
+ cdf_flag = 0;
+#endif
+ if (!existing_dir)
+ {
+#ifdef HPUX_CDF
+ /* If the directory name ends in a + and is SUID,
+ then it is a CDF. Strip the trailing + from
+ the name before creating it. */
+ cdf_char = strlen (file_hdr->c_name) - 1;
+ if ( (cdf_char > 0) &&
+ (file_hdr->c_mode & 04000) &&
+ (file_hdr->c_name [cdf_char] == '+') )
+ {
+ file_hdr->c_name [cdf_char] = '\0';
+ cdf_flag = 1;
+ }
+#endif
+ res = cpio_mkdir (file_hdr, &setstat_delayed);
+ }
+ else
+ res = 0;
+ if (res < 0 && create_dir_flag)
+ {
+ create_all_directories (file_hdr->c_name);
+ res = cpio_mkdir (file_hdr, &setstat_delayed);
+ }
+ if (res < 0)
+ {
+ /* In some odd cases where the file_hdr->c_name includes `.',
+ the directory may have actually been created by
+ create_all_directories(), so the mkdir will fail
+ because the directory exists. If that's the case,
+ don't complain about it. */
+ struct stat file_stat;
+ if (errno != EEXIST)
+ {
+ mkdir_error (file_hdr->c_name);
+ return -1;
+ }
+ if (lstat (file_hdr->c_name, &file_stat))
+ {
+ stat_error (file_hdr->c_name);
+ return -1;
+ }
+ if (!(S_ISDIR (file_stat.st_mode)))
+ {
+ error (0, 0, _("%s is not a directory"),
+ quotearg_colon (file_hdr->c_name));
+ return -1;
+ }
+ }
+
+ if (!setstat_delayed && repair_delayed_set_stat (file_hdr))
+ set_perms (-1, file_hdr);
+ return 0;
+}
+